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