summaryrefslogtreecommitdiff
path: root/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp')
-rw-r--r--ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp2926
1 files changed, 2926 insertions, 0 deletions
diff --git a/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp b/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp
new file mode 100644
index 000000000..772835e6d
--- /dev/null
+++ b/ext/systemc/src/sysc/datatypes/fx/scfx_rep.cpp
@@ -0,0 +1,2926 @@
+/*****************************************************************************
+
+ Licensed to Accellera Systems Initiative Inc. (Accellera) under one or
+ more contributor license agreements. See the NOTICE file distributed
+ with this work for additional information regarding copyright ownership.
+ Accellera licenses this file to you under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with the
+ License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied. See the License for the specific language governing
+ permissions and limitations under the License.
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ scfx_rep.cpp -
+
+ Original Author: Robert Graulich, Synopsys, Inc.
+ Martin Janssen, Synopsys, Inc.
+
+ *****************************************************************************/
+
+/*****************************************************************************
+
+ MODIFICATION LOG - modifiers, enter your name, affiliation, date and
+ changes you are making here.
+
+ Name, Affiliation, Date:
+ Description of Modification:
+
+ *****************************************************************************/
+
+
+// $Log: scfx_rep.cpp,v $
+// Revision 1.4 2011/08/24 22:05:43 acg
+// Torsten Maehne: initialization changes to remove warnings.
+//
+// Revision 1.3 2011/08/15 16:43:24 acg
+// Torsten Maehne: changes to remove unused argument warnings.
+//
+// Revision 1.2 2009/02/28 00:26:20 acg
+// Andy Goodrich: bug fixes.
+//
+// Revision 1.2 2008/11/06 17:22:47 acg
+// Andy Goodrich: bug fixes for 2.2.1.
+//
+// Revision 1.1.1.1 2006/12/15 20:31:36 acg
+// SystemC 2.2
+//
+// Revision 1.3 2006/01/13 18:53:58 acg
+// Andy Goodrich: added $Log command so that CVS comments are reproduced in
+// the source.
+//
+
+#include "sysc/utils/sc_machine.h"
+#include "sysc/datatypes/fx/scfx_rep.h"
+
+#include "sysc/datatypes/fx/scfx_ieee.h"
+#include "sysc/datatypes/fx/scfx_pow10.h"
+#include "sysc/datatypes/fx/scfx_utils.h"
+
+#include "sysc/datatypes/bit/sc_bv_base.h"
+
+#include <ctype.h>
+#include <cstdio>
+#include <stdlib.h>
+#include <math.h>
+
+
+namespace sc_dt
+{
+
+// ----------------------------------------------------------------------------
+// some utilities
+// ----------------------------------------------------------------------------
+
+static scfx_pow10 pow10_fx;
+
+static const int mantissa0_size = SCFX_IEEE_DOUBLE_M_SIZE - bits_in_int;
+
+static inline
+int
+n_word( int x )
+{
+ return ( x + bits_in_word - 1 ) / bits_in_word;
+}
+
+
+// ----------------------------------------------------------------------------
+// CONSTRUCTORS
+// ----------------------------------------------------------------------------
+
+scfx_rep::scfx_rep()
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ set_zero();
+}
+
+scfx_rep::scfx_rep( int a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a != 0 )
+ {
+ m_mant.clear();
+ m_wp = m_msw = m_lsw = 2;
+ m_state = normal;
+ if( a > 0 )
+ {
+ m_mant[2] = a;
+ m_sign = 1;
+ }
+ else
+ {
+ m_mant[2] = -a;
+ m_sign = -1;
+ }
+ }
+ else
+ set_zero();
+}
+
+scfx_rep::scfx_rep( unsigned int a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a != 0 )
+ {
+ m_mant.clear();
+ m_wp = m_msw = m_lsw = 2;
+ m_state = normal;
+ m_mant[2] = a;
+ m_sign = 1;
+ }
+ else
+ set_zero();
+}
+
+scfx_rep::scfx_rep( long a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a != 0 )
+ {
+ m_mant.clear();
+ m_state = normal;
+ if ( a > 0 )
+ {
+ m_sign = 1;
+ }
+ else
+ {
+ a = -a;
+ m_sign = -1;
+ }
+# if defined(SC_LONG_64)
+ m_wp = 1;
+ m_mant[1] = static_cast<word>( a );
+ m_mant[2] = static_cast<word>( a >> bits_in_word );
+ find_sw();
+# else
+ m_wp = 2;
+ m_msw = 2;
+ m_lsw = 2;
+ m_mant[2] = a;
+# endif
+
+ }
+ else
+ set_zero();
+}
+
+scfx_rep::scfx_rep( unsigned long a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a != 0 )
+ {
+ m_mant.clear();
+ m_wp = m_msw = m_lsw = 2;
+ m_state = normal;
+# if defined(SC_LONG_64)
+ m_wp = 1;
+ m_mant[1] = static_cast<word>( a );
+ m_mant[2] = static_cast<word>( a >> bits_in_word );
+ find_sw();
+# else
+ m_wp = 2;
+ m_msw = 2;
+ m_lsw = 2;
+ m_mant[2] = a;
+# endif
+ m_sign = 1;
+ }
+ else
+ set_zero();
+}
+
+scfx_rep::scfx_rep( double a )
+: m_mant( min_mant ), m_wp( 0 ), m_sign(), m_state( normal ), m_msw( 0 ),
+ m_lsw( 0 ), m_r_flag( false )
+{
+ m_mant.clear();
+
+ scfx_ieee_double id( a );
+
+ m_sign = id.negative() ? -1 : 1;
+
+ if( id.is_nan() )
+ m_state = not_a_number;
+ else if( id.is_inf() )
+ m_state = infinity;
+ else if( id.is_subnormal() )
+ {
+ m_mant[0] = id.mantissa1();
+ m_mant[1] = id.mantissa0();
+ normalize( id.exponent() + 1 - SCFX_IEEE_DOUBLE_M_SIZE );
+ }
+ else if( id.is_normal() )
+ {
+ m_mant[0] = id.mantissa1();
+ m_mant[1] = id.mantissa0() | ( 1 << mantissa0_size );
+ normalize( id.exponent() - SCFX_IEEE_DOUBLE_M_SIZE );
+ }
+}
+
+scfx_rep::scfx_rep( int64 a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a != 0 )
+ {
+ m_mant.clear();
+ m_wp = 1;
+ m_state = normal;
+ if( a > 0 )
+ {
+ m_mant[1] = static_cast<word>( a );
+ m_mant[2] = static_cast<word>( a >> bits_in_word );
+ m_sign = 1;
+ }
+ else
+ {
+ m_mant[1] = static_cast<word>( -a );
+ m_mant[2] = static_cast<word>( (-a) >> bits_in_word );
+ m_sign = -1;
+ }
+ find_sw();
+ }
+ else
+ set_zero();
+}
+
+scfx_rep::scfx_rep( uint64 a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a != 0 )
+ {
+ m_mant.clear();
+ m_wp = 1;
+ m_state = normal;
+ m_mant[1] = static_cast<word>( a );
+ m_mant[2] = static_cast<word>( a >> bits_in_word );
+ m_sign = 1;
+ find_sw();
+ }
+ else
+ set_zero();
+}
+
+scfx_rep::scfx_rep( const sc_signed& a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a.iszero() )
+ set_zero();
+ else
+ {
+ int words = n_word( a.length() );
+ if( words > size() )
+ resize_to( words );
+ m_mant.clear();
+ m_wp = 0;
+ m_state = normal;
+ if( a.sign() )
+ {
+ sc_signed a2 = -a;
+ for( int i = 0; i < a2.length(); ++ i )
+ {
+ if( a2[i] )
+ {
+ scfx_index x = calc_indices( i );
+ m_mant[x.wi()] |= 1 << x.bi();
+ }
+ }
+ m_sign = -1;
+ }
+ else
+ {
+ for( int i = 0; i < a.length(); ++ i )
+ {
+ if( a[i] )
+ {
+ scfx_index x = calc_indices( i );
+ m_mant[x.wi()] |= 1 << x.bi();
+ }
+ }
+ m_sign = 1;
+ }
+ find_sw();
+ }
+}
+
+scfx_rep::scfx_rep( const sc_unsigned& a )
+: m_mant( min_mant ), m_wp(), m_sign(), m_state(), m_msw(), m_lsw(),
+ m_r_flag( false )
+{
+ if( a.iszero() )
+ set_zero();
+ else
+ {
+ int words = n_word( a.length() );
+ if( words > size() )
+ resize_to( words );
+ m_mant.clear();
+ m_wp = 0;
+ m_state = normal;
+ for( int i = 0; i < a.length(); ++ i )
+ {
+ if( a[i] )
+ {
+ scfx_index x = calc_indices( i );
+ m_mant[x.wi()] |= 1 << x.bi();
+ }
+ }
+ m_sign = 1;
+ find_sw();
+ }
+}
+
+
+// copy constructor
+
+scfx_rep::scfx_rep( const scfx_rep& a )
+: m_mant( a.m_mant ), m_wp( a.m_wp ), m_sign( a.m_sign ), m_state( a.m_state ),
+ m_msw( a.m_msw ), m_lsw( a.m_lsw ), m_r_flag( false )
+{}
+
+
+// ----------------------------------------------------------------------------
+// OPERATORS : new, delete
+//
+// Memory management for class scfx_rep.
+// ----------------------------------------------------------------------------
+
+union scfx_rep_node
+{
+ char data[sizeof( scfx_rep )];
+ scfx_rep_node* next;
+};
+
+
+static scfx_rep_node* list = 0;
+
+
+void*
+scfx_rep::operator new( std::size_t size )
+{
+ const int ALLOC_SIZE = 1024;
+
+ if( size != sizeof( scfx_rep ) )
+ return ::operator new( size );
+
+ if( ! list )
+ {
+ list = new scfx_rep_node[ALLOC_SIZE];
+ for( int i = 0; i < ALLOC_SIZE - 1; i ++ )
+ list[i].next = list + i + 1;
+ list[ALLOC_SIZE - 1].next = 0;
+ }
+
+ scfx_rep* ptr = reinterpret_cast<scfx_rep*>( list->data );
+ list = list->next;
+
+ return ptr;
+}
+
+
+void scfx_rep::operator delete( void* ptr, std::size_t size )
+{
+ if( size != sizeof( scfx_rep ) )
+ {
+ ::operator delete( ptr );
+ return;
+ }
+
+ scfx_rep_node* node = static_cast<scfx_rep_node*>( ptr );
+ node->next = list;
+ list = node;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : from_string
+//
+// Convert from character string to sc_fxrep.
+// ----------------------------------------------------------------------------
+
+#define SCFX_FAIL_IF_(cnd) \
+{ \
+ if( ( cnd ) ) \
+ { \
+ m_state = not_a_number; \
+ m_mant.clear(); /* to avoid Purify UMRs during assignment */ \
+ return; \
+ } \
+}
+
+
+void
+scfx_rep::from_string( const char* s, int cte_wl )
+{
+ SCFX_FAIL_IF_( s == 0 || *s == 0 );
+
+ scfx_string s2;
+ s2 += s;
+ s2 += '\0';
+
+ bool sign_char;
+ m_sign = scfx_parse_sign( s, sign_char );
+
+ sc_numrep numrep = scfx_parse_prefix( s );
+
+ int base = 0;
+
+ switch( numrep )
+ {
+ case SC_DEC:
+ {
+ base = 10;
+ if( scfx_is_nan( s ) )
+ { // special case: NaN
+ m_state = not_a_number;
+ m_mant.clear(); /* to avoid Purify UMRs during assignment */
+ return;
+ }
+ if( scfx_is_inf( s ) )
+ { // special case: Infinity
+ m_state = infinity;
+ m_mant.clear(); /* to avoid Purify UMRs during assignment */
+ return;
+ }
+ break;
+ }
+ case SC_BIN:
+ case SC_BIN_US:
+ {
+ SCFX_FAIL_IF_( sign_char );
+ base = 2;
+ break;
+ }
+
+ case SC_BIN_SM:
+ {
+ base = 2;
+ break;
+ }
+ case SC_OCT:
+ case SC_OCT_US:
+ {
+ SCFX_FAIL_IF_( sign_char );
+ base = 8;
+ break;
+ }
+ case SC_OCT_SM:
+ {
+ base = 8;
+ break;
+ }
+ case SC_HEX:
+ case SC_HEX_US:
+ {
+ SCFX_FAIL_IF_( sign_char );
+ base = 16;
+ break;
+ }
+ case SC_HEX_SM:
+ {
+ base = 16;
+ break;
+ }
+ case SC_CSD:
+ {
+ SCFX_FAIL_IF_( sign_char );
+ base = 2;
+ scfx_csd2tc( s2 );
+ s = (const char*) s2 + 4;
+ numrep = SC_BIN;
+ break;
+ }
+ default:;
+ }
+
+ //
+ // find end of mantissa and count the digits and points
+ //
+
+ const char *end = s;
+ bool based_point = false;
+ int int_digits = 0;
+ int frac_digits = 0;
+
+ while( *end )
+ {
+ if( scfx_exp_start( end ) )
+ break;
+
+ if( *end == '.' )
+ {
+ SCFX_FAIL_IF_( based_point );
+ based_point = true;
+ }
+ else
+ {
+ SCFX_FAIL_IF_( ! scfx_is_digit( *end, numrep ) );
+ if( based_point )
+ frac_digits ++;
+ else
+ int_digits ++;
+ }
+
+ ++ end;
+ }
+
+ SCFX_FAIL_IF_( int_digits == 0 && frac_digits == 0 );
+
+ // [ exponent ]
+
+ int exponent = 0;
+
+ if( *end )
+ {
+ for( const char *e = end + 2; *e; ++ e )
+ SCFX_FAIL_IF_( ! scfx_is_digit( *e, SC_DEC ) );
+ exponent = atoi( end + 1 );
+ }
+
+ //
+ // check if the mantissa is negative
+ //
+
+ bool mant_is_neg = false;
+
+ switch( numrep )
+ {
+ case SC_BIN:
+ case SC_OCT:
+ case SC_HEX:
+ {
+ const char* p = s;
+ if( *p == '.' )
+ ++ p;
+
+ mant_is_neg = ( scfx_to_digit( *p, numrep ) >= ( base >> 1 ) );
+
+ break;
+ }
+ default:
+ ;
+ }
+
+ //
+ // convert the mantissa
+ //
+
+ switch( base )
+ {
+ case 2:
+ {
+ int bit_offset = exponent % bits_in_word;
+ int word_offset = exponent / bits_in_word;
+
+ int_digits += bit_offset;
+ frac_digits -= bit_offset;
+
+ int words = n_word( int_digits ) + n_word( frac_digits );
+ if( words > size() )
+ resize_to( words );
+ m_mant.clear();
+
+ int j = n_word( frac_digits ) * bits_in_word + int_digits - 1;
+
+ for( ; s < end; s ++ )
+ {
+ switch( *s )
+ {
+ case '1':
+ set_bin( j );
+ case '0':
+ j --;
+ case '.':
+ break;
+ default:
+ SCFX_FAIL_IF_( true ); // should not happen
+ }
+ }
+
+ m_wp = n_word( frac_digits ) - word_offset;
+ break;
+ }
+ case 8:
+ {
+ exponent *= 3;
+ int_digits *= 3;
+ frac_digits *= 3;
+
+ int bit_offset = exponent % bits_in_word;
+ int word_offset = exponent / bits_in_word;
+
+ int_digits += bit_offset;
+ frac_digits -= bit_offset;
+
+ int words = n_word( int_digits ) + n_word( frac_digits );
+ if( words > size() )
+ resize_to( words );
+ m_mant.clear();
+
+ int j = n_word( frac_digits ) * bits_in_word + int_digits - 3;
+
+ for( ; s < end; s ++ )
+ {
+ switch( *s )
+ {
+ case '7': case '6': case '5': case '4':
+ case '3': case '2': case '1':
+ set_oct( j, *s - '0' );
+ case '0':
+ j -= 3;
+ case '.':
+ break;
+ default:
+ SCFX_FAIL_IF_( true ); // should not happen
+ }
+ }
+
+ m_wp = n_word( frac_digits ) - word_offset;
+ break;
+ }
+ case 10:
+ {
+ word carry, temp;
+ int length = int_digits + frac_digits;
+ resize_to( sc_max( min_mant, n_word( 4 * length ) ) );
+
+ m_mant.clear();
+ m_msw = m_lsw = 0;
+
+ for( ; s < end; s ++ )
+ {
+ switch( *s )
+ {
+ case '9': case '8': case '7': case '6': case '5':
+ case '4': case '3': case '2': case '1': case '0':
+ multiply_by_ten();
+ carry = *s - '0';
+ for ( int i = 0; carry && i < m_mant.size(); i++ )
+ {
+ temp = m_mant[i];
+ temp += carry;
+ carry = temp < m_mant[i];
+ m_mant[i] = temp;
+ }
+ case '.':
+ break;
+ default:
+ SCFX_FAIL_IF_( true ); // should not happen
+ }
+ }
+
+ m_wp = 0;
+ find_sw();
+
+ int denominator = frac_digits - exponent;
+
+ if( denominator )
+ {
+ scfx_rep frac_num = pow10_fx( denominator );
+ scfx_rep* temp_num =
+ div_scfx_rep( const_cast<const scfx_rep&>( *this ),
+ frac_num, cte_wl );
+ *this = *temp_num;
+ delete temp_num;
+ }
+
+ break;
+ }
+ case 16:
+ {
+ exponent *= 4;
+ int_digits *= 4;
+ frac_digits *= 4;
+
+ int bit_offset = exponent % bits_in_word;
+ int word_offset = exponent / bits_in_word;
+
+ int_digits += bit_offset;
+ frac_digits -= bit_offset;
+
+ int words = n_word( int_digits ) + n_word( frac_digits );
+ if( words > size() )
+ resize_to( words );
+ m_mant.clear();
+
+ int j = n_word( frac_digits ) * bits_in_word + int_digits - 4;
+
+ for( ; s < end; s ++ )
+ {
+ switch( *s )
+ {
+ case 'f': case 'e': case 'd': case 'c': case 'b': case 'a':
+ set_hex( j, *s - 'a' + 10 );
+ j -= 4;
+ break;
+ case 'F': case 'E': case 'D': case 'C': case 'B': case 'A':
+ set_hex( j, *s - 'A' + 10 );
+ j -= 4;
+ break;
+ case '9': case '8': case '7': case '6': case '5':
+ case '4': case '3': case '2': case '1':
+ set_hex( j, *s - '0' );
+ case '0':
+ j -= 4;
+ case '.':
+ break;
+ default:
+ SCFX_FAIL_IF_( true ); // should not happen
+ }
+ }
+
+ m_wp = n_word( frac_digits ) - word_offset;
+ break;
+ }
+ }
+
+ m_state = normal;
+ find_sw();
+
+ //
+ // two's complement of mantissa if it is negative
+ //
+
+ if( mant_is_neg )
+ {
+ m_mant[m_msw] |= -1 << scfx_find_msb( m_mant[m_msw] );
+ for( int i = m_msw + 1; i < m_mant.size(); ++ i )
+ m_mant[i] = static_cast<word>( -1 );
+ complement( m_mant, m_mant, m_mant.size() );
+ inc( m_mant );
+ m_sign *= -1;
+ find_sw();
+ }
+}
+
+
+#undef SCFX_FAIL_IF_
+
+
+// ----------------------------------------------------------------------------
+// METHOD : to_double
+//
+// Convert from scfx_rep to double.
+// ----------------------------------------------------------------------------
+
+double
+scfx_rep::to_double() const
+{
+ scfx_ieee_double id;
+
+ // handle special cases
+
+ if( is_nan() )
+ {
+ id.set_nan();
+ return id;
+ }
+
+ if( is_inf() )
+ {
+ id.set_inf();
+ id.negative( m_sign < 0 );
+ return id;
+ }
+
+ if( is_zero() )
+ {
+ id = 0.;
+ id.negative( m_sign < 0 );
+ return id;
+ }
+
+ int msb = scfx_find_msb( m_mant[m_msw] );
+
+ int exp = (m_msw - m_wp) * bits_in_word + msb;
+
+ if( exp > SCFX_IEEE_DOUBLE_E_MAX )
+ {
+ id.set_inf();
+ id.negative( m_sign < 0 );
+ return id;
+ }
+
+ if( exp < SCFX_IEEE_DOUBLE_E_MIN
+ - static_cast<int>( SCFX_IEEE_DOUBLE_M_SIZE ) )
+ {
+ id = 0.;
+ return id;
+ }
+
+ int shift = mantissa0_size - msb;
+
+ unsigned int m0;
+ unsigned int m1 = 0;
+ unsigned int guard = 0;
+
+ if( shift == 0 )
+ {
+ m0 = m_mant[m_msw] & ~( 1 << mantissa0_size );
+ if( m_msw > m_lsw )
+ {
+ m1 = m_mant[m_msw - 1];
+ if( m_msw - 1 > m_lsw )
+ guard = m_mant[m_msw - 2] >> ( bits_in_word - 1 );
+ }
+ }
+ else if( shift < 0 )
+ {
+ m0 = ( m_mant[m_msw] >> -shift ) & ~( 1 << mantissa0_size );
+ m1 = m_mant[m_msw] << ( bits_in_word + shift );
+ if( m_msw > m_lsw )
+ {
+ m1 |= m_mant[m_msw - 1] >> -shift;
+ guard = ( m_mant[m_msw - 1] >> ( -shift - 1 ) ) & 1;
+ }
+ }
+ else
+ {
+ m0 = ( m_mant[m_msw] << shift ) & ~( 1 << mantissa0_size );
+ if( m_msw > m_lsw )
+ {
+ m0 |= m_mant[m_msw - 1] >> ( bits_in_word - shift );
+ m1 = m_mant[m_msw - 1] << shift;
+ if( m_msw - 1 > m_lsw )
+ {
+ m1 |= m_mant[m_msw - 2] >> ( bits_in_word - shift );
+ guard = ( m_mant[m_msw - 2] >> (bits_in_word - shift - 1) )
+ & 1;
+ }
+ }
+ }
+
+ if( exp < SCFX_IEEE_DOUBLE_E_MIN )
+ {
+ m0 |= ( 1 << mantissa0_size );
+
+ int subnormal_shift = SCFX_IEEE_DOUBLE_E_MIN - exp;
+
+ if( subnormal_shift < bits_in_word )
+ {
+ m1 = m1 >> subnormal_shift
+ | m0 << ( bits_in_word - subnormal_shift );
+ m0 = m0 >> subnormal_shift;
+ }
+ else
+ {
+ m1 = m0 >> ( subnormal_shift - bits_in_word );
+ m0 = 0;
+ }
+
+ guard = 0;
+
+ exp = SCFX_IEEE_DOUBLE_E_MIN - 1;
+ }
+
+ id.mantissa0( m0 );
+ id.mantissa1( m1 );
+ id.exponent( exp );
+ id.negative( m_sign < 0 );
+
+ double result = id;
+
+ if( guard != 0 )
+ result += m_sign * scfx_pow2( exp - SCFX_IEEE_DOUBLE_M_SIZE );
+
+ return result;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : to_string
+//
+// Convert from scfx_rep to character string.
+// ----------------------------------------------------------------------------
+
+void
+print_dec( scfx_string& s, const scfx_rep& num, int w_prefix, sc_fmt fmt )
+{
+ if( num.is_neg() )
+ s += '-';
+
+ if( w_prefix == 1 ) {
+ scfx_print_prefix( s, SC_DEC );
+ }
+
+ if( num.is_zero() )
+ {
+ s += '0';
+ return;
+ }
+
+ // split 'num' into its integer and fractional part
+
+ scfx_rep int_part = num;
+ scfx_rep frac_part = num;
+
+ int i;
+
+ for( i = int_part.m_lsw; i <= int_part.m_msw && i < int_part.m_wp; i ++ )
+ int_part.m_mant[i] = 0;
+ int_part.find_sw();
+ if( int_part.m_wp < int_part.m_lsw )
+ int_part.resize_to( int_part.size() - int_part.m_wp, -1 );
+
+ for( i = frac_part.m_msw;
+ i >= frac_part.m_lsw && i >= frac_part.m_wp;
+ i -- )
+ frac_part.m_mant[i] = 0;
+ frac_part.find_sw();
+ if( frac_part.m_msw == frac_part.size() - 1 )
+ frac_part.resize_to( frac_part.size() + 1, 1 );
+
+ // print integer part
+
+ int int_digits = 0;
+ int int_zeros = 0;
+
+ if( ! int_part.is_zero() )
+ {
+ double int_wl = ( int_part.m_msw - int_part.m_wp ) * bits_in_word
+ + scfx_find_msb( int_part.m_mant[int_part.m_msw] ) + 1;
+ int_digits = (int) ceil( int_wl * log10( 2. ) );
+
+ int len = s.length();
+ s.append( int_digits );
+
+ bool zero_digits = ( frac_part.is_zero() && fmt != SC_F );
+
+ for( i = int_digits + len - 1; i >= len; i-- )
+ {
+ unsigned int remainder = int_part.divide_by_ten();
+ s[i] = static_cast<char>( '0' + remainder );
+
+ if( zero_digits )
+ {
+ if( remainder == 0 )
+ int_zeros ++;
+ else
+ zero_digits = false;
+ }
+ }
+
+ // discard trailing zeros from int_part
+ s.discard( int_zeros );
+
+ if( s[len] == '0' )
+ {
+ // int_digits was overestimated by one
+ s.remove( len );
+ -- int_digits;
+ }
+ }
+
+ // print fractional part
+
+ int frac_digits = 0;
+ int frac_zeros = 0;
+
+ if( ! frac_part.is_zero() )
+ {
+ s += '.';
+
+ bool zero_digits = ( int_digits == 0 && fmt != SC_F );
+
+ double frac_wl = ( frac_part.m_wp - frac_part.m_msw ) * bits_in_word
+ - scfx_find_msb( frac_part.m_mant[frac_part.m_msw] )
+ - 1;
+ frac_zeros = (int) floor( frac_wl * log10( 2. ) );
+
+ scfx_rep temp;
+ sc_dt::multiply( temp, frac_part, pow10_fx( frac_zeros ) );
+ frac_part = temp;
+ if( frac_part.m_msw == frac_part.size() - 1 )
+ frac_part.resize_to( frac_part.size() + 1, 1 );
+
+ frac_digits = frac_zeros;
+ if( ! zero_digits )
+ {
+ for( i = 0; i < frac_zeros; i ++ )
+ s += '0';
+ frac_zeros = 0;
+ }
+
+ while( ! frac_part.is_zero() )
+ {
+ frac_part.multiply_by_ten();
+ int n = frac_part.m_mant[frac_part.m_msw + 1];
+
+ if( zero_digits )
+ {
+ if( n == 0 )
+ frac_zeros ++;
+ else
+ zero_digits = false;
+ }
+
+ if( ! zero_digits )
+ s += static_cast<char>( '0' + n );
+
+ frac_part.m_mant[frac_part.m_msw + 1] = 0;
+ frac_digits ++;
+ }
+ }
+
+ // print exponent
+
+ if( fmt != SC_F )
+ {
+ if( frac_digits == 0 )
+ scfx_print_exp( s, int_zeros );
+ else if( int_digits == 0 )
+ scfx_print_exp( s, - frac_zeros );
+ }
+}
+
+void
+print_other( scfx_string& s, const scfx_rep& a, sc_numrep numrep, int w_prefix,
+ sc_fmt fmt, const scfx_params* params )
+{
+ scfx_rep b = a;
+
+ sc_numrep numrep2 = numrep;
+
+ bool numrep_is_sm = ( numrep == SC_BIN_SM ||
+ numrep == SC_OCT_SM ||
+ numrep == SC_HEX_SM );
+
+ if( numrep_is_sm )
+ {
+ if( b.is_neg() )
+ {
+ s += '-';
+ b = *neg_scfx_rep( a );
+ }
+ switch( numrep )
+ {
+ case SC_BIN_SM:
+ numrep2 = SC_BIN_US;
+ break;
+ case SC_OCT_SM:
+ numrep2 = SC_OCT_US;
+ break;
+ case SC_HEX_SM:
+ numrep2 = SC_HEX_US;
+ break;
+ default:
+ ;
+ }
+ }
+
+ if( w_prefix != 0 ) {
+ scfx_print_prefix( s, numrep );
+ }
+
+ numrep = numrep2;
+
+ int msb, lsb;
+
+ if( params != 0 )
+ {
+ msb = params->iwl() - 1;
+ lsb = params->iwl() - params->wl();
+
+ if( params->enc() == SC_TC_ &&
+ ( numrep == SC_BIN_US ||
+ numrep == SC_OCT_US ||
+ numrep == SC_HEX_US ) &&
+ ! numrep_is_sm &&
+ params->wl() > 1 )
+ -- msb;
+ else if( params->enc() == SC_US_ &&
+ ( numrep == SC_BIN ||
+ numrep == SC_OCT ||
+ numrep == SC_HEX ||
+ numrep == SC_CSD ) )
+ ++ msb;
+ }
+ else
+ {
+ if( b.is_zero() )
+ {
+ msb = 0;
+ lsb = 0;
+ }
+ else
+ {
+ msb = ( b.m_msw - b.m_wp ) * bits_in_word
+ + scfx_find_msb( b.m_mant[ b.m_msw ] ) + 1;
+ while( b.get_bit( msb ) == b.get_bit( msb - 1 ) )
+ -- msb;
+
+ if( numrep == SC_BIN_US ||
+ numrep == SC_OCT_US ||
+ numrep == SC_HEX_US )
+ -- msb;
+
+ lsb = ( b.m_lsw - b.m_wp ) * bits_in_word
+ + scfx_find_lsb( b.m_mant[ b.m_lsw ] );
+ }
+ }
+
+ int step;
+
+ switch( numrep )
+ {
+ case SC_BIN:
+ case SC_BIN_US:
+ case SC_CSD:
+ step = 1;
+ break;
+ case SC_OCT:
+ case SC_OCT_US:
+ step = 3;
+ break;
+ case SC_HEX:
+ case SC_HEX_US:
+ step = 4;
+ break;
+ default:
+ step = 0;
+ }
+
+ msb = (int) ceil( double( msb + 1 ) / step ) * step - 1;
+
+ lsb = (int) floor( double( lsb ) / step ) * step;
+
+ if( msb < 0 )
+ {
+ s += '.';
+ if( fmt == SC_F )
+ {
+ int sign = ( b.is_neg() ) ? ( 1 << step ) - 1 : 0;
+ for( int i = ( msb + 1 ) / step; i < 0; i ++ )
+ {
+ if( sign < 10 )
+ s += static_cast<char>( sign + '0' );
+ else
+ s += static_cast<char>( sign + 'a' - 10 );
+ }
+ }
+ }
+
+ int i = msb;
+ while( i >= lsb )
+ {
+ int value = 0;
+ for( int j = step - 1; j >= 0; -- j )
+ {
+ value += static_cast<int>( b.get_bit( i ) ) << j;
+ -- i;
+ }
+ if( value < 10 )
+ s += static_cast<char>( value + '0' );
+ else
+ s += static_cast<char>( value + 'a' - 10 );
+ if( i == -1 )
+ s += '.';
+ }
+
+ if( lsb > 0 && fmt == SC_F )
+ {
+ for( int i = lsb / step; i > 0; i -- )
+ s += '0';
+ }
+
+ if( s[s.length() - 1] == '.' )
+ s.discard( 1 );
+
+ if( fmt != SC_F )
+ {
+ if( msb < 0 )
+ scfx_print_exp( s, ( msb + 1 ) / step );
+ else if( lsb > 0 )
+ scfx_print_exp( s, lsb / step );
+ }
+
+ if( numrep == SC_CSD )
+ scfx_tc2csd( s, w_prefix );
+}
+
+const char*
+scfx_rep::to_string( sc_numrep numrep, int w_prefix,
+ sc_fmt fmt, const scfx_params* params ) const
+{
+ static scfx_string s;
+
+ s.clear();
+
+ if( is_nan() )
+ scfx_print_nan( s );
+ else if( is_inf() )
+ scfx_print_inf( s, is_neg() );
+ else if( is_neg() && ! is_zero() &&
+ ( numrep == SC_BIN_US ||
+ numrep == SC_OCT_US ||
+ numrep == SC_HEX_US ) )
+ s += "negative";
+ else if( numrep == SC_DEC || numrep == SC_NOBASE )
+ sc_dt::print_dec( s, *this, w_prefix, fmt );
+ else
+ sc_dt::print_other( s, *this, numrep, w_prefix, fmt, params );
+
+ return s;
+}
+
+
+// ----------------------------------------------------------------------------
+// ADD
+//
+// add two mantissas of the same size
+// result has the same size
+// returns carry of operation
+// ----------------------------------------------------------------------------
+
+static inline
+int
+add_mants( int size, scfx_mant& result,
+ const scfx_mant& a, const scfx_mant& b )
+{
+ unsigned int carry = 0;
+
+ int index = 0;
+
+ do
+ {
+ word x = a[index];
+ word y = b[index];
+
+ y += carry;
+ carry = y < carry;
+ y += x;
+ carry += y < x;
+ result[index] = y;
+ }
+ while( ++ index < size );
+
+ return ( carry ? 1 : 0 );
+}
+
+
+static inline
+int
+sub_mants( int size, scfx_mant& result,
+ const scfx_mant& a, const scfx_mant& b )
+{
+ unsigned carry = 0;
+
+ int index = 0;
+
+ do
+ {
+ word x = a[index];
+ word y = b[index];
+
+ y += carry;
+ carry = y < carry;
+ y = x - y;
+ carry += y > x;
+ result[index] = y;
+ }
+ while( ++ index < size );
+
+ return ( carry ? 1 : 0 );
+}
+
+
+scfx_rep*
+add_scfx_rep( const scfx_rep& lhs, const scfx_rep& rhs, int max_wl )
+{
+ scfx_rep& result = *new scfx_rep;
+
+ //
+ // check for special cases
+ //
+
+ if( lhs.is_nan() || rhs.is_nan()
+ || ( lhs.is_inf() && rhs.is_inf() && lhs.m_sign != rhs.m_sign ) )
+ {
+ result.set_nan();
+ return &result;
+ }
+
+ if( lhs.is_inf() )
+ {
+ result.set_inf( lhs.m_sign );
+ return &result;
+ }
+
+ if( rhs.is_inf() )
+ {
+ result.set_inf( rhs.m_sign );
+ return &result;
+ }
+
+ //
+ // align operands if needed
+ //
+
+ scfx_mant_ref lhs_mant;
+ scfx_mant_ref rhs_mant;
+
+ int len_mant = lhs.size();
+ int new_wp = lhs.m_wp;
+
+ align( lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant );
+
+ //
+ // size the result mantissa
+ //
+
+ result.resize_to( len_mant );
+ result.m_wp = new_wp;
+
+ //
+ // do it
+ //
+
+ if( lhs.m_sign == rhs.m_sign )
+ {
+ add_mants( len_mant, result.m_mant, lhs_mant, rhs_mant );
+ result.m_sign = lhs.m_sign;
+ }
+ else
+ {
+ int cmp = compare_abs( lhs, rhs );
+
+ if( cmp == 1 )
+ {
+ sub_mants( len_mant, result.m_mant, lhs_mant, rhs_mant );
+ result.m_sign = lhs.m_sign;
+ }
+ else if ( cmp == -1 )
+ {
+ sub_mants( len_mant, result.m_mant, rhs_mant, lhs_mant );
+ result.m_sign = rhs.m_sign;
+ }
+ else
+ {
+ result.m_mant.clear();
+ result.m_sign = 1;
+ }
+ }
+
+ result.find_sw();
+ result.round( max_wl );
+
+ return &result;
+}
+
+
+// ----------------------------------------------------------------------------
+// SUB
+//
+// sub two word's of the same size
+// result has the same size
+// returns carry of operation
+// ----------------------------------------------------------------------------
+
+static inline
+int
+sub_with_index( scfx_mant& a, int a_msw, int /*a_lsw*/,
+ const scfx_mant& b, int b_msw, int b_lsw )
+{
+ unsigned carry = 0;
+
+ int size = b_msw - b_lsw;
+ int a_index = a_msw - size;
+ int b_index = b_msw - size;
+
+ do
+ {
+ word x = a[a_index];
+ word y = b[b_index];
+
+ y += carry;
+ carry = y < carry;
+ y = x - y;
+ carry += y > x;
+ a[a_index] = y;
+
+ a_index ++;
+ b_index ++;
+ }
+ while( size -- );
+
+ if( carry )
+ {
+ // special case: a[a_msw + 1 ] == 1
+ a[a_msw + 1] = 0;
+ }
+
+ return ( carry ? 1 : 0 );
+}
+
+
+scfx_rep*
+sub_scfx_rep( const scfx_rep& lhs, const scfx_rep& rhs, int max_wl )
+{
+ scfx_rep& result = *new scfx_rep;
+
+ //
+ // check for special cases
+ //
+
+ if( lhs.is_nan() || rhs.is_nan()
+ || ( lhs.is_inf() && rhs.is_inf() && lhs.m_sign == rhs.m_sign ) )
+ {
+ result.set_nan();
+ return &result;
+ }
+
+ if( lhs.is_inf() )
+ {
+ result.set_inf( lhs.m_sign );
+ return &result;
+ }
+
+ if( rhs.is_inf() )
+ {
+ result.set_inf( -1 * rhs.m_sign );
+ return &result;
+ }
+
+ //
+ // align operands if needed
+ //
+
+ scfx_mant_ref lhs_mant;
+ scfx_mant_ref rhs_mant;
+
+ int len_mant = lhs.size();
+ int new_wp = lhs.m_wp;
+
+ align( lhs, rhs, new_wp, len_mant, lhs_mant, rhs_mant );
+
+ //
+ // size the result mantissa
+ //
+
+ result.resize_to( len_mant );
+ result.m_wp = new_wp;
+
+ //
+ // do it
+ //
+
+ if( lhs.m_sign != rhs.m_sign )
+ {
+ add_mants( len_mant, result.m_mant, lhs_mant, rhs_mant );
+ result.m_sign = lhs.m_sign;
+ }
+ else
+ {
+ int cmp = compare_abs( lhs, rhs );
+
+ if( cmp == 1 )
+ {
+ sub_mants( len_mant, result.m_mant, lhs_mant, rhs_mant );
+ result.m_sign = lhs.m_sign;
+ }
+ else if ( cmp == -1 )
+ {
+ sub_mants( len_mant, result.m_mant, rhs_mant, lhs_mant );
+ result.m_sign = -rhs.m_sign;
+ } else {
+ result.m_mant.clear();
+ result.m_sign = 1;
+ }
+ }
+
+ result.find_sw();
+ result.round( max_wl );
+
+ return &result;
+}
+
+
+// ----------------------------------------------------------------------------
+// MUL
+// ----------------------------------------------------------------------------
+
+union word_short
+{
+ word l;
+ struct
+ {
+#if defined( SC_BIG_ENDIAN )
+ half_word u;
+ half_word l;
+#elif defined( SC_LITTLE_ENDIAN )
+ half_word l;
+ half_word u;
+#endif
+ } s;
+};
+
+
+#if defined( SC_BIG_ENDIAN )
+static const int half_word_incr = -1;
+#elif defined( SC_LITTLE_ENDIAN )
+static const int half_word_incr = 1;
+#endif
+
+
+void
+multiply( scfx_rep& result, const scfx_rep& lhs, const scfx_rep& rhs,
+ int max_wl )
+{
+ //
+ // check for special cases
+ //
+
+ if( lhs.is_nan() || rhs.is_nan()
+ || (lhs.is_inf() && rhs.is_zero())
+ || (lhs.is_zero() && rhs.is_inf()) )
+ {
+ result.set_nan();
+ return;
+ }
+
+ if( lhs.is_inf() || rhs.is_inf() )
+ {
+ result.set_inf( lhs.m_sign * rhs.m_sign );
+ return;
+ }
+
+ if( lhs.is_zero() || rhs.is_zero() ) {
+ result.set_zero( lhs.m_sign * rhs.m_sign );
+ return;
+ }
+
+ //
+ // do it
+ //
+
+ int len_lhs = lhs.m_msw - lhs.m_lsw + 1;
+ int len_rhs = rhs.m_msw - rhs.m_lsw + 1;
+
+ int new_size = sc_max( min_mant, len_lhs + len_rhs );
+ int new_wp = ( lhs.m_wp - lhs.m_lsw ) + ( rhs.m_wp - rhs.m_lsw );
+ int new_sign = lhs.m_sign * rhs.m_sign;
+
+ result.resize_to( new_size );
+ result.m_mant.clear();
+ result.m_wp = new_wp;
+ result.m_sign = new_sign;
+ result.m_state = scfx_rep::normal;
+
+ half_word *s1 = lhs.m_mant.half_addr( lhs.m_lsw );
+ half_word *s2 = rhs.m_mant.half_addr( rhs.m_lsw );
+
+ half_word *t = result.m_mant.half_addr();
+
+ len_lhs <<= 1;
+ len_rhs <<= 1;
+
+ int i1, i2;
+
+ for( i1 = 0; i1 * half_word_incr < len_lhs; i1 += half_word_incr )
+ {
+ word_short ls;
+ ls.l = 0;
+
+ half_word v1 = s1[i1];
+
+ for( i2 = 0; i2 * half_word_incr < len_rhs; i2 += half_word_incr )
+ {
+ ls.l += v1 * s2[i2];
+ ls.s.l = ls.s.u + ( ( t[i2] += ls.s.l ) < ls.s.l );
+ ls.s.u = 0;
+ }
+
+ t[i2] = ls.s.l;
+ t += half_word_incr;
+ }
+
+ result.find_sw();
+ result.round( max_wl );
+}
+
+
+// ----------------------------------------------------------------------------
+// DIV
+// ----------------------------------------------------------------------------
+
+scfx_rep*
+div_scfx_rep( const scfx_rep& lhs, const scfx_rep& rhs, int div_wl )
+{
+ scfx_rep& result = *new scfx_rep;
+
+ //
+ // check for special cases
+ //
+
+ if( lhs.is_nan() || rhs.is_nan() || (lhs.is_inf() && rhs.is_inf()) ||
+ (lhs.is_zero() && rhs.is_zero()) )
+ {
+ result.set_nan();
+ return &result;
+ }
+
+ if( lhs.is_inf() || rhs.is_zero() )
+ {
+ result.set_inf( lhs.m_sign * rhs.m_sign );
+ return &result;
+ }
+
+ if( lhs.is_zero() || rhs.is_inf() )
+ {
+ result.set_zero( lhs.m_sign * rhs.m_sign );
+ return &result;
+ }
+
+ //
+ // do it
+ //
+
+ // compute one bit more for rounding
+ div_wl ++;
+
+ result.resize_to( sc_max( n_word( div_wl ) + 1, min_mant ) );
+ result.m_mant.clear();
+ result.m_sign = lhs.m_sign * rhs.m_sign;
+
+ int msb_lhs = scfx_find_msb( lhs.m_mant[lhs.m_msw] )
+ + ( lhs.m_msw - lhs.m_wp ) * bits_in_word;
+ int msb_rhs = scfx_find_msb( rhs.m_mant[rhs.m_msw] )
+ + ( rhs.m_msw - rhs.m_wp ) * bits_in_word;
+
+ int msb_res = msb_lhs - msb_rhs;
+ int to_shift = -msb_res % bits_in_word;
+ int result_index;
+
+ int c = ( msb_res % bits_in_word >= 0 ) ? 1 : 0;
+
+ result_index = (result.size() - c) * bits_in_word + msb_res % bits_in_word;
+ result.m_wp = (result.size() - c) - msb_res / bits_in_word;
+
+ scfx_rep remainder = lhs;
+
+ // align msb from remainder to msb from rhs
+ remainder.lshift( to_shift );
+
+ // make sure msw( remainder ) < size - 1
+ if( remainder.m_msw == remainder.size() - 1 )
+ remainder.resize_to( remainder.size() + 1, 1 );
+
+ // make sure msw( remainder ) >= msw( rhs )!
+ int msw_diff = rhs.m_msw - remainder.m_msw;
+ if (msw_diff > 0)
+ remainder.resize_to( remainder.size() + msw_diff, -1 );
+
+ int counter;
+
+ for( counter = div_wl; counter && ! remainder.is_zero(); counter -- )
+ {
+ if( compare_msw_ff( rhs, remainder ) <= 0 )
+ {
+ result.set_bin( result_index );
+ sub_with_index( remainder.m_mant, remainder.m_msw, remainder.m_lsw,
+ rhs.m_mant, rhs.m_msw, rhs.m_lsw );
+ }
+ result_index --;
+ remainder.shift_left( 1 );
+ remainder.m_lsw = remainder.find_lsw();
+ }
+
+ // perform convergent rounding, if needed
+ if( counter == 0 )
+ {
+ int index = result_index + 1 - result.m_wp * bits_in_word;
+
+ scfx_index x = result.calc_indices( index );
+ scfx_index x1 = result.calc_indices( index + 1 );
+
+ if( result.o_bit_at( x ) && result.o_bit_at( x1 ) )
+ result.q_incr( x );
+
+ result.m_r_flag = true;
+ }
+
+ result.find_sw();
+
+ return &result;
+}
+
+
+// ----------------------------------------------------------------------------
+// destructive shift mantissa to the left
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::lshift( int n )
+{
+ if( n == 0 )
+ return;
+
+ if( n < 0 )
+ {
+ rshift( -n );
+ return;
+ }
+
+ if( is_normal() )
+ {
+ int shift_bits = n % bits_in_word;
+ int shift_words = n / bits_in_word;
+
+ // resize if needed
+ if( m_msw == size() - 1 &&
+ scfx_find_msb( m_mant[m_msw] ) >= bits_in_word - shift_bits )
+ resize_to( size() + 1, 1 );
+
+ // do it
+ m_wp -= shift_words;
+ shift_left( shift_bits );
+ find_sw();
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// destructive shift mantissa to the right
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::rshift( int n )
+{
+ if( n == 0 )
+ return;
+
+ if( n < 0 )
+ {
+ lshift( -n );
+ return;
+ }
+
+ if( is_normal() )
+ {
+ int shift_bits = n % bits_in_word;
+ int shift_words = n / bits_in_word;
+
+ // resize if needed
+ if( m_lsw == 0 && scfx_find_lsb( m_mant[m_lsw] ) < shift_bits )
+ resize_to( size() + 1, -1 );
+
+ // do it
+ m_wp += shift_words;
+ shift_right( shift_bits );
+ find_sw();
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// FRIEND FUNCTION : compare_abs
+//
+// Compares the absolute values of two scfx_reps, excluding the special cases.
+// ----------------------------------------------------------------------------
+
+int
+compare_abs( const scfx_rep& a, const scfx_rep& b )
+{
+ // check for zero
+
+ word a_word = a.m_mant[a.m_msw];
+ word b_word = b.m_mant[b.m_msw];
+
+ if( a_word == 0 || b_word == 0 )
+ {
+ if( a_word != 0 )
+ return 1;
+ if( b_word != 0 )
+ return -1;
+ return 0;
+ }
+
+ // compare msw index
+
+ int a_msw = a.m_msw - a.m_wp;
+ int b_msw = b.m_msw - b.m_wp;
+
+ if( a_msw > b_msw )
+ return 1;
+
+ if( a_msw < b_msw )
+ return -1;
+
+ // compare content
+
+ int a_i = a.m_msw;
+ int b_i = b.m_msw;
+
+ while( a_i >= a.m_lsw && b_i >= b.m_lsw )
+ {
+ a_word = a.m_mant[a_i];
+ b_word = b.m_mant[b_i];
+ if( a_word > b_word )
+ return 1;
+ if( a_word < b_word )
+ return -1;
+ -- a_i;
+ -- b_i;
+ }
+
+ bool a_zero = true;
+ while( a_i >= a.m_lsw )
+ {
+ a_zero = a_zero && ( a.m_mant[a_i] == 0 );
+ -- a_i;
+ }
+
+ bool b_zero = true;
+ while( b_i >= b.m_lsw )
+ {
+ b_zero = b_zero && ( b.m_mant[b_i] == 0 );
+ -- b_i;
+ }
+
+ // assertion: a_zero || b_zero == true
+
+ if( ! a_zero && b_zero )
+ return 1;
+
+ if( a_zero && ! b_zero )
+ return -1;
+
+ return 0;
+}
+
+
+// ----------------------------------------------------------------------------
+// FRIEND FUNCTION : cmp_scfx_rep
+//
+// Compares the values of two scfx_reps, including the special cases.
+// ----------------------------------------------------------------------------
+
+int
+cmp_scfx_rep( const scfx_rep& a, const scfx_rep& b )
+{
+ // handle special cases
+
+ if( a.is_nan() || b.is_nan() )
+ {
+#if 0
+ if( a.is_nan() && b.is_nan() )
+ {
+ return 0;
+ }
+#endif
+ return 2;
+ }
+
+ if( a.is_inf() || b.is_inf() )
+ {
+ if( a.is_inf() )
+ {
+ if( ! a.is_neg() )
+ {
+ if( b.is_inf() && ! b.is_neg() )
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ else
+ {
+ if( b.is_inf() && b.is_neg() )
+ {
+ return 0;
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ }
+ if( b.is_inf() )
+ {
+ if( ! b.is_neg() )
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+ }
+
+ if( a.is_zero() && b.is_zero() )
+ {
+ return 0;
+ }
+
+ // compare sign
+
+ if( a.m_sign != b.m_sign )
+ {
+ return a.m_sign;
+ }
+
+ return ( a.m_sign * compare_abs( a, b ) );
+}
+
+
+// ----------------------------------------------------------------------------
+// PRIVATE METHOD : quantization
+//
+// Performs destructive quantization.
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::quantization( const scfx_params& params, bool& q_flag )
+{
+ scfx_index x = calc_indices( params.iwl() - params.wl() );
+
+ if( x.wi() < 0 )
+ return;
+
+ if( x.wi() >= size() )
+ resize_to( x.wi() + 1, 1 );
+
+ bool qb = q_bit( x );
+ bool qz = q_zero( x );
+
+ q_flag = ( qb || ! qz );
+
+ if( q_flag )
+ {
+ switch( params.q_mode() )
+ {
+ case SC_TRN: // truncation
+ {
+ if( is_neg() )
+ q_incr( x );
+ break;
+ }
+ case SC_RND: // rounding to plus infinity
+ {
+ if( ! is_neg() )
+ {
+ if( qb )
+ q_incr( x );
+ }
+ else
+ {
+ if( qb && ! qz )
+ q_incr( x );
+ }
+ break;
+ }
+ case SC_TRN_ZERO: // truncation to zero
+ {
+ break;
+ }
+ case SC_RND_INF: // rounding to infinity
+ {
+ if( qb )
+ q_incr( x );
+ break;
+ }
+ case SC_RND_CONV: // convergent rounding
+ {
+ if( (qb && ! qz) || (qb && qz && q_odd( x )) )
+ q_incr( x );
+ break;
+ }
+ case SC_RND_ZERO: // rounding to zero
+ {
+ if( qb && ! qz )
+ q_incr( x );
+ break;
+ }
+ case SC_RND_MIN_INF: // rounding to minus infinity
+ {
+ if( ! is_neg() )
+ {
+ if( qb && ! qz )
+ q_incr( x );
+ }
+ else
+ {
+ if( qb )
+ q_incr( x );
+ }
+ break;
+ }
+ default:
+ ;
+ }
+ q_clear( x );
+
+ find_sw();
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// PRIVATE METHOD : overflow
+//
+// Performs destructive overflow handling.
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::overflow( const scfx_params& params, bool& o_flag )
+{
+ scfx_index x = calc_indices( params.iwl() - 1 );
+
+ if( x.wi() >= size() )
+ resize_to( x.wi() + 1, 1 );
+
+ if( x.wi() < 0 )
+ {
+ resize_to( size() - x.wi(), -1 );
+ x.wi( 0 );
+ }
+
+ bool zero_left = o_zero_left( x );
+ bool bit_at = o_bit_at( x );
+ bool zero_right = o_zero_right( x );
+
+ bool under = false;
+ bool over = false;
+
+ sc_enc enc = params.enc();
+
+ if( enc == SC_TC_ )
+ {
+ if( is_neg() )
+ {
+ if( params.o_mode() == SC_SAT_SYM )
+ under = ( ! zero_left || bit_at );
+ else
+ under = (! zero_left || (zero_left && bit_at && ! zero_right));
+ }
+ else
+ over = ( ! zero_left || bit_at );
+ }
+ else
+ {
+ if( is_neg() )
+ under = ( ! is_zero() );
+ else
+ over = ( ! zero_left );
+ }
+
+ o_flag = ( under || over );
+
+ if( o_flag )
+ {
+ scfx_index x2 = calc_indices( params.iwl() - params.wl() );
+
+ if( x2.wi() < 0 )
+ {
+ resize_to( size() - x2.wi(), -1 );
+ x.wi( x.wi() - x2.wi() );
+ x2.wi( 0 );
+ }
+
+ switch( params.o_mode() )
+ {
+ case SC_WRAP: // wrap-around
+ {
+ int n_bits = params.n_bits();
+
+ if( n_bits == 0 )
+ {
+ // wrap-around all 'wl' bits
+ toggle_tc();
+ o_extend( x, enc );
+ toggle_tc();
+ }
+ else if( n_bits < params.wl() )
+ {
+ scfx_index x3 = calc_indices( params.iwl() - 1 - n_bits );
+
+ // wrap-around least significant 'wl - n_bits' bits;
+ // saturate most significant 'n_bits' bits
+ toggle_tc();
+ o_set( x, x3, enc, under );
+ o_extend( x, enc );
+ toggle_tc();
+ }
+ else
+ {
+ // saturate all 'wl' bits
+ if( under )
+ o_set_low( x, enc );
+ else
+ o_set_high( x, x2, enc );
+ }
+ break;
+ }
+ case SC_SAT: // saturation
+ {
+ if( under )
+ o_set_low( x, enc );
+ else
+ o_set_high( x, x2, enc );
+ break;
+ }
+ case SC_SAT_SYM: // symmetrical saturation
+ {
+ if( under )
+ {
+ if( enc == SC_TC_ )
+ o_set_high( x, x2, SC_TC_, -1 );
+ else
+ o_set_low( x, SC_US_ );
+ }
+ else
+ o_set_high( x, x2, enc );
+ break;
+ }
+ case SC_SAT_ZERO: // saturation to zero
+ {
+ set_zero();
+ break;
+ }
+ case SC_WRAP_SM: // sign magnitude wrap-around
+ {
+ SC_ERROR_IF_( enc == SC_US_,
+ sc_core::SC_ID_WRAP_SM_NOT_DEFINED_ );
+
+ int n_bits = params.n_bits();
+
+ if( n_bits == 0 )
+ {
+ scfx_index x4 = calc_indices( params.iwl() );
+
+ if( x4.wi() >= size() )
+ resize_to( x4.wi() + 1, 1 );
+
+ toggle_tc();
+ if( o_bit_at( x4 ) != o_bit_at( x ) )
+ o_invert( x2 );
+ o_extend( x, SC_TC_ );
+ toggle_tc();
+ }
+ else if( n_bits == 1 )
+ {
+ toggle_tc();
+ if( is_neg() != o_bit_at( x ) )
+ o_invert( x2 );
+ o_extend( x, SC_TC_ );
+ toggle_tc();
+ }
+ else if( n_bits < params.wl() )
+ {
+ scfx_index x3 = calc_indices( params.iwl() - 1 - n_bits );
+ scfx_index x4 = calc_indices( params.iwl() - n_bits );
+
+ // wrap-around least significant 'wl - n_bits' bits;
+ // saturate most significant 'n_bits' bits
+ toggle_tc();
+ if( is_neg() == o_bit_at( x4 ) )
+ o_invert( x2 );
+ o_set( x, x3, SC_TC_, under );
+ o_extend( x, SC_TC_ );
+ toggle_tc();
+ }
+ else
+ {
+ if( under )
+ o_set_low( x, SC_TC_ );
+ else
+ o_set_high( x, x2, SC_TC_ );
+ }
+ break;
+ }
+ default:
+ ;
+ }
+
+ find_sw();
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// PUBLIC METHOD : cast
+//
+// Performs a destructive cast operation on a scfx_rep.
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::cast( const scfx_params& params, bool& q_flag, bool& o_flag )
+{
+ q_flag = false;
+ o_flag = false;
+
+ // check for special cases
+
+ if( is_zero() )
+ {
+ if( is_neg() )
+ m_sign = 1;
+ return;
+ }
+
+ // perform casting
+
+ quantization( params, q_flag );
+ overflow( params, o_flag );
+
+ // check for special case: -0
+
+ if( is_zero() && is_neg() )
+ m_sign = 1;
+}
+
+
+// ----------------------------------------------------------------------------
+// make sure, the two mantissas are aligned
+// ----------------------------------------------------------------------------
+
+void
+align( const scfx_rep& lhs, const scfx_rep& rhs, int& new_wp,
+ int& len_mant, scfx_mant_ref& lhs_mant, scfx_mant_ref& rhs_mant )
+{
+ bool need_lhs = true;
+ bool need_rhs = true;
+
+ if( lhs.m_wp != rhs.m_wp || lhs.size() != rhs.size() )
+ {
+ int lower_bound_lhs = lhs.m_lsw - lhs.m_wp;
+ int upper_bound_lhs = lhs.m_msw - lhs.m_wp;
+ int lower_bound_rhs = rhs.m_lsw - rhs.m_wp;
+ int upper_bound_rhs = rhs.m_msw - rhs.m_wp;
+
+ int lower_bound = sc_min( lower_bound_lhs, lower_bound_rhs );
+ int upper_bound = sc_max( upper_bound_lhs, upper_bound_rhs );
+
+ new_wp = -lower_bound;
+ len_mant = sc_max( min_mant, upper_bound - lower_bound + 1 );
+
+ if( new_wp != lhs.m_wp || len_mant != lhs.size() )
+ {
+ lhs_mant = lhs.resize( len_mant, new_wp );
+ need_lhs = false;
+ }
+
+ if( new_wp != rhs.m_wp || len_mant != rhs.size() )
+ {
+ rhs_mant = rhs.resize( len_mant, new_wp );
+ need_rhs = false;
+ }
+ }
+
+ if( need_lhs )
+ {
+ lhs_mant = lhs.m_mant;
+ }
+
+ if( need_rhs )
+ {
+ rhs_mant = rhs.m_mant;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// compare two mantissas
+// ----------------------------------------------------------------------------
+
+int
+compare_msw_ff( const scfx_rep& lhs, const scfx_rep& rhs )
+{
+ // special case: rhs.m_mant[rhs.m_msw + 1] == 1
+ if( rhs.m_msw < rhs.size() - 1 && rhs.m_mant[rhs.m_msw + 1 ] != 0 )
+ {
+ return -1;
+ }
+
+ int lhs_size = lhs.m_msw - lhs.m_lsw + 1;
+ int rhs_size = rhs.m_msw - rhs.m_lsw + 1;
+
+ int size = sc_min( lhs_size, rhs_size );
+
+ int lhs_index = lhs.m_msw;
+ int rhs_index = rhs.m_msw;
+
+ int i;
+
+ for( i = 0;
+ i < size && lhs.m_mant[lhs_index] == rhs.m_mant[rhs_index];
+ i ++ )
+ {
+ lhs_index --;
+ rhs_index --;
+ }
+
+ if( i == size )
+ {
+ if( lhs_size == rhs_size )
+ {
+ return 0;
+ }
+
+ if( lhs_size < rhs_size )
+ {
+ return -1;
+ }
+ else
+ {
+ return 1;
+ }
+ }
+
+ if( lhs.m_mant[lhs_index] < rhs.m_mant[rhs_index] )
+ {
+ return -1;
+ } else {
+ return 1;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// divide the mantissa by ten
+// ----------------------------------------------------------------------------
+
+unsigned int
+scfx_rep::divide_by_ten()
+{
+#if defined( SC_BIG_ENDIAN )
+ half_word* hw = (half_word*) &m_mant[m_msw];
+#elif defined( SC_LITTLE_ENDIAN )
+ half_word* hw = ( (half_word*) &m_mant[m_msw] ) + 1;
+#endif
+
+ unsigned int remainder = 0;
+
+ word_short ls;
+ ls.l = 0;
+
+#if defined( SC_BIG_ENDIAN )
+ for( int i = 0, end = ( m_msw - m_wp + 1 ) * 2; i < end; i ++ )
+#elif defined( SC_LITTLE_ENDIAN )
+ for( int i = 0, end = -( m_msw - m_wp + 1 ) * 2; i > end; i -- )
+#endif
+ {
+ ls.s.u = static_cast<half_word>( remainder );
+ ls.s.l = hw[i];
+ remainder = ls.l % 10;
+ ls.l /= 10;
+ hw[i] = ls.s.l;
+ }
+
+ return remainder;
+}
+
+
+// ----------------------------------------------------------------------------
+// multiply the mantissa by ten
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::multiply_by_ten()
+{
+ int size = m_mant.size() + 1;
+
+ scfx_mant mant8( size );
+ scfx_mant mant2( size );
+
+ size --;
+
+ mant8[size] = (m_mant[size - 1] >> (bits_in_word - 3));
+ mant2[size] = (m_mant[size - 1] >> (bits_in_word - 1));
+
+ while( -- size )
+ {
+ mant8[size] = ( m_mant[size] << 3 ) |
+ ( m_mant[size - 1] >> ( bits_in_word - 3 ) );
+ mant2[size] = ( m_mant[size] << 1 ) |
+ ( m_mant[size - 1] >> ( bits_in_word - 1 ) );
+ }
+
+ mant8[0] = ( m_mant[0] << 3 );
+ mant2[0] = ( m_mant[0] << 1 );
+
+ add_mants( m_mant.size(), m_mant, mant8, mant2 );
+
+#if 0
+ for( int i = size() - 1; i > 0; i -- )
+ {
+ m_mant[i] = ( m_mant[i] << 3 ) |
+ ( m_mant[i-1] >> ( bits_in_word - 3 ) )
+ + ( m_mant[i] << 1 ) |
+ ( m_mant[i-1] >> ( bits_in_word - 1 ) );
+ }
+ m_mant[0] = ( m_mant[0] << 3 ) + ( m_mant[0] << 1 );
+#endif
+}
+
+
+// ----------------------------------------------------------------------------
+// normalize
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::normalize( int exponent )
+{
+ int shift = exponent % bits_in_word;
+ if( shift < 0 )
+ {
+ shift += bits_in_word;
+ }
+
+ if( shift )
+ {
+ shift_left( shift );
+ }
+
+ find_sw();
+
+ m_wp = (shift - exponent) / bits_in_word;
+}
+
+
+// ----------------------------------------------------------------------------
+// return a new mantissa that is aligned and resized
+// ----------------------------------------------------------------------------
+
+scfx_mant*
+scfx_rep::resize( int new_size, int new_wp ) const
+{
+ scfx_mant *result = new scfx_mant( new_size );
+
+ result->clear();
+
+ int shift = new_wp - m_wp;
+
+ for( int j = m_lsw; j <= m_msw; j ++ )
+ {
+ (*result)[j+shift] = m_mant[j];
+ }
+
+ return result;
+}
+
+
+// ----------------------------------------------------------------------------
+// set a single bit
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::set_bin( int i )
+{
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+}
+
+
+// ----------------------------------------------------------------------------
+// set three bits
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::set_oct( int i, int n )
+{
+ if( n & 1 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+ i ++;
+ if( n & 2 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+ i ++;
+ if( n & 4 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// set four bits
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::set_hex( int i, int n )
+{
+ if( n & 1 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+ i ++;
+ if( n & 2 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+ i ++;
+ if( n & 4 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+ i ++;
+ if( n & 8 )
+ {
+ m_mant[i >> 5] |= 1 << ( i & 31 );
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// PRIVATE METHOD : shift_left
+//
+// Shifts a scfx_rep to the left by a MAXIMUM of bits_in_word - 1 bits.
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::shift_left( int n )
+{
+ if( n != 0 )
+ {
+ int shift_left = n;
+ int shift_right = bits_in_word - n;
+
+ SC_ASSERT_( !(m_mant[size()-1] >> shift_right),
+ "shift_left overflow" );
+
+ for( int i = size() - 1; i > 0; i -- )
+ {
+ m_mant[i] = ( m_mant[i] << shift_left ) |
+ ( m_mant[i-1] >> shift_right );
+ }
+ m_mant[0] <<= shift_left;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// PRIVATE METHOD : shift_right
+//
+// Shifts a scfx_rep to the right by a MAXIMUM of bits_in_word - 1 bits.
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::shift_right( int n )
+{
+ if( n != 0 )
+ {
+ int shift_left = bits_in_word - n;
+ int shift_right = n;
+
+ SC_ASSERT_( !(m_mant[0] << shift_left), "shift_right overflow" );
+
+ for( int i = 0; i < size() - 1; i ++ )
+ {
+ m_mant[i] = ( m_mant[i] >> shift_right ) |
+ ( m_mant[i+1] << shift_left );
+ }
+ m_mant[size()-1] >>= shift_right;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : get_bit
+//
+// Tests a bit, in two's complement.
+// ----------------------------------------------------------------------------
+
+bool
+scfx_rep::get_bit( int i ) const
+{
+ if( ! is_normal() )
+ return false;
+
+ scfx_index x = calc_indices( i );
+
+ if( x.wi() >= size() )
+ return is_neg();
+
+ if( x.wi() < 0 )
+ return false;
+
+ const_cast<scfx_rep*>( this )->toggle_tc();
+
+ bool result = ( m_mant[x.wi()] & ( 1 << x.bi() ) ) != 0;
+
+ const_cast<scfx_rep*>( this )->toggle_tc();
+
+ return result;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : set
+//
+// Sets a bit, in two's complement, between iwl-1 and -fwl.
+// ----------------------------------------------------------------------------
+
+bool
+scfx_rep::set( int i, const scfx_params& params )
+{
+ if( ! is_normal() )
+ return false;
+
+ scfx_index x = calc_indices( i );
+
+ if( x.wi() >= size() )
+ {
+ if( is_neg() )
+ return true;
+ else
+ resize_to( x.wi() + 1, 1 );
+ }
+ else if( x.wi() < 0 )
+ {
+ resize_to( size() - x.wi(), -1 );
+ x.wi( 0 );
+ }
+
+ toggle_tc();
+
+ m_mant[x.wi()] |= 1 << x.bi();
+
+ if( i == params.iwl() - 1 )
+ o_extend( x, params.enc() ); // sign extension
+
+ toggle_tc();
+
+ find_sw();
+
+ return true;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : clear
+//
+// Clears a bit, in two's complement, between iwl-1 and -fwl.
+// ----------------------------------------------------------------------------
+
+bool
+scfx_rep::clear( int i, const scfx_params& params )
+{
+ if( ! is_normal() )
+ return false;
+
+ scfx_index x = calc_indices( i );
+
+ if( x.wi() >= size() )
+ {
+ if( ! is_neg() )
+ return true;
+ else
+ resize_to( x.wi() + 1, 1 );
+ }
+ else if( x.wi() < 0 )
+ return true;
+
+ toggle_tc();
+
+ m_mant[x.wi()] &= ~( 1 << x.bi() );
+
+ if( i == params.iwl() - 1 )
+ o_extend( x, params.enc() ); // sign extension
+
+ toggle_tc();
+
+ find_sw();
+
+ return true;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : get_slice
+// ----------------------------------------------------------------------------
+
+bool
+scfx_rep::get_slice( int i, int j, const scfx_params&,
+ sc_bv_base& bv ) const
+{
+ if( is_nan() || is_inf() )
+ return false;
+
+ // get the bits
+
+ int l = j;
+ for( int k = 0; k < bv.length(); ++ k )
+ {
+ bv[k] = get_bit( l );
+
+ if( i >= j )
+ ++ l;
+ else
+ -- l;
+ }
+
+ return true;
+}
+
+bool
+scfx_rep::set_slice( int i, int j, const scfx_params& params,
+ const sc_bv_base& bv )
+{
+ if( is_nan() || is_inf() )
+ return false;
+
+ // set the bits
+
+ int l = j;
+ for( int k = 0; k < bv.length(); ++ k )
+ {
+ if( bv[k].to_bool() )
+ set( l, params );
+ else
+ clear( l, params );
+
+ if( i >= j )
+ ++ l;
+ else
+ -- l;
+ }
+
+ return true;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : print
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::print( ::std::ostream& os ) const
+{
+ os << to_string( SC_DEC, -1, SC_E );
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : dump
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::dump( ::std::ostream& os ) const
+{
+ os << "scfx_rep" << ::std::endl;
+ os << "(" << ::std::endl;
+
+ os << "mant =" << ::std::endl;
+ for( int i = size() - 1; i >= 0; i -- )
+ {
+ char buf[BUFSIZ];
+ std::sprintf( buf, " %d: %10u (%8x)", i, (int) m_mant[i], (int) m_mant[i] );
+ os << buf << ::std::endl;
+ }
+
+ os << "wp = " << m_wp << ::std::endl;
+ os << "sign = " << m_sign << ::std::endl;
+
+ os << "state = ";
+ switch( m_state )
+ {
+ case normal:
+ os << "normal";
+ break;
+ case infinity:
+ os << "infinity";
+ break;
+ case not_a_number:
+ os << "not_a_number";
+ break;
+ default:
+ os << "unknown";
+ }
+ os << ::std::endl;
+
+ os << "msw = " << m_msw << ::std::endl;
+ os << "lsw = " << m_lsw << ::std::endl;
+
+ os << ")" << ::std::endl;
+}
+
+
+// ----------------------------------------------------------------------------
+// METHOD : get_type
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::get_type( int& wl, int& iwl, sc_enc& enc ) const
+{
+ if( is_nan() || is_inf() )
+ {
+ wl = 0;
+ iwl = 0;
+ enc = SC_TC_;
+ return;
+ }
+
+ if( is_zero() )
+ {
+ wl = 1;
+ iwl = 1;
+ enc = SC_US_;
+ return;
+ }
+
+ int msb = ( m_msw - m_wp ) * bits_in_word
+ + scfx_find_msb( m_mant[ m_msw ] ) + 1;
+ while( get_bit( msb ) == get_bit( msb - 1 ) )
+ {
+ -- msb;
+ }
+
+ int lsb = ( m_lsw - m_wp ) * bits_in_word
+ + scfx_find_lsb( m_mant[ m_lsw ] );
+
+ if( is_neg() )
+ {
+ wl = msb - lsb + 1;
+ iwl = msb + 1;
+ enc = SC_TC_;
+ }
+ else
+ {
+ wl = msb - lsb;
+ iwl = msb;
+ enc = SC_US_;
+ }
+}
+
+
+// ----------------------------------------------------------------------------
+// PRIVATE METHOD : round
+//
+// Performs convergent rounding (rounding to even) as in floating-point.
+// ----------------------------------------------------------------------------
+
+void
+scfx_rep::round( int wl )
+{
+ // check for special cases
+
+ if( is_nan() || is_inf() || is_zero() )
+ return;
+
+ // estimate effective wordlength and compare
+
+ int wl_effective;
+
+ wl_effective = ( m_msw - m_lsw + 1 ) * bits_in_word;
+ if( wl_effective <= wl )
+ return;
+
+ // calculate effective wordlength and compare
+
+ int msb = scfx_find_msb( m_mant[m_msw] );
+ int lsb = scfx_find_lsb( m_mant[m_lsw] );
+
+ wl_effective = ( m_msw * bits_in_word + msb ) -
+ ( m_lsw * bits_in_word + lsb ) + 1;
+ if( wl_effective <= wl )
+ return;
+
+ // perform rounding
+
+ int wi = m_msw - ( wl - 1 ) / bits_in_word;
+ int bi = msb - ( wl - 1 ) % bits_in_word;
+ if( bi < 0 )
+ {
+ -- wi;
+ bi += bits_in_word;
+ }
+
+ scfx_index x( wi, bi );
+
+ if( (q_bit( x ) && ! q_zero( x )) ||
+ (q_bit( x ) && q_zero( x ) && q_odd( x )) )
+ q_incr( x );
+ q_clear( x );
+
+ find_sw();
+
+ m_r_flag = true;
+}
+
+} // namespace sc_dt
+
+
+// Taf!