removed: from Big::ToString() the feature with calculating how many valid digits there are
after the comma operator this was not correctly calculated - sometimes gives unexpected results, e.g. 0.5/2/2=0.125 (only one bit in the mantissa) gives 0.1 as the result changed: cosmetic changes in Big::Add() git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@283 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
32b8c7a957
commit
d5a5ea1a7d
23
CHANGELOG
23
CHANGELOG
|
@ -1,4 +1,4 @@
|
||||||
Version 0.9.1 prerelease (2009.12.28):
|
Version 0.9.1 prerelease (2010.02.02):
|
||||||
* fixed: the parser didn't use characters for changing the base (# and &)
|
* fixed: the parser didn't use characters for changing the base (# and &)
|
||||||
those characters were skipped
|
those characters were skipped
|
||||||
(this bug was introduced in 0.9.0)
|
(this bug was introduced in 0.9.0)
|
||||||
|
@ -14,26 +14,11 @@ Version 0.9.1 prerelease (2009.12.28):
|
||||||
Consider this binary value (32 bit mantissa):
|
Consider this binary value (32 bit mantissa):
|
||||||
(bin)1.0000000000000000000000000000011
|
(bin)1.0000000000000000000000000000011
|
||||||
previously ToString() gave 1, now we have: 1.000000001
|
previously ToString() gave 1, now we have: 1.000000001
|
||||||
|
* changed: in Big::ToString() the base rounding is made only if the result value
|
||||||
|
would not be an integer, e.g. if the value is 1.999999999999 then
|
||||||
|
the base rounding will not be done - because as the result would be 2
|
||||||
* added: IEEE 754 half-to-even rounding (bankers' rounding) to the following
|
* added: IEEE 754 half-to-even rounding (bankers' rounding) to the following
|
||||||
floating point algorithms: Big::Add, Big::Sub, Big::Mul, Big::Div
|
floating point algorithms: Big::Add, Big::Sub, Big::Mul, Big::Div
|
||||||
* added: to Big::ToString() - additional rounding when conv.base_round is used
|
|
||||||
if the value is not an integer we calculate how many valid digits there are
|
|
||||||
after the comma operator (in conv.base radix) and then we skipped the rest
|
|
||||||
digits, after skipping the base-rounding is made
|
|
||||||
this helps to print values which have some last clear bits in the mantissa
|
|
||||||
consider this 32 bit value:
|
|
||||||
(binary)0.00011100001010001111010111000000000
|
|
||||||
which has mantissa equal: (binary)11100001010001111010111000000000 (32 bits)
|
|
||||||
previous the ToString() method gave: (decimal)0.10999999[...]
|
|
||||||
now we have: (decimal)0.11
|
|
||||||
* added: Parser::SetSmallToZero(bool zero) (default true)
|
|
||||||
if true then the parser changes small values into zero
|
|
||||||
small value means:
|
|
||||||
- if the mantissa of the value consists only of one, two or three set bits
|
|
||||||
- and these bits are next to each other
|
|
||||||
- and the exponent is smaller than about 2 times the number of bits from the mantissa
|
|
||||||
this helps to correctly calculate expressions such as: "0.80-3*0.34+0.22"
|
|
||||||
now the parser gives zero (previous there was a value very closed to zero)
|
|
||||||
* added: static sint UInt<value_size>::FindLowestBitInWord(uint x)
|
* added: static sint UInt<value_size>::FindLowestBitInWord(uint x)
|
||||||
this method is looking for the lowest set bit in a word
|
this method is looking for the lowest set bit in a word
|
||||||
* added: UInt::FindLowestBit(uint & table_id, uint & index)
|
* added: UInt::FindLowestBit(uint & table_id, uint & index)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Copyright (c) 2006-2009, Tomasz Sowa
|
Copyright (c) 2006-2010, Tomasz Sowa
|
||||||
All rights reserved.
|
All rights reserved.
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
|
|
@ -2807,7 +2807,7 @@ namespace ttmath
|
||||||
}
|
}
|
||||||
|
|
||||||
// the simplest way to initialize is to call the Gamma function with (TTMATH_GAMMA_BOUNDARY + 1)
|
// the simplest way to initialize is to call the Gamma function with (TTMATH_GAMMA_BOUNDARY + 1)
|
||||||
// when x is larger then less coefficients we need
|
// when x is larger then fewer coefficients we need
|
||||||
Gamma(x, *this);
|
Gamma(x, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2009, Tomasz Sowa
|
* Copyright (c) 2006-2010, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -729,7 +729,7 @@ private:
|
||||||
uint RoundHalfToEven(bool is_half, bool rounding_up = true)
|
uint RoundHalfToEven(bool is_half, bool rounding_up = true)
|
||||||
{
|
{
|
||||||
uint c = 0;
|
uint c = 0;
|
||||||
|
return 0;
|
||||||
if( !is_half || mantissa.IsTheLowestBitSet() )
|
if( !is_half || mantissa.IsTheLowestBitSet() )
|
||||||
{
|
{
|
||||||
if( rounding_up )
|
if( rounding_up )
|
||||||
|
@ -742,12 +742,14 @@ private:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
uint c_from_zero = mantissa.SubOne();
|
#ifdef TTMATH_DEBUG
|
||||||
|
uint c_from_zero =
|
||||||
|
#endif
|
||||||
|
mantissa.SubOne();
|
||||||
|
|
||||||
// we're using rounding_up=false in Add() when the mantissas
|
// we're using rounding_up=false in Add() when the mantissas have different signs
|
||||||
// have different signs, but we have guarantee then the result
|
// mantissa can be zero only when previous mantissa was equal to ss2.mantissa
|
||||||
// will be greater than or equal to zero
|
// but in such a case 'last_bit_set' will not be set and consequently 'do_rounding' will be false
|
||||||
// (if it is zero then we should not do the rounding here)
|
|
||||||
TTMATH_ASSERT( c_from_zero == 0 )
|
TTMATH_ASSERT( c_from_zero == 0 )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -756,7 +758,8 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
*
|
*
|
||||||
|
@ -789,6 +792,7 @@ private:
|
||||||
if( exp_offset < mantissa_size_in_bits )
|
if( exp_offset < mantissa_size_in_bits )
|
||||||
{
|
{
|
||||||
uint moved = exp_offset.ToInt(); // how many times we must move ss2.mantissa
|
uint moved = exp_offset.ToInt(); // how many times we must move ss2.mantissa
|
||||||
|
rest_zero = true;
|
||||||
|
|
||||||
if( moved > 0 )
|
if( moved > 0 )
|
||||||
{
|
{
|
||||||
|
@ -816,7 +820,6 @@ private:
|
||||||
uint AddMantissas( Big<exp, man> & ss2,
|
uint AddMantissas( Big<exp, man> & ss2,
|
||||||
bool & last_bit_set,
|
bool & last_bit_set,
|
||||||
bool & rest_zero,
|
bool & rest_zero,
|
||||||
bool & do_rounding,
|
|
||||||
bool & rounding_up)
|
bool & rounding_up)
|
||||||
{
|
{
|
||||||
uint c = 0;
|
uint c = 0;
|
||||||
|
@ -826,16 +829,14 @@ private:
|
||||||
// values have the same signs
|
// values have the same signs
|
||||||
if( mantissa.Add(ss2.mantissa) )
|
if( mantissa.Add(ss2.mantissa) )
|
||||||
{
|
{
|
||||||
// we have one bit more from addition (carry was)
|
// we have one bit more from addition (carry)
|
||||||
// now rest_zero means the old rest_zero with the old last_bit_set
|
// now rest_zero means the old rest_zero with the old last_bit_set
|
||||||
// we check only the situation when rest_zero was true
|
rest_zero = (!last_bit_set && rest_zero);
|
||||||
// (if it was false then it is false now too)
|
|
||||||
if( rest_zero && last_bit_set )
|
|
||||||
rest_zero = false;
|
|
||||||
|
|
||||||
last_bit_set = mantissa.Rcr(1,1);
|
last_bit_set = mantissa.Rcr(1,1);
|
||||||
c += exponent.AddOne();
|
c += exponent.AddOne();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rounding_up = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -845,18 +846,13 @@ private:
|
||||||
// is greater than or equal to the mantissa of the ss2
|
// is greater than or equal to the mantissa of the ss2
|
||||||
|
|
||||||
#ifdef TTMATH_DEBUG
|
#ifdef TTMATH_DEBUG
|
||||||
// this is to get rid of a warning saying that c_temp is not used
|
uint c_temp =
|
||||||
uint c_temp = /* mantissa.Sub(ss2.mantissa); */
|
|
||||||
#endif
|
#endif
|
||||||
mantissa.Sub(ss2.mantissa);
|
mantissa.Sub(ss2.mantissa);
|
||||||
|
|
||||||
TTMATH_ASSERT( c_temp == 0 )
|
TTMATH_ASSERT( c_temp == 0 )
|
||||||
|
|
||||||
rounding_up = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do_rounding = true;
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,49 +867,49 @@ public:
|
||||||
*/
|
*/
|
||||||
uint Add(Big<exp, man> ss2, bool round = true)
|
uint Add(Big<exp, man> ss2, bool round = true)
|
||||||
{
|
{
|
||||||
|
bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up;
|
||||||
Int<exp> exp_offset( exponent );
|
Int<exp> exp_offset( exponent );
|
||||||
|
|
||||||
uint c = 0;
|
uint c = 0;
|
||||||
|
|
||||||
if( IsNan() || ss2.IsNan() )
|
if( IsNan() || ss2.IsNan() )
|
||||||
return CheckCarry(1);
|
return CheckCarry(1);
|
||||||
|
|
||||||
if( ss2.IsZero() )
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
exp_offset.Sub( ss2.exponent );
|
exp_offset.Sub( ss2.exponent );
|
||||||
exp_offset.Abs();
|
exp_offset.Abs();
|
||||||
|
|
||||||
// (1) abs(this) will be >= abs(ss2)
|
// (1) abs(this) will be >= abs(ss2)
|
||||||
if( SmallerWithoutSignThan(ss2) )
|
if( SmallerWithoutSignThan(ss2) )
|
||||||
{
|
{
|
||||||
|
// !! use Swap here (not implemented yet)
|
||||||
Big<exp, man> temp(ss2);
|
Big<exp, man> temp(ss2);
|
||||||
|
|
||||||
ss2 = *this;
|
ss2 = *this;
|
||||||
*this = temp;
|
*this = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool last_bit_set = false;
|
if( ss2.IsZero() )
|
||||||
bool rest_zero = true;
|
return 0;
|
||||||
bool do_adding = false;
|
|
||||||
bool do_rounding = false;
|
|
||||||
bool rounding_up = true;
|
|
||||||
|
|
||||||
|
last_bit_set = rest_zero = do_adding = do_rounding = rounding_up = false;
|
||||||
AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding);
|
AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding);
|
||||||
|
|
||||||
if( do_adding )
|
if( do_adding )
|
||||||
c += AddMantissas(ss2, last_bit_set, rest_zero, do_rounding, rounding_up);
|
c += AddMantissas(ss2, last_bit_set, rest_zero, rounding_up);
|
||||||
|
|
||||||
if( round && do_rounding && last_bit_set )
|
if( !round || !last_bit_set )
|
||||||
|
do_rounding = false;
|
||||||
|
|
||||||
|
if( do_rounding )
|
||||||
c += RoundHalfToEven(rest_zero, rounding_up);
|
c += RoundHalfToEven(rest_zero, rounding_up);
|
||||||
|
|
||||||
if( do_adding || (do_rounding && last_bit_set) )
|
if( do_adding || do_rounding )
|
||||||
c += Standardizing();
|
c += Standardizing();
|
||||||
|
|
||||||
return CheckCarry(c);
|
return CheckCarry(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Subtraction this = this - ss2
|
Subtraction this = this - ss2
|
||||||
|
|
||||||
|
@ -3359,6 +3355,11 @@ private:
|
||||||
Big<exp+1,man> new_exp_;
|
Big<exp+1,man> new_exp_;
|
||||||
c += new_exp_.ToString_Log(temp, conv.base); // this logarithm isn't very complicated
|
c += new_exp_.ToString_Log(temp, conv.base); // this logarithm isn't very complicated
|
||||||
|
|
||||||
|
// adding some epsilon value (to get rid of some floating point errors)
|
||||||
|
temp.Set05();
|
||||||
|
temp.exponent.SubOne(); // temp = 0.5/2 = 0.25
|
||||||
|
c += new_exp_.Add(temp);
|
||||||
|
|
||||||
if( !new_exp_.IsSign() && !new_exp_.IsInteger() )
|
if( !new_exp_.IsSign() && !new_exp_.IsInteger() )
|
||||||
{
|
{
|
||||||
// new_exp_ > 0 and with fraction
|
// new_exp_ > 0 and with fraction
|
||||||
|
@ -3402,10 +3403,6 @@ private:
|
||||||
// maximum valid bits
|
// maximum valid bits
|
||||||
temp.mantissa.ToString(new_man, conv.base);
|
temp.mantissa.ToString(new_man, conv.base);
|
||||||
|
|
||||||
// because we had used a bigger type for calculating I think we
|
|
||||||
// shouldn't have had a carry
|
|
||||||
// (in the future this can be changed)
|
|
||||||
|
|
||||||
// base rounding
|
// base rounding
|
||||||
if( conv.base_round )
|
if( conv.base_round )
|
||||||
c += ToString_BaseRound<string_type, char_type>(new_man, conv, new_exp);
|
c += ToString_BaseRound<string_type, char_type>(new_man, conv, new_exp);
|
||||||
|
@ -3743,34 +3740,50 @@ private:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
an auxiliary method for converting into the string
|
an auxiliary method for converting into the string
|
||||||
|
|
||||||
returns log(n, 2) (logarithm with the base equal 2)
|
|
||||||
n is in the range of [2,16]
|
|
||||||
*/
|
*/
|
||||||
double ToString_LogBase2(uint n) const
|
template<class string_type, class char_type>
|
||||||
|
bool ToString_RoundMantissaWouldBeInteger(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp) const
|
||||||
{
|
{
|
||||||
static double log_tab[] = {
|
// if new_exp is greater or equal to zero then we have an integer value,
|
||||||
1.0000000000000000,
|
// if new_exp is equal -1 then we have only one digit after the comma
|
||||||
1.5849625007211562,
|
// and after rounding it would be an integer value
|
||||||
2.0000000000000000,
|
if( !new_exp.IsSign() || new_exp == -1 )
|
||||||
2.3219280948873623,
|
return true;
|
||||||
2.5849625007211562,
|
|
||||||
2.8073549220576041,
|
|
||||||
3.0000000000000000,
|
|
||||||
3.1699250014423124,
|
|
||||||
3.3219280948873623,
|
|
||||||
3.4594316186372973,
|
|
||||||
3.5849625007211562,
|
|
||||||
3.7004397181410922,
|
|
||||||
3.8073549220576041,
|
|
||||||
3.9068905956085185,
|
|
||||||
4.0000000000000000
|
|
||||||
};
|
|
||||||
|
|
||||||
if( n < 2 || n > 16 )
|
if( new_man.size() >= TTMATH_UINT_HIGHEST_BIT || new_man.size() < 2 )
|
||||||
return 1.0;
|
return true; // oops, the mantissa is too large for calculating (or too small) - we are not doing the base rounding
|
||||||
|
|
||||||
return log_tab[n-2];
|
uint i = 0;
|
||||||
|
char_type digit;
|
||||||
|
|
||||||
|
if( new_exp >= -sint(new_man.size()) )
|
||||||
|
{
|
||||||
|
uint new_exp_abs = -new_exp.ToInt();
|
||||||
|
i = new_man.size() - new_exp_abs; // start from the first digit after the comma operator
|
||||||
|
}
|
||||||
|
|
||||||
|
if( Misc::CharToDigit(new_man[new_man.size()-1]) >= conv.base/2 )
|
||||||
|
{
|
||||||
|
if( new_exp < -sint(new_man.size()) )
|
||||||
|
{
|
||||||
|
// there are some zeroes after the comma operator
|
||||||
|
// (between the comma and the first digit from the mantissa)
|
||||||
|
// and the result value will never be an integer
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
digit = static_cast<char_type>( Misc::DigitToChar(conv.base-1) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
digit = '0';
|
||||||
|
}
|
||||||
|
|
||||||
|
for( ; i < new_man.size()-1 ; ++i)
|
||||||
|
if( new_man[i] != digit )
|
||||||
|
return false; // it will not be an integer
|
||||||
|
|
||||||
|
return true; // it will be integer after rounding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3779,235 +3792,47 @@ private:
|
||||||
|
|
||||||
this method is used for base!=2, base!=4, base!=8 and base!=16
|
this method is used for base!=2, base!=4, base!=8 and base!=16
|
||||||
we do the rounding when the value has fraction (is not an integer)
|
we do the rounding when the value has fraction (is not an integer)
|
||||||
|
|
||||||
if the value is not an integer we calculate how many valid digits there are
|
|
||||||
after the comma operator (in conv.base radix) and then we skipped the rest
|
|
||||||
digits, after skipping the base-rounding is made
|
|
||||||
*/
|
*/
|
||||||
template<class string_type, class char_type>
|
template<class string_type, class char_type>
|
||||||
uint ToString_BaseRound(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp) const
|
uint ToString_BaseRound(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp) const
|
||||||
{
|
{
|
||||||
uint table_id, bit_index, zeroes;
|
// we must have minimum two characters
|
||||||
|
|
||||||
// at least two digits
|
|
||||||
if( new_man.size() < 2 )
|
if( new_man.size() < 2 )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// exponents should be less than zero
|
// assert that there will not be an integer after rounding
|
||||||
// if new_exp are greater than or equal to zero then the value is integer
|
if( ToString_RoundMantissaWouldBeInteger<string_type, char_type>(new_man, conv, new_exp) )
|
||||||
// (but the integer can be too if the exponents are less than zero - we check it later)
|
|
||||||
if( !new_exp.IsSign() || !exponent.IsSign() )
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if( !mantissa.FindLowestBit(table_id, bit_index) )
|
typename string_type::size_type i = new_man.length() - 1;
|
||||||
// mantissa is zero, it should not be zero here
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// how many zero bits there are at the end of the mantissa
|
// we're erasing the last character
|
||||||
zeroes = table_id * TTMATH_BITS_PER_UINT + bit_index;
|
uint digit = Misc::CharToDigit( new_man[i] );
|
||||||
|
new_man.erase(i, 1);
|
||||||
|
uint c = new_exp.AddOne();
|
||||||
|
|
||||||
return ToString_BaseRoundDelInvalidAndRound<string_type, char_type>(new_man, conv, new_exp, zeroes);
|
// if the last character is greater or equal 'base/2'
|
||||||
}
|
// we are adding one into the new mantissa
|
||||||
|
if( digit >= conv.base / 2 )
|
||||||
|
ToString_RoundMantissa_AddOneIntoMantissa<string_type, char_type>(new_man, conv);
|
||||||
|
|
||||||
/*!
|
|
||||||
an auxiliary method for converting into the string
|
|
||||||
|
|
||||||
this method is used for base!=2, base!=4, base!=8 and base!=16
|
|
||||||
we do the rounding when the value has fraction (is not an integer)
|
|
||||||
*/
|
|
||||||
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 c, len, valid_bits, del;
|
|
||||||
|
|
||||||
c = 0;
|
|
||||||
del = 0;
|
|
||||||
|
|
||||||
// how many bits there are in the mantissa
|
|
||||||
len = man * TTMATH_BITS_PER_UINT;
|
|
||||||
|
|
||||||
if( exponent > -sint(len) )
|
|
||||||
// but bits only after the comma operator
|
|
||||||
len = uint(-exponent.ToInt()); // exponent is also less than zero
|
|
||||||
|
|
||||||
valid_bits = 0;
|
|
||||||
|
|
||||||
if( len > zeroes )
|
|
||||||
valid_bits = len - zeroes;
|
|
||||||
|
|
||||||
if( valid_bits == 0 )
|
|
||||||
// this is an integer value
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// the rest digits (in conv.base radix) will be cut off from new_man
|
|
||||||
// but at least two characters must be left
|
|
||||||
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)
|
|
||||||
c += ToString_RoundMantissa<string_type, char_type>(new_man, conv, new_exp);
|
|
||||||
|
|
||||||
if( del>0 && !conv.trim_zeroes )
|
|
||||||
// we must add the zeroes after ToString_RoundMantissa()
|
|
||||||
new_man.append(del, '0');
|
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
an auxiliary method for converting into the string
|
|
||||||
|
|
||||||
returning how many digits were deleted
|
|
||||||
*/
|
|
||||||
template<class string_type, class char_type>
|
|
||||||
uint ToString_BaseRoundDelInvalid( string_type & new_man,
|
|
||||||
uint radix,
|
|
||||||
Int<exp+1> & new_exp,
|
|
||||||
uint valid_bits) const
|
|
||||||
{
|
|
||||||
uint del, del_max, valid_digits;
|
|
||||||
|
|
||||||
del = 0;
|
|
||||||
|
|
||||||
// calculating how many valid digits there are after the comma operator
|
|
||||||
// (in new_man where the radix is conv.base)
|
|
||||||
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
|
|
||||||
|
|
||||||
if( valid_digits > new_man.size() )
|
|
||||||
valid_digits = new_man.size();
|
|
||||||
|
|
||||||
if( new_man.size() < 3 )
|
|
||||||
// it must be at least three characters in the new_man
|
|
||||||
return del;
|
|
||||||
|
|
||||||
Int<exp+1> new_exp_abs(new_exp);
|
|
||||||
new_exp_abs.Abs();
|
|
||||||
|
|
||||||
if( new_exp_abs > new_man.size() )
|
|
||||||
new_exp_abs = new_man.size();
|
|
||||||
|
|
||||||
if( 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
|
|
||||||
// also new_man.size() is > 2
|
|
||||||
del_max = (new_man.size()==3)? 1 : new_man.size()-2;
|
|
||||||
|
|
||||||
if( del > del_max )
|
|
||||||
del = del_max;
|
|
||||||
|
|
||||||
if( del > 0 )
|
|
||||||
new_man.erase(new_man.size()-del); // deleting del characters at the end of new_man
|
|
||||||
|
|
||||||
return del;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
|
||||||
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
|
|
||||||
|
|
||||||
this method roundes the last character from the new mantissa
|
|
||||||
*/
|
|
||||||
template<class string_type, class char_type>
|
|
||||||
uint ToString_RoundMantissa(string_type & new_man, const Conv & conv, Int<exp+1> & new_exp) const
|
|
||||||
{
|
|
||||||
// we must have minimum two characters
|
|
||||||
if( new_man.size() < 2 )
|
|
||||||
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;
|
|
||||||
|
|
||||||
// we're erasing the last character
|
|
||||||
uint digit = Misc::CharToDigit( new_man[i] );
|
|
||||||
new_man.erase(i, 1);
|
|
||||||
uint carry = new_exp.AddOne();
|
|
||||||
|
|
||||||
// if the last character is greater or equal 'base/2'
|
|
||||||
// we'll add one into the new mantissa
|
|
||||||
if( digit >= conv.base / 2 )
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
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>
|
||||||
uint ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv, bool change_mantissa = true) const
|
void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv) const
|
||||||
{
|
{
|
||||||
if( new_man.empty() )
|
if( new_man.empty() )
|
||||||
return 0;
|
return;
|
||||||
|
|
||||||
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 )
|
||||||
{
|
{
|
||||||
|
@ -4025,21 +3850,11 @@ private:
|
||||||
else
|
else
|
||||||
was_carry = false;
|
was_carry = false;
|
||||||
|
|
||||||
if( change_mantissa )
|
|
||||||
new_man[i] = static_cast<char_type>( Misc::DigitToChar(digit) );
|
new_man[i] = static_cast<char_type>( Misc::DigitToChar(digit) );
|
||||||
|
|
||||||
how_many += 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if( i<0 && was_carry )
|
if( i<0 && was_carry )
|
||||||
{
|
|
||||||
if( change_mantissa )
|
|
||||||
new_man.insert( new_man.begin() , '1' );
|
new_man.insert( new_man.begin() , '1' );
|
||||||
|
|
||||||
how_many += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return how_many;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2009, Tomasz Sowa
|
* Copyright (c) 2006-2010, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -2731,7 +2731,7 @@ ErrorCode Parse(const std::wstring & str)
|
||||||
/*!
|
/*!
|
||||||
this method returns true is something was calculated
|
this method returns true is something was calculated
|
||||||
(at least one mathematical operator was used or a function or variable)
|
(at least one mathematical operator was used or a function or variable)
|
||||||
e.g. the string to Parse() looked like this:
|
e.g. true if the string to Parse() looked like this:
|
||||||
"1+1"
|
"1+1"
|
||||||
"2*3"
|
"2*3"
|
||||||
"sin(5)"
|
"sin(5)"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2006-2009, Tomasz Sowa
|
* Copyright (c) 2006-2010, Tomasz Sowa
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
|
Loading…
Reference in New Issue