added: flag TTMATH_BIG_ZERO to Big<> class

if this flag is set then there is a value zero
added:   Big::ClearInfoBit(unsigned char)
         Big::SetInfoBit(unsigned char)
         Big::IsInfoBit(unsigned char)
         some methods for manipulating the info flags
changed: IsZero() is using TTMATH_BIG_ZERO flag
         now it has O(1) complexity
         previously was O(n)
changed: optimized some methods
         they are using IsZero() for testing at the beginning
         because this method is much faster now
changed: Big::Div(ss2)
         Big::Mod(ss2)
         they return 2 when ss2 is zero
         previously returned 1



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@190 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2009-09-11 04:24:42 +00:00
parent 74b31b1f54
commit e13e5eb329
3 changed files with 194 additions and 60 deletions

View File

@ -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) * added: support for wide characters (wchar_t)
wide characters are used when macro TTMATH_USE_WCHAR is defined wide characters are used when macro TTMATH_USE_WCHAR is defined
this macro is defined automatically when there is macro UNICODE or _UNICODE 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 * added: x86_64 asm code for Microsoft Visual compiler
file: ttmathuint_x86_64_msvc.asm file: ttmathuint_x86_64_msvc.asm
(this file should be compiled first because MS VC doesn't support inline assembler in x86_64 mode) (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: 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 * removed: Parser<>::SetFactorialMax() method
the factorial() is such a fast now that we don't need the method longer the factorial() is such a fast now that we don't need the method longer
* removed: ErrorCode::err_too_big_factorial * removed: ErrorCode::err_too_big_factorial

View File

@ -59,7 +59,7 @@ namespace ttmath
/*! /*!
\brief Big implements the floating point numbers \brief Big implements the floating point numbers
*/ */
template <uint exp,uint man> template <uint exp, uint man>
class Big 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) (when the bit is set)
*/ */
#define TTMATH_BIG_SIGN 128 #define TTMATH_BIG_SIGN 128
@ -98,11 +99,18 @@ unsigned char info;
/*! /*!
Not a number 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 #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 this method moves all bits from mantissa into its left side
(suitably changes the exponent) or if the mantissa is zero (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 it can return a carry
the carry will be when we don't have enough space in the exponent the carry will be when we don't have enough space in the exponent
@ -138,7 +147,10 @@ public:
uint Standardizing() uint Standardizing()
{ {
if( mantissa.IsTheHighestBitSet() ) if( mantissa.IsTheHighestBitSet() )
{
ClearInfoBit(TTMATH_BIG_ZERO);
return 0; return 0;
}
if( CorrectZero() ) if( CorrectZero() )
return 0; return 0;
@ -161,27 +173,63 @@ private:
{ {
if( mantissa.IsZero() ) if( mantissa.IsZero() )
{ {
Abs(); SetInfoBit(TTMATH_BIG_ZERO);
ClearInfoBit(TTMATH_BIG_SIGN);
exponent.SetZero(); exponent.SetZero();
return true; return true;
}
else
{
ClearInfoBit(TTMATH_BIG_ZERO);
} }
return false; return false;
} }
public: 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 this method sets zero
*/ */
void SetZero() void SetZero()
{ {
info = 0; info = TTMATH_BIG_ZERO;
exponent.SetZero(); exponent.SetZero();
mantissa.SetZero(); mantissa.SetZero();
@ -216,7 +264,7 @@ public:
*/ */
void SetNan() void SetNan()
{ {
info |= TTMATH_BIG_NAN; SetInfoBit(TTMATH_BIG_NAN);
} }
@ -537,12 +585,7 @@ public:
*/ */
bool IsZero() const bool IsZero() const
{ {
/* return IsInfoBit(TTMATH_BIG_ZERO);
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();
} }
@ -552,7 +595,7 @@ public:
*/ */
bool IsSign() const bool IsSign() const
{ {
return (info & TTMATH_BIG_SIGN) == TTMATH_BIG_SIGN; return IsInfoBit(TTMATH_BIG_SIGN);
} }
@ -561,7 +604,7 @@ public:
*/ */
bool IsNan() const bool IsNan() const
{ {
return (info & TTMATH_BIG_NAN) == TTMATH_BIG_NAN; return IsInfoBit(TTMATH_BIG_NAN);
} }
@ -576,7 +619,7 @@ public:
*/ */
void Abs() void Abs()
{ {
info &= ~TTMATH_BIG_SIGN; ClearInfoBit(TTMATH_BIG_SIGN);
} }
@ -618,7 +661,7 @@ public:
*/ */
void SetSign() 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 // we don't have to check the NaN flag here
if( info & TTMATH_BIG_SIGN )
{
info &= ~TTMATH_BIG_SIGN;
return;
}
if( IsZero() ) if( IsZero() )
return; 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() ) 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();
@ -759,6 +802,15 @@ public:
if( IsSign() || ss2.IsSign() ) if( IsSign() || ss2.IsSign() )
return 2; return 2;
if( IsZero() )
return 0;
if( ss2.IsZero() )
{
SetZero();
return 0;
}
Int<exp> exp_offset( exponent ); Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
@ -810,6 +862,15 @@ public:
if( IsSign() || ss2.IsSign() ) if( IsSign() || ss2.IsSign() )
return 2; return 2;
if( IsZero() )
{
*this = ss2;
return 0;
}
if( ss2.IsZero() )
return 0;
Int<exp> exp_offset( exponent ); Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
@ -858,6 +919,15 @@ public:
if( IsSign() || ss2.IsSign() ) if( IsSign() || ss2.IsSign() )
return 2; return 2;
if( ss2.IsZero() )
return 0;
if( IsZero() )
{
*this = ss2;
return 0;
}
Int<exp> exp_offset( exponent ); Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
@ -903,6 +973,15 @@ public:
if( IsNan() ) if( IsNan() )
return 1; return 1;
if( IsZero() )
return 0;
if( ss2 == 0 )
{
SetZero();
return 0;
}
// man_result = mantissa * ss2.mantissa // man_result = mantissa * ss2.mantissa
mantissa.MulInt(ss2, man_result); mantissa.MulInt(ss2, man_result);
@ -987,6 +1066,15 @@ public:
if( IsNan() || ss2.IsNan() ) if( IsNan() || ss2.IsNan() )
return CheckCarry(1); return CheckCarry(1);
if( IsZero() )
return 0;
if( ss2.IsZero() )
{
SetZero();
return 0;
}
// man_result = mantissa * ss2.mantissa // man_result = mantissa * ss2.mantissa
mantissa.MulBig(ss2.mantissa, man_result); mantissa.MulBig(ss2.mantissa, man_result);
@ -1023,9 +1111,11 @@ public:
/*! /*!
division this = this / ss2 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<exp, man> & ss2) uint Div(const Big<exp, man> & ss2)
{ {
@ -1035,9 +1125,18 @@ public:
UInt<man*2> man2; UInt<man*2> man2;
uint i,c = 0; uint i,c = 0;
if( IsNan() || ss2.IsNan() || ss2.IsZero() ) if( IsNan() || ss2.IsNan() )
return CheckCarry(1); return CheckCarry(1);
if( ss2.IsZero() )
{
SetNan();
return 2;
}
if( IsZero() )
return 0;
for(i=0 ; i<man ; ++i) for(i=0 ; i<man ; ++i)
{ {
man1.table[i+man] = mantissa.table[i]; man1.table[i+man] = mantissa.table[i];
@ -1084,6 +1183,11 @@ public:
it means: it means:
in other words: this(old) = ss2 * q + this(new) in other words: this(old) = ss2 * q + this(new)
return value:
0 - ok
1 - carry
2 - improper argument (ss2 is zero)
*/ */
uint Mod(const Big<exp, man> & ss2) uint Mod(const Big<exp, man> & ss2)
{ {
@ -1094,6 +1198,12 @@ public:
if( IsNan() || ss2.IsNan() ) if( IsNan() || ss2.IsNan() )
return CheckCarry(1); return CheckCarry(1);
if( ss2.IsZero() )
{
SetNan();
return 2;
}
if( !SmallerWithoutSignThan(ss2) ) if( !SmallerWithoutSignThan(ss2) )
{ {
Big<exp, man> temp(*this); Big<exp, man> temp(*this);
@ -1130,11 +1240,17 @@ public:
if( IsNan() ) if( IsNan() )
return 1; return 1;
if( pow.IsZero() && IsZero() ) if( IsZero() )
{ {
// we don't define zero^zero if( pow.IsZero() )
SetNan(); {
return 2; // we don't define zero^zero
SetNan();
return 2;
}
// 0^(+something) is zero
return 0;
} }
Big<exp, man> start(*this), start_temp; Big<exp, man> start(*this), start_temp;
@ -1233,10 +1349,16 @@ public:
if( IsNan() || pow.IsNan() ) if( IsNan() || pow.IsNan() )
return CheckCarry(1); return CheckCarry(1);
if( pow.IsZero() && IsZero() ) if( IsZero() )
{ {
SetNan(); if( pow.IsZero() )
return 2; {
SetNan();
return 2;
}
// 0^(+something) is zero
return 0;
} }
if( pow.IsSign() ) if( pow.IsSign() )
@ -2517,6 +2639,10 @@ private:
// setting the rest of mantissa.table into zero (if some has left) // setting the rest of mantissa.table into zero (if some has left)
for( ; i<=man ; ++i) for( ; i<=man ; ++i)
mantissa.table[man-i] = 0; 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<exp,man> & ss2) const bool SmallerWithoutSignThan(const Big<exp,man> & ss2) const
{ {
// we should check the mantissas beforehand because sometimes we can have if( IsZero() )
// a mantissa set to zero but in the exponent something another value
// (maybe we've forgotten about calling CorrectZero() ?)
if( mantissa.IsZero() )
{ {
if( ss2.mantissa.IsZero() ) if( ss2.IsZero() )
// we've got two zeroes // we've got two zeroes
return false; return false;
else else
@ -3835,7 +3958,7 @@ public:
return true; return true;
} }
if( ss2.mantissa.IsZero() ) if( ss2.IsZero() )
// this!=0 and ss2==0 // this!=0 and ss2==0
return false; return false;
@ -3857,12 +3980,9 @@ public:
*/ */
bool GreaterWithoutSignThan(const Big<exp,man> & ss2) const bool GreaterWithoutSignThan(const Big<exp,man> & ss2) const
{ {
// we should check the mantissas beforehand because sometimes we can have if( IsZero() )
// a mantissa set to zero but in the exponent something another value
// (maybe we've forgotten about calling CorrectZero() ?)
if( mantissa.IsZero() )
{ {
if( ss2.mantissa.IsZero() ) if( ss2.IsZero() )
// we've got two zeroes // we've got two zeroes
return false; return false;
else else
@ -3870,7 +3990,7 @@ public:
return false; return false;
} }
if( ss2.mantissa.IsZero() ) if( ss2.IsZero() )
// this!=0 and ss2==0 // this!=0 and ss2==0
return true; return true;
@ -3892,12 +4012,9 @@ public:
*/ */
bool EqualWithoutSign(const Big<exp,man> & ss2) const bool EqualWithoutSign(const Big<exp,man> & ss2) const
{ {
// we should check the mantissas beforehand because sometimes we can have if( IsZero() )
// a mantissa set to zero but in the exponent something another value
// (maybe we've forgotten about calling CorrectZero() ?)
if( mantissa.IsZero() )
{ {
if( ss2.mantissa.IsZero() ) if( ss2.IsZero() )
// we've got two zeroes // we've got two zeroes
return true; return true;
else else
@ -3905,7 +4022,7 @@ public:
return false; return false;
} }
if( ss2.mantissa.IsZero() ) if( ss2.IsZero() )
// this!=0 and ss2==0 // this!=0 and ss2==0
return false; return false;
@ -3936,6 +4053,9 @@ public:
// there is no sense to ignore the whole mantissas // there is no sense to ignore the whole mantissas
TTMATH_ASSERT( nBitsToIgnore < man*TTMATH_BITS_PER_UINT ) TTMATH_ASSERT( nBitsToIgnore < man*TTMATH_BITS_PER_UINT )
if( IsZero() && ss2.IsZero() )
return true;
uint words = nBitsToIgnore / TTMATH_BITS_PER_UINT; uint words = nBitsToIgnore / TTMATH_BITS_PER_UINT;
uint bits = nBitsToIgnore % TTMATH_BITS_PER_UINT; uint bits = nBitsToIgnore % TTMATH_BITS_PER_UINT;
uint i; uint i;
@ -4069,7 +4189,7 @@ public:
/*! /*!
an operator for changing the sign 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<exp,man> operator-() const Big<exp,man> operator-() const
{ {
@ -4293,6 +4413,9 @@ public:
if( IsNan() ) if( IsNan() )
return 1; return 1;
if( IsZero() )
return 0;
half.Set05(); half.Set05();
if( IsSign() ) if( IsSign() )
@ -4302,7 +4425,7 @@ public:
} }
else else
{ {
// 'this' is >= 0 // 'this' is > 0
c = Add( half ); c = Add( half );
} }

View File

@ -1,7 +1,7 @@
; ;
; This file is a part of TTMath Bignum Library ; This file is a part of TTMath Bignum Library
; and is distributed under the (new) BSD licence. ; and is distributed under the (new) BSD licence.
; Author: Christian Kaiser <> ; Author: Christian Kaiser <chk@online.de>
; ;
; ;
@ -18,7 +18,7 @@
; notice, this list of conditions and the following disclaimer in the ; notice, this list of conditions and the following disclaimer in the
; documentation and/or other materials provided with the distribution. ; 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 ; project may be used to endorse or promote products derived
; from this software without specific prior written permission. ; from this software without specific prior written permission.
; ;