added: Int::DivInt(int divisor, int * remainder)

changed: added specializations to Big::ToString() when the base is equal 4, 8 or 16
         the previous version was not accurate on some last digits (after the comma operator)
         consider this binary value (32 bit mantissa):
         base 2: 1.1111 1111 1111 1111 1111 1111 1110 101
         previous ToString() gave:
            base 4:  1.33333333333332
            base 8:  1.777777777
            base 16: 1.FFFFFF
         now we have:
            base 4:  1.3333333333333222
            base 8:  1.77777777724
            base 16: 1.FFFFFFEA



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@238 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2009-11-09 17:42:10 +00:00
parent 4b4b30392a
commit 0d1a57bdb4
3 changed files with 214 additions and 4 deletions

View File

@ -1,4 +1,4 @@
Version 0.9.0 prerelease (2009.11.01):
Version 0.9.0 prerelease (2009.11.09):
* added: support for wide characters (wchar_t, std::wstring)
* added: Big::IsInteger()
returns true if the value is integer (without fraction)
@ -47,6 +47,7 @@ Version 0.9.0 prerelease (2009.11.01):
* added: UInt::Sqrt() - a new algorithm for calculating the square root
* added: to the parser: function frac() - returns a value without the integer part
(only fraction remains)
* added: Int::DivInt(int divisor, int * remainder)
* changed: Factorial() is using the Gamma() function now
* changed: Big::Div(ss2)
Big::Mod(ss2)
@ -55,6 +56,18 @@ Version 0.9.0 prerelease (2009.11.01):
* changed: algorithms in Big::Sqrt() and ttmath::Root(x ; n)
they were not too much accurate for some integers
e.g. Root(16;4) returned a value very closed to 2 (not exactly 2)
* changed: added specializations to Big::ToString() when the base is equal 4, 8 or 16
the previous version was not accurate on some last digits (after the comma operator)
consider this binary value (32 bit mantissa):
base 2: 1.1111 1111 1111 1111 1111 1111 1110 101
previous ToString() gave:
base 4: 1.33333333333332
base 8: 1.777777777
base 16: 1.FFFFFF
now we have:
base 4: 1.3333333333333222
base 8: 1.77777777724
base 16: 1.FFFFFFEA
* removed: Parser<>::SetFactorialMax() method
the factorial() is such a fast now that we don't need the method longer
* removed: ErrorCode::err_too_big_factorial

View File

