From de583784881805f6195cb0eb1822aa1f26361fc0 Mon Sep 17 00:00:00 2001 From: Christian Kaiser Date: Thu, 25 Jun 2009 14:11:17 +0000 Subject: [PATCH] - added AboutEqualWithoutSign() to big<> to allow 'suppression' of some unexpected results (that are perfectly logical though, given the possibly unrepresentable nature of binary representation of decimals) like big<>("10.456466") * 2 == big<>("20.912932") resulting in FALSE result. git-svn-id: svn://ttmath.org/publicrep/ttmath/branches/chk@171 e52654a7-88a9-db11-a3e9-0013d4bc506e --- ttmath/ttmath.h | 548 +++++++++++++++++++++---------------------- ttmath/ttmathbig.h | 40 ++-- ttmath/ttmathtypes.h | 24 +- 3 files changed, 306 insertions(+), 306 deletions(-) diff --git a/ttmath/ttmath.h b/ttmath/ttmath.h index ab9faf5..15eea50 100644 --- a/ttmath/ttmath.h +++ b/ttmath/ttmath.h @@ -45,7 +45,7 @@ \brief Mathematics functions. */ -#include "ttmathconfig.h" +#include "ttmathconfig.h" #include "ttmathbig.h" #include "ttmathobjects.h" @@ -96,21 +96,21 @@ namespace ttmath -2.7 = -3 */ template - ValueType Round(const ValueType & x, ErrorCode * err = 0) + ValueType Round(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType result( x ); - uint c = result.Round(); - - if( err ) - *err = c ? err_overflow : err_ok; + uint c = result.Round(); + + if( err ) + *err = c ? err_overflow : err_ok; return result; } @@ -131,14 +131,14 @@ namespace ttmath template ValueType Ceil(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType result(x); uint c = 0; @@ -178,14 +178,14 @@ namespace ttmath template ValueType Floor(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType result(x); uint c = 0; @@ -226,14 +226,14 @@ namespace ttmath template ValueType Ln(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType result; uint state = result.Ln(x); @@ -267,14 +267,14 @@ namespace ttmath template ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0) { - if( x.IsNan() || base.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return ValueType(); // default NaN - } - + if( x.IsNan() || base.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // default NaN + } + ValueType result; uint state = result.Log(x, base); @@ -308,14 +308,14 @@ namespace ttmath template ValueType Exp(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType result; uint c = result.Exp(x); @@ -345,7 +345,7 @@ namespace ttmath (you don't have to call this function) */ template - uint PrepareSin(ValueType & x, bool & change_sign) + uint PrepareSin(ValueType & x, bool & change_sign) { ValueType temp; @@ -361,10 +361,10 @@ namespace ttmath // we're reducing the period 2*PI // (for big values there'll always be zero) temp.Set2Pi(); - - if( x.Mod(temp) ) - return 1; - + + if( x.Mod(temp) ) + return 1; + // we're setting 'x' as being in the range of <0, 0.5PI> @@ -385,8 +385,8 @@ namespace ttmath x.Sub( temp ); x = temp - x; } - - return 0; + + return 0; } @@ -473,7 +473,7 @@ namespace ttmath if( c ) // Sin is from <-1,1> and cannot make an overflow // but the carry can be from the Taylor series - // (then we only break our calculations) + // (then we only break our calculations) break; if( addition ) @@ -505,23 +505,23 @@ namespace ttmath this function calculates the Sine */ template - ValueType Sin(ValueType x, ErrorCode * err = 0) + ValueType Sin(ValueType x, ErrorCode * err = 0) { using namespace auxiliaryfunctions; - ValueType one, result; + ValueType one, result; bool change_sign; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - - if( err ) - *err = err_ok; + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( err ) + *err = err_ok; if( PrepareSin( x, change_sign ) ) { @@ -531,7 +531,7 @@ namespace ttmath // result has NaN flag set by default if( err ) - *err = err_overflow; // maybe another error code? err_improper_argument? + *err = err_overflow; // maybe another error code? err_improper_argument? return result; // NaN is set by default } @@ -561,20 +561,20 @@ namespace ttmath we're using the formula cos(x) = sin(x + PI/2) */ template - ValueType Cos(ValueType x, ErrorCode * err = 0) + ValueType Cos(ValueType x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType pi05; pi05.Set05Pi(); - uint c = x.Add( pi05 ); + uint c = x.Add( pi05 ); if( c ) { @@ -584,9 +584,9 @@ namespace ttmath return ValueType(); // result is undefined (NaN is set by default) } - return Sin(x, err); - } - + return Sin(x, err); + } + /*! this function calulates the Tangent @@ -601,10 +601,10 @@ namespace ttmath template ValueType Tan(const ValueType & x, ErrorCode * err = 0) { - ValueType result = Cos(x, err); - - if( err && *err != err_ok ) - return result; + ValueType result = Cos(x, err); + + if( err && *err != err_ok ) + return result; if( result.IsZero() ) { @@ -616,7 +616,7 @@ namespace ttmath return result; } - return Sin(x, err) / result; + return Sin(x, err) / result; } @@ -643,10 +643,10 @@ namespace ttmath template ValueType Cot(const ValueType & x, ErrorCode * err = 0) { - ValueType result = Sin(x, err); - - if( err && *err != err_ok ) - return result; + ValueType result = Sin(x, err); + + if( err && *err != err_ok ) + return result; if( result.IsZero() ) { @@ -658,7 +658,7 @@ namespace ttmath return result; } - return Cos(x, err) / result; + return Cos(x, err) / result; } @@ -843,14 +843,14 @@ namespace ttmath one.SetOne(); bool change_sign = false; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + if( x.GreaterWithoutSignThan(one) ) { if( err ) @@ -1073,9 +1073,9 @@ namespace ttmath one.SetOne(); bool change_sign = false; - if( x.IsNan() ) - return result; // NaN is set by default - + if( x.IsNan() ) + return result; // NaN is set by default + // if x is negative we're using the formula: // atan(-x) = -atan(x) if( x.IsSign() ) @@ -1156,14 +1156,14 @@ namespace ttmath template ValueType Sinh(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType ex, emx; uint c = 0; @@ -1188,14 +1188,14 @@ namespace ttmath template ValueType Cosh(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType ex, emx; uint c = 0; @@ -1220,14 +1220,14 @@ namespace ttmath template ValueType Tanh(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType ex, emx, nominator, denominator; uint c = 0; @@ -1268,14 +1268,14 @@ namespace ttmath template ValueType Coth(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + if( x.IsZero() ) { if( err ) @@ -1333,14 +1333,14 @@ namespace ttmath template ValueType ASinh(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType xx(x), one, result; uint c = 0; one.SetOne(); @@ -1369,14 +1369,14 @@ namespace ttmath template ValueType ACosh(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType xx(x), one, result; uint c = 0; one.SetOne(); @@ -1418,14 +1418,14 @@ namespace ttmath template ValueType ATanh(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType nominator(x), denominator, one, result; uint c = 0; one.SetOne(); @@ -1471,14 +1471,14 @@ namespace ttmath template ValueType ACoth(const ValueType & x, ErrorCode * err = 0) { - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return x; // NaN - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + ValueType nominator(x), denominator(x), one, result; uint c = 0; one.SetOne(); @@ -1537,14 +1537,14 @@ namespace ttmath ValueType result, temp; uint c = 0; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + result = x; // it is better to make division first and then multiplication @@ -1573,14 +1573,14 @@ namespace ttmath ValueType result, delimiter; uint c = 0; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + result = 180; c += result.Mul(x); @@ -1618,7 +1618,7 @@ namespace ttmath ValueType delimiter, multipler; uint c = 0; - if( d.IsNan() || m.IsNan() || s.IsNan() || m.IsSign() || s.IsSign() ) + if( d.IsNan() || m.IsNan() || s.IsNan() || m.IsSign() || s.IsSign() ) { if( err ) *err = err_improper_argument; @@ -1672,14 +1672,14 @@ namespace ttmath ValueType result, temp; uint c = 0; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + result = x; // it is better to make division first and then multiplication @@ -1708,14 +1708,14 @@ namespace ttmath ValueType result, delimiter; uint c = 0; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + result = 200; c += result.Mul(x); @@ -1740,14 +1740,14 @@ namespace ttmath ValueType result, temp; uint c = 0; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + result = x; temp = 200; @@ -1790,14 +1790,14 @@ namespace ttmath ValueType result, temp; uint c = 0; - if( x.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return result; // NaN is set by default - } - + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + result = x; temp = 180; @@ -1831,7 +1831,7 @@ namespace ttmath template ValueType Sqrt(ValueType x, ErrorCode * err = 0) { - if( x.IsNan() || x.IsSign() ) + if( x.IsNan() || x.IsSign() ) { if( err ) *err = err_improper_argument; @@ -1913,7 +1913,7 @@ namespace ttmath template - bool RootCheckIndexOne(const ValueType & index, ErrorCode * err) + bool RootCheckIndexOne(const ValueType & index, ErrorCode * err) { ValueType one; one.SetOne(); @@ -1955,12 +1955,12 @@ namespace ttmath template - bool RootCheckXZero(ValueType & x, ErrorCode * err) + bool RootCheckXZero(ValueType & x, ErrorCode * err) { if( x.IsZero() ) { // root(0;index) is zero (if index!=0) - // RootCheckIndexZero() must be called beforehand + // RootCheckIndexZero() must be called beforehand x.SetZero(); if( err ) @@ -2027,19 +2027,19 @@ namespace ttmath { using namespace auxiliaryfunctions; - if( x.IsNan() || index.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return ValueType(); // NaN is set by default - } - + if( x.IsNan() || index.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + if( RootCheckIndexSign(x, index, err) ) return x; if( RootCheckIndexZero(x, index, err) ) return x; - if( RootCheckIndexOne ( index, err) ) return x; + if( RootCheckIndexOne ( index, err) ) return x; if( RootCheckIndexFrac(x, index, err) ) return x; - if( RootCheckXZero (x, err) ) return x; + if( RootCheckXZero (x, err) ) return x; // index integer and index!=0 // x!=0 @@ -2090,17 +2090,17 @@ namespace ttmath while( !carry && multiplerWasStopSignal() ) - { + // after each 128 iterations we make a test + if( stop->WasStopSignal() ) + { if( err ) *err = err_interrupt; return 2; } - } + } ++multipler; carry += result.MulUInt(multipler); @@ -2123,25 +2123,25 @@ namespace ttmath one.SetOne(); uint carry = 0; - uint iter = 1; // only for testing the stop object + uint iter = 1; // only for testing the stop object while( !carry && multipler < x ) { - if( stop && (iter & 31)==0 ) // it means 'stop && (iter % 32)==0' + if( stop && (iter & 31)==0 ) // it means 'stop && (iter % 32)==0' { - // after each 32 iterations we make a test - if( stop->WasStopSignal() ) - { + // after each 32 iterations we make a test + if( stop->WasStopSignal() ) + { if( err ) *err = err_interrupt; return 2; } - } + } carry += multipler.Add(one); carry += result.Mul(multipler); - ++iter; + ++iter; } if( err ) @@ -2168,16 +2168,16 @@ namespace ttmath static History history; ValueType result; - if( x.IsNan() || x.IsSign() ) + if( x.IsNan() || x.IsSign() ) { if( err ) *err = err_improper_argument; - return result; // NaN set by default + return result; // NaN set by default } - result.SetOne(); - + result.SetOne(); + if( !x.exponent.IsSign() && !x.exponent.IsZero() ) { // when x.exponent>0 there's no sense to calculate the formula @@ -2256,25 +2256,25 @@ namespace ttmath e.g. mod( 12.6 ; 3) = 0.6 because 12.6 = 3*4 + 0.6 - mod(-12.6 ; 3) = -0.6 bacause -12.6 = 3*(-4) + (-0.6) + mod(-12.6 ; 3) = -0.6 bacause -12.6 = 3*(-4) + (-0.6) mod( 12.6 ; -3) = 0.6 mod(-12.6 ; -3) = -0.6 */ template - ValueType Mod(ValueType a, const ValueType & b, ErrorCode * err = 0) - { - if( a.IsNan() || b.IsNan() ) - { - if( err ) - *err = err_improper_argument; - - return ValueType(); // NaN is set by default - } - - uint c = a.Mod(b); - - if( err ) - *err = c ? err_overflow : err_ok; + ValueType Mod(ValueType a, const ValueType & b, ErrorCode * err = 0) + { + if( a.IsNan() || b.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + uint c = a.Mod(b); + + if( err ) + *err = c ? err_overflow : err_ok; return a; } @@ -2290,11 +2290,11 @@ namespace ttmath */ #include "ttmathparser.h" - -#ifdef _MSC_VER -#pragma warning( default: 4127 ) -//warning C4127: conditional expression is constant + +#ifdef _MSC_VER +#pragma warning( default: 4127 ) +//warning C4127: conditional expression is constant +#endif + + #endif - - -#endif diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index 2b7c68c..72c59a3 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -3864,26 +3864,36 @@ public: return false; } - bool IsNearZero() const + bool AboutEqualWithoutSign(const Big & ss2, int nBitsToIgnore = 4) 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( mantissa.IsZero() && ss2.mantissa.IsZero()) + { return true; - } + } - UInt m(mantissa); - - m.Rcr(man*3); // pi * thumb rule... - - return(m.IsZero()); + if( exponent==ss2.exponent ) + { + if (mantissa == ss2.mantissa) + { + return(true); + } + ASSERT(nBitsToIgnore < TTMATH_BITS_PER_UINT); + + for (int n = man-1; n > 0; --n) + { + if (mantissa.table[n] != ss2.mantissa.table[n]) + return(false); + } + uint nMask = ~((1 << nBitsToIgnore) - 1); + return((mantissa.table[0] & nMask) == (ss2.mantissa.table[0] & nMask)); + } return false; } - bool operator<(const Big & ss2) const { if( IsSign() && !ss2.IsSign() ) @@ -3914,16 +3924,6 @@ public: } - bool operator^=(const Big & ss2) const - { - if( IsSign() != ss2.IsSign() ) - return false; - - return AboutEqualWithoutSign( ss2 ); - } - - - bool operator>(const Big & ss2) const { if( IsSign() && !ss2.IsSign() ) diff --git a/ttmath/ttmathtypes.h b/ttmath/ttmathtypes.h index e81a127..5b69b8d 100644 --- a/ttmath/ttmathtypes.h +++ b/ttmath/ttmathtypes.h @@ -64,8 +64,8 @@ */ #define TTMATH_MAJOR_VER 0 #define TTMATH_MINOR_VER 8 -#define TTMATH_REVISION_VER 5 -#define TTMATH_PRERELEASE_VER 0 +#define TTMATH_REVISION_VER 5 +#define TTMATH_PRERELEASE_VER 0 /*! @@ -232,16 +232,16 @@ namespace ttmath -/*! - this is a limit when calculating Karatsuba multiplication - if the size of a vector is smaller than TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE - the Karatsuba algorithm will use standard schoolbook multiplication -*/ -#ifdef __GNUC__ -#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 -#else -#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 5 -#endif +/*! + this is a limit when calculating Karatsuba multiplication + if the size of a vector is smaller than TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE + the Karatsuba algorithm will use standard schoolbook multiplication +*/ +#ifdef __GNUC__ +#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 +#else +#define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 5 +#endif namespace ttmath {