sc_fxval.cc revision 12854
1/***************************************************************************** 2 3 Licensed to Accellera Systems Initiative Inc. (Accellera) under one or 4 more contributor license agreements. See the NOTICE file distributed 5 with this work for additional information regarding copyright ownership. 6 Accellera licenses this file to you under the Apache License, Version 2.0 7 (the "License"); you may not use this file except in compliance with the 8 License. You may obtain a copy of the License at 9 10 http://www.apache.org/licenses/LICENSE-2.0 11 12 Unless required by applicable law or agreed to in writing, software 13 distributed under the License is distributed on an "AS IS" BASIS, 14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 15 implied. See the License for the specific language governing 16 permissions and limitations under the License. 17 18 *****************************************************************************/ 19 20/***************************************************************************** 21 22 sc_fxval.cpp - 23 24 Original Author: Martin Janssen, Synopsys, Inc. 25 26 *****************************************************************************/ 27 28/***************************************************************************** 29 30 MODIFICATION LOG - modifiers, enter your name, affiliation, date and 31 changes you are making here. 32 33 Name, Affiliation, Date: 34 Description of Modification: 35 36 *****************************************************************************/ 37 38 39// $Log: sc_fxval.cpp,v $ 40// Revision 1.1.1.1 2006/12/15 20:20:04 acg 41// SystemC 2.3 42// 43// Revision 1.3 2006/01/13 18:53:58 acg 44// Andy Goodrich: added $Log command so that CVS comments are reproduced in 45// the source. 46// 47 48#include <cctype> 49#include <cfloat> 50#include <cmath> 51#include <cstdlib> 52 53#include "systemc/ext/dt/fx/sc_fxval.hh" 54 55namespace sc_dt 56{ 57 58// ---------------------------------------------------------------------------- 59// CLASS : sc_fxval 60// 61// Fixed-point value type; arbitrary precision. 62// ---------------------------------------------------------------------------- 63 64// explicit conversion to character string 65 66const std::string 67sc_fxval::to_string() const 68{ 69 return std::string(m_rep->to_string(SC_DEC, -1, SC_E)); 70} 71 72const std::string 73sc_fxval::to_string(sc_numrep numrep) const 74{ 75 return std::string(m_rep->to_string(numrep, -1, SC_E)); 76} 77 78const std::string 79sc_fxval::to_string(sc_numrep numrep, bool w_prefix) const 80{ 81 return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), SC_E)); 82} 83 84const std::string 85sc_fxval::to_string(sc_fmt fmt) const 86{ 87 return std::string(m_rep->to_string(SC_DEC, -1, fmt)); 88} 89 90const std::string 91sc_fxval::to_string(sc_numrep numrep, sc_fmt fmt) const 92{ 93 return std::string(m_rep->to_string(numrep, -1, fmt)); 94} 95 96const std::string 97sc_fxval::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const 98{ 99 return std::string(m_rep->to_string(numrep, (w_prefix ? 1 : 0), fmt)); 100} 101 102 103const std::string 104sc_fxval::to_dec() const 105{ 106 return std::string(m_rep->to_string(SC_DEC, -1, SC_E)); 107} 108 109const std::string 110sc_fxval::to_bin() const 111{ 112 return std::string(m_rep->to_string(SC_BIN, -1, SC_E)); 113} 114 115const std::string 116sc_fxval::to_oct() const 117{ 118 return std::string(m_rep->to_string(SC_OCT, -1, SC_E)); 119} 120 121const std::string 122sc_fxval::to_hex() const 123{ 124 return std::string(m_rep->to_string(SC_HEX, -1, SC_E)); 125} 126 127 128// print or dump content 129 130void sc_fxval::print(::std::ostream &os) const { m_rep->print(os); } 131 132void 133sc_fxval::scan(::std::istream &is) 134{ 135 std::string s; 136 is >> s; 137 *this = s.c_str(); 138} 139 140void 141sc_fxval::dump(::std::ostream &os) const 142{ 143 os << "sc_fxval" << ::std::endl; 144 os << "(" << ::std::endl; 145 os << "rep = "; 146 m_rep->dump(os); 147 // TO BE COMPLETED 148 // os << "r_flag = " << m_r_flag << ::std::endl; 149 // os << "observer = "; 150 // if (m_observer != 0) 151 // m_observer->dump(os); 152 // else 153 // os << "0" << ::std::endl; 154 os << ")" << ::std::endl; 155} 156 157// protected methods and friend functions 158sc_fxval_observer * 159sc_fxval::lock_observer() const 160{ 161 SC_ASSERT_(m_observer != 0, "lock observer failed"); 162 sc_fxval_observer *tmp = m_observer; 163 m_observer = 0; 164 return tmp; 165} 166 167void 168sc_fxval::unlock_observer(sc_fxval_observer *observer_) const 169{ 170 SC_ASSERT_(observer_ != 0, "unlock observer failed"); 171 m_observer = observer_; 172} 173 174 175// ---------------------------------------------------------------------------- 176// CLASS : sc_fxval_fast 177// 178// Fixed-point value types; limited precision. 179// ---------------------------------------------------------------------------- 180 181static void 182print_dec(scfx_string &s, scfx_ieee_double id, int w_prefix, sc_fmt fmt) 183{ 184 if (id.negative() != 0) { 185 id.negative(0); 186 s += '-'; 187 } 188 189 if (w_prefix == 1) { 190 scfx_print_prefix(s, SC_DEC); 191 } 192 193 if (id.is_zero()) { 194 s += '0'; 195 return; 196 } 197 198 // split 'id' into its integer and fractional part 199 double int_part; 200 double frac_part = std::modf(static_cast<double>(id), &int_part); 201 202 int i; 203 204 // print integer part 205 int int_digits = 0; 206 int int_zeros = 0; 207 208 if (int_part != 0.0) { 209 int_digits = (int)std::ceil(std::log10(int_part + 1.0)); 210 211 int len = s.length(); 212 s.append(int_digits); 213 214 bool zero_digits = (frac_part == 0.0 && fmt != SC_F); 215 216 for (i = int_digits + len - 1; i >= len; i--) { 217 unsigned int remainder = (unsigned int)std::fmod(int_part, 10.0); 218 s[i] = static_cast<char>('0' + remainder); 219 220 if (zero_digits) { 221 if (remainder == 0) 222 int_zeros++; 223 else 224 zero_digits = false; 225 } 226 227 int_part /= 10.0; 228 } 229 230 // discard trailing zeros from int_part 231 s.discard(int_zeros); 232 233 if (s[len] == '0') { 234 // int_digits was overestimated by one 235 s.remove(len); 236 --int_digits; 237 } 238 } 239 240 // print fractional part 241 int frac_digits = 0; 242 int frac_zeros = 0; 243 244 if (frac_part != 0.0) { 245 s += '.'; 246 247 bool zero_digits = (int_digits == 0 && fmt != SC_F); 248 249 frac_zeros = (int)std::floor(-std::log10(frac_part + DBL_EPSILON)); 250 251 frac_part *= std::pow(10.0, frac_zeros); 252 253 frac_digits = frac_zeros; 254 if (!zero_digits) { 255 for (i = 0; i < frac_zeros; i++) 256 s += '0'; 257 frac_zeros = 0; 258 } 259 260 while (frac_part != 0.0) { 261 frac_part *= 10.0; 262 int n = static_cast<int>(frac_part); 263 264 if (zero_digits) { 265 if (n == 0) 266 frac_zeros++; 267 else 268 zero_digits = false; 269 } 270 271 if (!zero_digits) 272 s += static_cast<char>('0' + n); 273 274 frac_part -= n; 275 frac_digits++; 276 } 277 } 278 279 // print exponent 280 if (fmt != SC_F) { 281 if (frac_digits == 0) 282 scfx_print_exp(s, int_zeros); 283 else if (int_digits == 0) 284 scfx_print_exp(s, -frac_zeros); 285 } 286} 287 288static void 289print_other(scfx_string &s, const scfx_ieee_double &id, sc_numrep numrep, 290 int w_prefix, sc_fmt fmt, const scfx_params *params) 291{ 292 scfx_ieee_double id2 = id; 293 294 sc_numrep numrep2 = numrep; 295 296 bool numrep_is_sm = (numrep == SC_BIN_SM || 297 numrep == SC_OCT_SM || 298 numrep == SC_HEX_SM); 299 300 if (numrep_is_sm) { 301 if (id2.negative() != 0) { 302 s += '-'; 303 id2.negative(0); 304 } 305 switch (numrep) { 306 case SC_BIN_SM: 307 numrep2 = SC_BIN_US; 308 break; 309 case SC_OCT_SM: 310 numrep2 = SC_OCT_US; 311 break; 312 case SC_HEX_SM: 313 numrep2 = SC_HEX_US; 314 break; 315 default: 316 ; 317 } 318 } 319 320 if (w_prefix != 0) { 321 scfx_print_prefix(s, numrep); 322 } 323 324 numrep = numrep2; 325 326 sc_fxval_fast a(id2); 327 328 int msb, lsb; 329 330 if (params != 0) { 331 msb = params->iwl() - 1; 332 lsb = params->iwl() - params->wl(); 333 334 if (params->enc() == SC_TC_ && 335 (numrep == SC_BIN_US || 336 numrep == SC_OCT_US || 337 numrep == SC_HEX_US) && 338 !numrep_is_sm && 339 params->wl() > 1) { 340 --msb; 341 } else if (params->enc() == SC_US_ && 342 (numrep == SC_BIN || 343 numrep == SC_OCT || 344 numrep == SC_HEX || 345 numrep == SC_CSD)) { 346 ++msb; 347 } 348 } else { 349 if (a.is_zero()) { 350 msb = 0; 351 lsb = 0; 352 } else { 353 msb = id2.exponent() + 1; 354 while (a.get_bit(msb) == a.get_bit(msb - 1)) 355 --msb; 356 357 if (numrep == SC_BIN_US || 358 numrep == SC_OCT_US || 359 numrep == SC_HEX_US) { 360 --msb; 361 } 362 363 lsb = id2.exponent() - 52; 364 while (!a.get_bit(lsb)) 365 ++lsb; 366 } 367 } 368 369 int step; 370 371 switch (numrep) { 372 case SC_BIN: 373 case SC_BIN_US: 374 case SC_CSD: 375 step = 1; 376 break; 377 case SC_OCT: 378 case SC_OCT_US: 379 step = 3; 380 break; 381 case SC_HEX: 382 case SC_HEX_US: 383 step = 4; 384 break; 385 default: 386 SC_REPORT_FATAL("assertion failed", "unexpected sc_numrep"); 387 sc_core::sc_abort(); 388 } 389 390 msb = (int)std::ceil(double(msb + 1) / step) * step - 1; 391 392 lsb = (int)std::floor(double(lsb) / step) * step; 393 394 if (msb < 0) { 395 s += '.'; 396 if (fmt == SC_F) { 397 int sign = (id2.negative() != 0) ? (1 << step) - 1 : 0; 398 for (int i = (msb + 1) / step; i < 0; i++) { 399 if (sign < 10) 400 s += static_cast<char>(sign + '0'); 401 else 402 s += static_cast<char>(sign + 'a' - 10); 403 } 404 } 405 } 406 407 int i = msb; 408 while (i >= lsb) { 409 int value = 0; 410 for (int j = step - 1; j >= 0; --j) { 411 value += static_cast<int>(a.get_bit(i)) << j; 412 --i; 413 } 414 if (value < 10) 415 s += static_cast<char>(value + '0'); 416 else 417 s += static_cast<char>(value + 'a' - 10); 418 if (i == -1) 419 s += '.'; 420 } 421 422 if (lsb > 0 && fmt == SC_F) { 423 for (int i = lsb / step; i > 0; i--) 424 s += '0'; 425 } 426 427 if (s[s.length() - 1] == '.') 428 s.discard(1); 429 430 if (fmt != SC_F) { 431 if (msb < 0) 432 scfx_print_exp(s, (msb + 1) / step); 433 else if (lsb > 0) 434 scfx_print_exp(s, lsb / step); 435 } 436 437 if (numrep == SC_CSD) 438 scfx_tc2csd(s, w_prefix); 439} 440 441const char * 442to_string(const scfx_ieee_double &id, sc_numrep numrep, int w_prefix, 443 sc_fmt fmt, const scfx_params *params=0) 444{ 445 static scfx_string s; 446 447 s.clear(); 448 449 if (id.is_nan()) { 450 scfx_print_nan(s); 451 } else if (id.is_inf()) { 452 scfx_print_inf(s, static_cast<bool>(id.negative())); 453 } else if (id.negative() && !id.is_zero() && 454 (numrep == SC_BIN_US || 455 numrep == SC_OCT_US || 456 numrep == SC_HEX_US)) { 457 s += "negative"; 458 } else if (numrep == SC_DEC) { 459 sc_dt::print_dec(s, id, w_prefix, fmt); 460 } else { 461 sc_dt::print_other(s, id, numrep, w_prefix, fmt, params); 462 } 463 464 return s; 465} 466 467 468// explicit conversion to character string 469const std::string 470sc_fxval_fast::to_string() const 471{ 472 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E)); 473} 474 475const std::string 476sc_fxval_fast::to_string(sc_numrep numrep) const 477{ 478 return std::string(sc_dt::to_string(m_val, numrep, -1, SC_E)); 479} 480 481const std::string 482sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix) const 483{ 484 return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), 485 SC_E)); 486} 487 488const std::string 489sc_fxval_fast::to_string(sc_fmt fmt) const 490{ 491 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, fmt)); 492} 493 494const std::string 495sc_fxval_fast::to_string(sc_numrep numrep, sc_fmt fmt) const 496{ 497 return std::string(sc_dt::to_string(m_val, numrep, -1, fmt)); 498} 499 500const std::string 501sc_fxval_fast::to_string(sc_numrep numrep, bool w_prefix, sc_fmt fmt) const 502{ 503 return std::string(sc_dt::to_string(m_val, numrep, (w_prefix ? 1 : 0), 504 fmt)); 505} 506 507const std::string 508sc_fxval_fast::to_dec() const 509{ 510 return std::string(sc_dt::to_string(m_val, SC_DEC, -1, SC_E)); 511} 512 513const std::string 514sc_fxval_fast::to_bin() const 515{ 516 return std::string(sc_dt::to_string(m_val, SC_BIN, -1, SC_E)); 517} 518 519const std::string 520sc_fxval_fast::to_oct() const 521{ 522 return std::string(sc_dt::to_string(m_val, SC_OCT, -1, SC_E)); 523} 524 525const std::string 526sc_fxval_fast::to_hex() const 527{ 528 return std::string(sc_dt::to_string(m_val, SC_HEX, -1, SC_E)); 529} 530 531 532// print or dump content 533 534void 535sc_fxval_fast::print(::std::ostream &os) const 536{ 537 os << sc_dt::to_string(m_val, SC_DEC, -1, SC_E); 538} 539 540void 541sc_fxval_fast::scan(::std::istream &is) 542{ 543 std::string s; 544 is >> s; 545 *this = s.c_str(); 546} 547 548void 549sc_fxval_fast::dump(::std::ostream &os) const 550{ 551 os << "sc_fxval_fast" << ::std::endl; 552 os << "(" << ::std::endl; 553 os << "val = " << m_val << ::std::endl; 554 // TO BE COMPLETED 555 // os << "r_flag = " << m_r_flag << ::std::endl; 556 // os << "observer = "; 557 // if (m_observer != 0) 558 // m_observer->dump(os); 559 // else 560 // os << "0" << ::std::endl; 561 os << ")" << ::std::endl; 562} 563 564 565// internal use only; 566bool 567sc_fxval_fast::get_bit(int i) const 568{ 569 scfx_ieee_double id(m_val); 570 if (id.is_zero() || id.is_nan() || id.is_inf()) 571 return false; 572 573 // convert to two's complement 574 unsigned int m0 = id.mantissa0(); 575 unsigned int m1 = id.mantissa1(); 576 577 if (id.is_normal()) 578 m0 += 1U << 20; 579 580 if (id.negative() != 0) { 581 m0 = ~ m0; 582 m1 = ~ m1; 583 unsigned int tmp = m1; 584 m1 += 1U; 585 if (m1 <= tmp) 586 m0 += 1U; 587 } 588 589 // get the right bit 590 int j = i - id.exponent(); 591 if ((j += 20) >= 32) 592 return ((m0 & 1U << 31) != 0); 593 else if (j >= 0) 594 return ((m0 & 1U << j) != 0); 595 else if ((j += 32) >= 0) 596 return ((m1 & 1U << j) != 0); 597 else 598 return false; 599} 600 601 602// protected methods and friend functions 603sc_fxval_fast_observer * 604sc_fxval_fast::lock_observer() const 605{ 606 SC_ASSERT_(m_observer != 0, "lock observer failed"); 607 sc_fxval_fast_observer *tmp = m_observer; 608 m_observer = 0; 609 return tmp; 610} 611 612void 613sc_fxval_fast::unlock_observer(sc_fxval_fast_observer *observer_) const 614{ 615 SC_ASSERT_(observer_ != 0, "unlock observer failed"); 616 m_observer = observer_; 617} 618 619#define SCFX_FAIL_IF_(cnd) \ 620{ \ 621 if ((cnd)) \ 622 return static_cast<double>(scfx_ieee_double::nan()); \ 623} 624 625double 626sc_fxval_fast::from_string(const char *s) 627{ 628 SCFX_FAIL_IF_(s == 0 || *s == 0); 629 630 scfx_string s2; 631 s2 += s; 632 s2 += '\0'; 633 634 bool sign_char; 635 int sign = scfx_parse_sign(s, sign_char); 636 637 sc_numrep numrep = scfx_parse_prefix(s); 638 639 int base = 0; 640 641 switch (numrep) { 642 case SC_DEC: 643 { 644 base = 10; 645 if (scfx_is_nan(s)) // special case: NaN 646 return static_cast<double>(scfx_ieee_double::nan()); 647 if (scfx_is_inf(s)) // special case: Infinity 648 return static_cast<double>(scfx_ieee_double::inf(sign)); 649 break; 650 } 651 case SC_BIN: 652 case SC_BIN_US: 653 { 654 SCFX_FAIL_IF_(sign_char); 655 base = 2; 656 break; 657 } 658 659 case SC_BIN_SM: 660 { 661 base = 2; 662 break; 663 } 664 case SC_OCT: 665 case SC_OCT_US: 666 { 667 SCFX_FAIL_IF_(sign_char); 668 base = 8; 669 break; 670 } 671 case SC_OCT_SM: 672 { 673 base = 8; 674 break; 675 } 676 case SC_HEX: 677 case SC_HEX_US: 678 { 679 SCFX_FAIL_IF_(sign_char); 680 base = 16; 681 break; 682 } 683 case SC_HEX_SM: 684 { 685 base = 16; 686 break; 687 } 688 case SC_CSD: 689 { 690 SCFX_FAIL_IF_(sign_char); 691 base = 2; 692 scfx_csd2tc(s2); 693 s = (const char*) s2 + 4; 694 numrep = SC_BIN; 695 break; 696 } 697 default:;// Martin, what is default??? 698 } 699 700 // 701 // find end of mantissa and count the digits and points 702 // 703 704 const char *end = s; 705 bool based_point = false; 706 int int_digits = 0; 707 int frac_digits = 0; 708 709 while (*end) { 710 if (scfx_exp_start(end)) 711 break; 712 713 if (*end == '.') { 714 SCFX_FAIL_IF_(based_point); 715 based_point = true; 716 } else { 717 SCFX_FAIL_IF_(!scfx_is_digit(*end, numrep)); 718 if (based_point) 719 frac_digits++; 720 else 721 int_digits++; 722 } 723 724 end++; 725 } 726 727 SCFX_FAIL_IF_(int_digits == 0 && frac_digits == 0); 728 729 // [ exponent ] 730 int exponent = 0; 731 if (*end) { 732 for (const char *e = end + 2; *e; e++) 733 SCFX_FAIL_IF_(!scfx_is_digit(*e, SC_DEC)); 734 exponent = std::atoi(end + 1); 735 } 736 737 // 738 // convert the mantissa 739 // 740 double integer = 0.0; 741 if (int_digits != 0) { 742 bool first_digit = true; 743 744 for (; s < end; s++) { 745 if (*s == '.') 746 break; 747 748 if (first_digit) { 749 integer = scfx_to_digit(*s, numrep); 750 switch (numrep) { 751 case SC_BIN: 752 case SC_OCT: 753 case SC_HEX: 754 { 755 if (integer >= (base >> 1)) 756 integer -= base; // two's complement 757 break; 758 } 759 default: 760 ; 761 } 762 first_digit = false; 763 } else { 764 integer *= base; 765 integer += scfx_to_digit(*s, numrep); 766 } 767 } 768 } 769 770 // [ . fraction ] 771 double fraction = 0.0; 772 if (frac_digits != 0) { 773 s++; // skip '.' 774 775 bool first_digit = (int_digits == 0); 776 double scale = 1.0; 777 for (; s < end; s++) { 778 scale /= base; 779 780 if (first_digit) { 781 fraction = scfx_to_digit(*s, numrep); 782 switch (numrep) { 783 case SC_BIN: 784 case SC_OCT: 785 case SC_HEX: 786 { 787 if (fraction >= (base >> 1)) 788 fraction -= base; // two's complement 789 break; 790 } 791 default: 792 ; 793 } 794 fraction *= scale; 795 first_digit = false; 796 } else { 797 fraction += scfx_to_digit(*s, numrep) * scale; 798 } 799 } 800 } 801 802 double exp = 803 (exponent != 0) ? std::pow((double) base, (double) exponent) : 1; 804 805 return (sign * (integer + fraction) * exp); 806} 807 808#undef SCFX_FAIL_IF_ 809 810} // namespace sc_dt 811