@ -3119,6 +3119,19 @@ private:
if( conv.base == 2 )
return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp);
// the speciality for base equal 4
if( conv.base == 4 )
return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 2);
// the speciality for base equal 8
if( conv.base == 8 )
return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 3);
// the speciality for base equal 16
if( conv.base == 16 )
return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 4);
// this = mantissa * 2^exponent
// temp = +1 * 2^exponent
@ -3348,9 +3361,6 @@ private:
we use it because if base is equal 2 we don't have to make those
complicated calculations and the output is directly from the source
(there will not be any small distortions)
(we can make that speciality when the base is 4,8 or 16 as well
but maybe in further time)
*/
template<class string_type>
uint ToString_CreateNewMantissaAndExponent_Base2( string_type & new_man,
@ -3377,6 +3387,135 @@ private:
}
/*!
a special method used to calculate the new mantissa and exponent
when the 'base' is equal 4, 8 or 16
when base is 4 then bits is 2
when base is 8 then bits is 3
when base is 16 then bits is 4
(and the algorithm can be used with a base greater than 16)
*/
template<class string_type>
uint ToString_CreateNewMantissaAndExponent_BasePow2( string_type & new_man,
Int<exp+1> & new_exp,
uint bits) const
{
int move; // how many times move the mantissa
UInt<man+1> man_temp(mantissa); // man+1 for moving
new_exp = exponent;
new_exp.DivInt((int)bits, move);
if( move != 0 )
{
// we're moving the man_temp to left-hand side
if( move < 0 )
{
move = bits + move;
new_exp.SubOne(); // when move is < than 0 then new_exp is < 0 too
}
man_temp.Rcl(move);
}
if( bits == 3 )
{
// base 8
// now 'move' is greater than or equal 0
uint len = man*TTMATH_BITS_PER_UINT + move;
return ToString_CreateNewMantissaAndExponent_Base8(new_man, man_temp, len, bits);
}
else
{
// base 4 or 16
return ToString_CreateNewMantissaAndExponent_Base4or16(new_man, man_temp, bits);
}
}
/*!
a special method used to calculate the new mantissa
when the 'base' is equal 8
bits is always 3
we can use this algorithm when the base is 4 or 16 too
but we have a faster method ToString_CreateNewMantissaAndExponent_Base4or16()
*/
template<class string_type>
uint ToString_CreateNewMantissaAndExponent_Base8( string_type & new_man,
UInt<man+1> & man_temp,
uint len,
uint bits) const
{
uint shift = TTMATH_BITS_PER_UINT - bits;
uint mask = TTMATH_UINT_MAX_VALUE >> shift;
uint i;
for( i=0 ; i<len ; i+=bits )
{
uint digit = man_temp.table[0] & mask;
new_man.insert(new_man.begin(), static_cast<char>(Misc::DigitToChar(digit)));
man_temp.Rcr(bits);
}
TTMATH_ASSERT( man_temp.IsZero() )
return 0;
}
/*!
a special method used to calculate the new mantissa
when the 'base' is equal 4 or 16
when the base is equal 4 or 16 the bits is 2 or 4
and because TTMATH_BITS_PER_UINT (32 or 64) is divisible by 2 (or 4)
then we can get digits from the end of our mantissa
*/
template<class string_type>
uint ToString_CreateNewMantissaAndExponent_Base4or16( string_type & new_man,
UInt<man+1> & man_temp,
uint bits) const
{
TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 2 == 0 )
TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 4 == 0 )
uint shift = TTMATH_BITS_PER_UINT - bits;
uint mask = TTMATH_UINT_MAX_VALUE << shift;
uint digit;
// table[man] - last word - is different from zero if we moved man_temp
digit = man_temp.table[man];
if( digit != 0 )
new_man += static_cast<char>(Misc::DigitToChar(digit));
for( int i=man-1 ; i>=0 ; --i )
{
uint shift_local = shift;
uint mask_local = mask;
while( mask_local != 0 )
{
digit = man_temp.table[i] & mask_local;
if( shift_local != 0 )
digit = digit >> shift_local;
new_man += static_cast<char>(Misc::DigitToChar(digit));
mask_local = mask_local >> bits;
shift_local = shift_local - bits;
}
}
return 0;
}
/*!
an auxiliary method for converting into the string

View File

@ -468,6 +468,64 @@ public:
}
/*!
division this = this / ss2 (ss2 is int)
returned values:
0 - ok
1 - division by zero
for example: (result means 'this')
20 / 3 --> result: 6 remainder: 2
-20 / 3 --> result: -6 remainder: -2
20 / -3 --> result: -6 remainder: 2
-20 / -3 --> result: 6 remainder: -2
in other words: this(old) = ss2 * this(new)(result) + remainder
*/
uint DivInt(int ss2, int * remainder = 0)
{
bool ss1_is_sign, ss2_is_sign;
ss1_is_sign = IsSign();
/*
we don't have to test the carry from Abs as well as in Mul
*/
Abs();
if( ss2 < 0 )
{
ss2 = -ss2;
ss2_is_sign = true;
}
else
{
ss2_is_sign = false;
}
uint rem;
uint c = UInt<value_size>::DivInt((uint)ss2, &rem);
if( ss1_is_sign != ss2_is_sign )
SetSign();
if( remainder )
{
if( ss1_is_sign )
*remainder = -int(rem);
else
*remainder = int(rem);
}
return c;
}
uint DivInt(int ss2, int & remainder)
{
return DivInt(ss2, &remainder);
}
private: