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:
parent
357524ae13
commit
e5fc7a52e8
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in New Issue