diff --git a/CHANGELOG b/CHANGELOG index 08a01d6..a257158 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,4 @@ -Version 0.9.0 prerelease (2009.09.10): +Version 0.9.0 prerelease (2009.09.11): * added: support for wide characters (wchar_t) wide characters are used when macro TTMATH_USE_WCHAR is defined this macro is defined automatically when there is macro UNICODE or _UNICODE defined @@ -26,7 +26,18 @@ Version 0.9.0 prerelease (2009.09.10): * added: x86_64 asm code for Microsoft Visual compiler file: ttmathuint_x86_64_msvc.asm (this file should be compiled first because MS VC doesn't support inline assembler in x86_64 mode) + * added: flag TTMATH_BIG_ZERO to Big<> class + if this flag is set then there is a value zero + Big::IsZero() is faster now + * added: Big::ClearInfoBit(unsigned char) + Big::SetInfoBit(unsigned char) + Big::IsInfoBit(unsigned char) + some methods for manipulating the info flags * changed: Factorial() is using the Gamma() function now + * changed: Big::Div(ss2) + Big::Mod(ss2) + they return 2 when ss2 is zero + previously returned 1 * 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 f443214..68e1037 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -59,7 +59,7 @@ namespace ttmath /*! \brief Big implements the floating point numbers */ -template +template class Big { @@ -90,7 +90,8 @@ unsigned char info; /*! - the number of a bit from 'info' which means that a value is with a sign + Sign + the mask of a bit from 'info' which means that there is a sign (when the bit is set) */ #define TTMATH_BIG_SIGN 128 @@ -98,11 +99,18 @@ unsigned char info; /*! Not a number - if this bit is set that there is no a valid number + if this bit is set that there is not a valid number */ #define TTMATH_BIG_NAN 64 +/*! + Zero + if this bit is set that there is value zero + mantissa should be zero and exponent should be zero too + (the Standardizing() method does this) +*/ +#define TTMATH_BIG_ZERO 32 /*! @@ -127,7 +135,8 @@ public: /*! this method moves all bits from mantissa into its left side (suitably changes the exponent) or if the mantissa is zero - it sets the exponent to zero as well (and clears the sign bit) + it sets the exponent to zero as well + (and clears the sign bit and sets the zero bit) it can return a carry the carry will be when we don't have enough space in the exponent @@ -138,7 +147,10 @@ public: uint Standardizing() { if( mantissa.IsTheHighestBitSet() ) + { + ClearInfoBit(TTMATH_BIG_ZERO); return 0; + } if( CorrectZero() ) return 0; @@ -161,27 +173,63 @@ private: { if( mantissa.IsZero() ) { - Abs(); + SetInfoBit(TTMATH_BIG_ZERO); + ClearInfoBit(TTMATH_BIG_SIGN); exponent.SetZero(); - return true; + return true; + } + else + { + ClearInfoBit(TTMATH_BIG_ZERO); } return false; } - - public: + /*! + this method clears a specific bit in the 'info' variable + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + */ + void ClearInfoBit(unsigned char bit) + { + info = info & (~bit); + } + + + /*! + this method sets a specific bit in the 'info' variable + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + + */ + void SetInfoBit(unsigned char bit) + { + info = info | bit; + } + + + /*! + this method returns true if a specific bit in the 'info' variable is set + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + */ + bool IsInfoBit(unsigned char bit) const + { + return (info & bit) != 0; + } + /*! this method sets zero */ void SetZero() { - info = 0; + info = TTMATH_BIG_ZERO; exponent.SetZero(); mantissa.SetZero(); @@ -216,7 +264,7 @@ public: */ void SetNan() { - info |= TTMATH_BIG_NAN; + SetInfoBit(TTMATH_BIG_NAN); } @@ -537,12 +585,7 @@ public: */ bool IsZero() const { - /* - we only have to test the mantissa - also we don't check the NaN flag - (maybe this method should return false if there is NaN flag set?) - */ - return mantissa.IsZero(); + return IsInfoBit(TTMATH_BIG_ZERO); } @@ -552,7 +595,7 @@ public: */ bool IsSign() const { - return (info & TTMATH_BIG_SIGN) == TTMATH_BIG_SIGN; + return IsInfoBit(TTMATH_BIG_SIGN); } @@ -561,7 +604,7 @@ public: */ bool IsNan() const { - return (info & TTMATH_BIG_NAN) == TTMATH_BIG_NAN; + return IsInfoBit(TTMATH_BIG_NAN); } @@ -576,7 +619,7 @@ public: */ void Abs() { - info &= ~TTMATH_BIG_SIGN; + ClearInfoBit(TTMATH_BIG_SIGN); } @@ -618,7 +661,7 @@ public: */ void SetSign() { - info |= TTMATH_BIG_SIGN; + SetInfoBit(TTMATH_BIG_SIGN); } @@ -634,16 +677,13 @@ public: { // we don't have to check the NaN flag here - if( info & TTMATH_BIG_SIGN ) - { - info &= ~TTMATH_BIG_SIGN; - return; - } - if( IsZero() ) return; - info |= TTMATH_BIG_SIGN; + if( IsSign() ) + ClearInfoBit(TTMATH_BIG_SIGN); + else + SetInfoBit(TTMATH_BIG_SIGN); } @@ -672,6 +712,9 @@ public: if( IsNan() || ss2.IsNan() ) return CheckCarry(1); + if( ss2.IsZero() ) + return 0; + exp_offset.Sub( ss2.exponent ); exp_offset.Abs(); @@ -759,6 +802,15 @@ public: if( IsSign() || ss2.IsSign() ) return 2; + if( IsZero() ) + return 0; + + if( ss2.IsZero() ) + { + SetZero(); + return 0; + } + Int exp_offset( exponent ); Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); @@ -810,6 +862,15 @@ public: if( IsSign() || ss2.IsSign() ) return 2; + if( IsZero() ) + { + *this = ss2; + return 0; + } + + if( ss2.IsZero() ) + return 0; + Int exp_offset( exponent ); Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); @@ -858,6 +919,15 @@ public: if( IsSign() || ss2.IsSign() ) return 2; + if( ss2.IsZero() ) + return 0; + + if( IsZero() ) + { + *this = ss2; + return 0; + } + Int exp_offset( exponent ); Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); @@ -903,6 +973,15 @@ public: if( IsNan() ) return 1; + if( IsZero() ) + return 0; + + if( ss2 == 0 ) + { + SetZero(); + return 0; + } + // man_result = mantissa * ss2.mantissa mantissa.MulInt(ss2, man_result); @@ -987,6 +1066,15 @@ public: if( IsNan() || ss2.IsNan() ) return CheckCarry(1); + if( IsZero() ) + return 0; + + if( ss2.IsZero() ) + { + SetZero(); + return 0; + } + // man_result = mantissa * ss2.mantissa mantissa.MulBig(ss2.mantissa, man_result); @@ -1023,9 +1111,11 @@ public: /*! division this = this / ss2 - this method returns carry (in a division carry can be as well) - (it also returns 0 if ss2 is zero) + return value: + 0 - ok + 1 - carry (in a division carry can be as well) + 2 - improper argument (ss2 is zero) */ uint Div(const Big & ss2) { @@ -1035,9 +1125,18 @@ public: UInt man2; uint i,c = 0; - if( IsNan() || ss2.IsNan() || ss2.IsZero() ) + if( IsNan() || ss2.IsNan() ) return CheckCarry(1); + if( ss2.IsZero() ) + { + SetNan(); + return 2; + } + + if( IsZero() ) + return 0; + for(i=0 ; i & ss2) { @@ -1094,6 +1198,12 @@ public: if( IsNan() || ss2.IsNan() ) return CheckCarry(1); + if( ss2.IsZero() ) + { + SetNan(); + return 2; + } + if( !SmallerWithoutSignThan(ss2) ) { Big temp(*this); @@ -1130,11 +1240,17 @@ public: if( IsNan() ) return 1; - if( pow.IsZero() && IsZero() ) + if( IsZero() ) { - // we don't define zero^zero - SetNan(); - return 2; + if( pow.IsZero() ) + { + // we don't define zero^zero + SetNan(); + return 2; + } + + // 0^(+something) is zero + return 0; } Big start(*this), start_temp; @@ -1233,10 +1349,16 @@ public: if( IsNan() || pow.IsNan() ) return CheckCarry(1); - if( pow.IsZero() && IsZero() ) + if( IsZero() ) { - SetNan(); - return 2; + if( pow.IsZero() ) + { + SetNan(); + return 2; + } + + // 0^(+something) is zero + return 0; } if( pow.IsSign() ) @@ -2517,6 +2639,10 @@ private: // setting the rest of mantissa.table into zero (if some has left) for( ; i<=man ; ++i) mantissa.table[man-i] = 0; + + // the highest bit is either one or zero (when the whole mantissa is zero) + // we can only call CorrectZero() + CorrectZero(); } @@ -3822,12 +3948,9 @@ public: */ bool SmallerWithoutSignThan(const Big & ss2) const { - // we should check the mantissas beforehand because sometimes we can have - // a mantissa set to zero but in the exponent something another value - // (maybe we've forgotten about calling CorrectZero() ?) - if( mantissa.IsZero() ) + if( IsZero() ) { - if( ss2.mantissa.IsZero() ) + if( ss2.IsZero() ) // we've got two zeroes return false; else @@ -3835,7 +3958,7 @@ public: return true; } - if( ss2.mantissa.IsZero() ) + if( ss2.IsZero() ) // this!=0 and ss2==0 return false; @@ -3857,12 +3980,9 @@ public: */ bool GreaterWithoutSignThan(const Big & ss2) const { - // we should check the mantissas beforehand because sometimes we can have - // a mantissa set to zero but in the exponent something another value - // (maybe we've forgotten about calling CorrectZero() ?) - if( mantissa.IsZero() ) + if( IsZero() ) { - if( ss2.mantissa.IsZero() ) + if( ss2.IsZero() ) // we've got two zeroes return false; else @@ -3870,7 +3990,7 @@ public: return false; } - if( ss2.mantissa.IsZero() ) + if( ss2.IsZero() ) // this!=0 and ss2==0 return true; @@ -3892,12 +4012,9 @@ public: */ bool EqualWithoutSign(const Big & ss2) const { - // we should check the mantissas beforehand because sometimes we can have - // a mantissa set to zero but in the exponent something another value - // (maybe we've forgotten about calling CorrectZero() ?) - if( mantissa.IsZero() ) + if( IsZero() ) { - if( ss2.mantissa.IsZero() ) + if( ss2.IsZero() ) // we've got two zeroes return true; else @@ -3905,7 +4022,7 @@ public: return false; } - if( ss2.mantissa.IsZero() ) + if( ss2.IsZero() ) // this!=0 and ss2==0 return false; @@ -3936,6 +4053,9 @@ public: // there is no sense to ignore the whole mantissas TTMATH_ASSERT( nBitsToIgnore < man*TTMATH_BITS_PER_UINT ) + if( IsZero() && ss2.IsZero() ) + return true; + uint words = nBitsToIgnore / TTMATH_BITS_PER_UINT; uint bits = nBitsToIgnore % TTMATH_BITS_PER_UINT; uint i; @@ -4069,7 +4189,7 @@ public: /*! an operator for changing the sign - it's not changing 'this' but the changed value will be returned + this method is not changing 'this' but the changed value is returned */ Big operator-() const { @@ -4293,6 +4413,9 @@ public: if( IsNan() ) return 1; + if( IsZero() ) + return 0; + half.Set05(); if( IsSign() ) @@ -4302,7 +4425,7 @@ public: } else { - // 'this' is >= 0 + // 'this' is > 0 c = Add( half ); } diff --git a/ttmath/ttmathuint_x86_64_msvc.asm b/ttmath/ttmathuint_x86_64_msvc.asm index 34e68c5..9adfbc4 100644 --- a/ttmath/ttmathuint_x86_64_msvc.asm +++ b/ttmath/ttmathuint_x86_64_msvc.asm @@ -1,7 +1,7 @@ ; ; This file is a part of TTMath Bignum Library ; and is distributed under the (new) BSD licence. -; Author: Christian Kaiser <> +; Author: Christian Kaiser ; ; @@ -18,7 +18,7 @@ ; notice, this list of conditions and the following disclaimer in the ; documentation and/or other materials provided with the distribution. ; -; * Neither the name Tomasz Sowa nor the names of contributors to this +; * Neither the name Christian Kaiser nor the names of contributors to this ; project may be used to endorse or promote products derived ; from this software without specific prior written permission. ;