fixed: base rounding in Big::ToString

if the result were integer we shoud not round the value
          3.0001 should be 3.0001 and
          2.9999 should be 2.9999



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@259 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2009-12-06 23:18:05 +00:00
parent 357524ae13
commit e5fc7a52e8
1 changed files with 100 additions and 29 deletions

View File

@ -807,6 +807,10 @@ public:
if( is_exact_half ) if( is_exact_half )
c += RoundHalfToEven(is_exact_half); c += RoundHalfToEven(is_exact_half);
} }
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// rounding
// we have to test bits from ss2 too
} }
else else
{ {
@ -3707,6 +3711,7 @@ private:
// exponents should be less than zero // exponents should be less than zero
// if new_exp are greater than or equal to zero then the value is integer // if new_exp are greater than or equal to zero then the value is integer
// (but the integer can be too if the exponents are less than zero - we check it later)
if( !new_exp.IsSign() || !exponent.IsSign() ) if( !new_exp.IsSign() || !exponent.IsSign() )
return 0; return 0;
@ -3731,8 +3736,9 @@ private:
template<class string_type, class char_type> template<class string_type, class char_type>
uint ToString_BaseRoundDelInvalidAndRound(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp, uint zeroes) const uint ToString_BaseRoundDelInvalidAndRound(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp, uint zeroes) const
{ {
uint len, valid_bits, del; uint c, len, valid_bits, del;
c = 0;
del = 0; del = 0;
// how many bits there are in the mantissa // how many bits there are in the mantissa
@ -3748,23 +3754,22 @@ private:
valid_bits = len - zeroes; valid_bits = len - zeroes;
if( valid_bits == 0 ) if( valid_bits == 0 )
// oops, this is an integer value (the value was not Standardized) // this is an integer value
return 0; return 0;
// the rest digits (in conv.base radix) will be cut off from new_man // the rest digits (in conv.base radix) will be cut off from new_man
// but at least two characters must be left // but at least two characters must be left
del = ToString_BaseRoundDelInvalid<string_type, char_type>(new_man, conv.base, new_exp, valid_bits); del = ToString_BaseRoundDelInvalid<string_type, char_type>(new_man, conv.base, new_exp, valid_bits);
if( del>0 && conv.trim_zeroes )
c += new_exp.Add(del);
// rounding from the last digit (the last digit will be deleted) // rounding from the last digit (the last digit will be deleted)
uint c = ToString_RoundMantissa<string_type, char_type>(new_man, conv, new_exp); c += ToString_RoundMantissa<string_type, char_type>(new_man, conv, new_exp);
if( del > 0 ) if( del>0 && !conv.trim_zeroes )
{ // we must add the zeroes after ToString_RoundMantissa()
if( conv.trim_zeroes ) new_man.append(del, '0');
c += new_exp.Add(del);
else
new_man.append(del, '0');
}
return c; return c;
} }
@ -3781,30 +3786,38 @@ private:
Int<exp+1> & new_exp, Int<exp+1> & new_exp,
uint valid_bits) const uint valid_bits) const
{ {
uint del, del_max, new_exp_abs, valid_digits; uint del, del_max, valid_digits;
del = 0;
// calculating how many valid digits there are after the comma operator // calculating how many valid digits there are after the comma operator
// (in new_man where the radix is conv.base) // (in new_man where the radix is conv.base)
sint v = sint(double(valid_bits) / ToString_LogBase2(radix) - 2.0); sint v = sint(double(valid_bits) / ToString_LogBase2(radix) + 0.5);
// even if v is less than 1 we want at least one digit after comma
// (valid_bits is greater than zero)
valid_digits = uint( (v<=1)? 1 : v ); // minimum 1 valid_digits = uint( (v<=1)? 1 : v ); // minimum 1
del = 0;
if( new_man.size() >= TTMATH_UINT_HIGHEST_BIT ) if( valid_digits > new_man.size() )
// oops, new_man.size() is too big for calculating valid_digits = new_man.size();
return del;
if( new_man.size() < 3 ) if( new_man.size() < 3 )
// it must be at least three characters in the new_man // it must be at least three characters in the new_man
return del; return del;
if( new_exp <= -sint(TTMATH_UINT_HIGHEST_BIT) ) Int<exp+1> new_exp_abs(new_exp);
// oops, new_exp is too big for calculating new_exp_abs.Abs();
return del;
new_exp_abs = uint(-new_exp.ToInt()); // new_exp is also less than zero if( new_exp_abs > new_man.size() )
new_exp_abs = new_man.size();
if( new_exp_abs > valid_digits ) if( new_exp_abs > valid_digits )
del = new_exp_abs - valid_digits; {
new_exp_abs.Sub(valid_digits);
del = new_exp_abs.ToUInt();
}
// because valid_digits is >= 1 then del is less than new_exp_abs
// and after deleting the result will not be an integer
// miminum two characters should be left in new_man // miminum two characters should be left in new_man
// also new_man.size() is > 2 // also new_man.size() is > 2
@ -3820,6 +3833,41 @@ private:
} }
/*!
an auxiliary method for converting into the string
*/
template<class string_type, class char_type>
bool ToString_RoundMantissaWouldBeInteger(string_type & new_man, Int<exp+1> & new_exp) const
{
// if new_exp is equal -1 then we have only one digit after the comma
// and after rounding it would be an integer value
// (we don't want to be integer after rounding)
if( new_exp == -1 )
return true;
if( new_man.size() > TTMATH_UINT_HIGHEST_BIT )
// oops, the mantissa is too large for calculating
return false;
uint i = 0;
if( new_exp > -sint(new_man.size()) )
{
uint new_exp_abs = -new_exp.ToInt();
i = new_man.size() - new_exp_abs;
}
// at least one digit after the comma operator should be different from zero
// but without checking the last digit (the last digit will be deleted later)
for( ; i<new_man.size()-1 ; ++i) // new_man.size() is >= 2
if( new_man[i] != '0' )
// it will not be integer
return false;
return true;
}
/*! /*!
an auxiliary method for converting into the string an auxiliary method for converting into the string
@ -3832,6 +3880,9 @@ private:
if( new_man.size() < 2 ) if( new_man.size() < 2 )
return 0; return 0;
if( ToString_RoundMantissaWouldBeInteger<string_type, char_type>(new_man, new_exp) )
return 0;
typename string_type::size_type i = new_man.length() - 1; typename string_type::size_type i = new_man.length() - 1;
// we're erasing the last character // we're erasing the last character
@ -3842,7 +3893,17 @@ private:
// if the last character is greater or equal 'base/2' // if the last character is greater or equal 'base/2'
// we'll add one into the new mantissa // we'll add one into the new mantissa
if( digit >= conv.base / 2 ) if( digit >= conv.base / 2 )
ToString_RoundMantissa_AddOneIntoMantissa<string_type, char_type>(new_man, conv); {
uint how_many = ToString_RoundMantissa_AddOneIntoMantissa<string_type, char_type>(new_man, conv, false);
if( new_exp <= -(int)how_many ) // it means: abs(new_exp) >= how_many
{
// we have to round only digits after the comma operator
// if how_many were greater than abs(new_exp) then
// the result would be integer (we don't want it to be integer)
ToString_RoundMantissa_AddOneIntoMantissa<string_type, char_type>(new_man, conv);
}
}
return carry; return carry;
} }
@ -3852,15 +3913,17 @@ private:
an auxiliary method for converting into the string an auxiliary method for converting into the string
this method addes one into the new mantissa this method addes one into the new mantissa
returns how many digits were affected
*/ */
template<class string_type, class char_type> template<class string_type, class char_type>
void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv) const uint ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv, bool change_mantissa = true) const
{ {
if( new_man.empty() ) if( new_man.empty() )
return; return 0;
sint i = sint( new_man.length() ) - 1; sint i = sint( new_man.length() ) - 1;
bool was_carry = true; bool was_carry = true;
uint how_many = 0;
for( ; i>=0 && was_carry ; --i ) for( ; i>=0 && was_carry ; --i )
{ {
@ -3878,11 +3941,21 @@ private:
else else
was_carry = false; was_carry = false;
new_man[i] = static_cast<char_type>( Misc::DigitToChar(digit) ); if( change_mantissa )
new_man[i] = static_cast<char_type>( Misc::DigitToChar(digit) );
how_many += 1;
} }
if( i<0 && was_carry ) if( i<0 && was_carry )
new_man.insert( new_man.begin() , '1' ); {
if( change_mantissa )
new_man.insert( new_man.begin() , '1' );
how_many += 1;
}
return how_many;
} }
@ -5117,9 +5190,7 @@ public:
return CheckCarry(c); return CheckCarry(c);
} }
/*! /*!
* *