From 0d1a57bdb4d6932d85001293d85bdf7d9ff284d2 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 9 Nov 2009 17:42:10 +0000 Subject: [PATCH] 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 --- CHANGELOG | 15 ++++- ttmath/ttmathbig.h | 145 ++++++++++++++++++++++++++++++++++++++++++++- ttmath/ttmathint.h | 58 ++++++++++++++++++ 3 files changed, 214 insertions(+), 4 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 0f6906b..d3bf84d 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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 diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index f2653f4..ff1ec91 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -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 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 + uint ToString_CreateNewMantissaAndExponent_BasePow2( string_type & new_man, + Int & new_exp, + uint bits) const + { + int move; // how many times move the mantissa + UInt 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 + uint ToString_CreateNewMantissaAndExponent_Base8( string_type & new_man, + UInt & 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(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 + uint ToString_CreateNewMantissaAndExponent_Base4or16( string_type & new_man, + UInt & 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(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(Misc::DigitToChar(digit)); + mask_local = mask_local >> bits; + shift_local = shift_local - bits; + } + } + + return 0; + } + + /*! an auxiliary method for converting into the string diff --git a/ttmath/ttmathint.h b/ttmath/ttmathint.h index cc89064..4d2fe61 100644 --- a/ttmath/ttmathint.h +++ b/ttmath/ttmathint.h @@ -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::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: