diff --git a/constgen/Makefile b/constgen/Makefile index 74bdf4b..b1a790b 100644 --- a/constgen/Makefile +++ b/constgen/Makefile @@ -1,6 +1,6 @@ o = main.o CC = g++ -CFLAGS = -s -O2 -DCONSTANTSGENERATOR +CFLAGS = -s -O2 -DTTMATH_CONSTANTSGENERATOR name = gen diff --git a/constgen/main.cpp b/constgen/main.cpp index 0eaea7b..e6b7fe4 100644 --- a/constgen/main.cpp +++ b/constgen/main.cpp @@ -91,7 +91,7 @@ void CalcE() ttmath::Big<1,400> e; ttmath::uint steps; - // macro CONSTANTSGENERATOR has to be defined + // macro TTMATH_CONSTANTSGENERATOR has to be defined e.ExpSurrounding0(1, &steps); std::cout << "---------------- e ----------------" << std::endl; e.mantissa.PrintTable(std::cout); @@ -105,7 +105,7 @@ void CalcLn(int x) ttmath::Big<1,400> ln; ttmath::uint steps; - // macro CONSTANTSGENERATOR has to be defined + // macro TTMATH_CONSTANTSGENERATOR has to be defined ln.LnSurrounding1(x, &steps); std::cout << "---------------- ln(" << x << ") ----------------" << std::endl; ln.mantissa.PrintTable(std::cout); diff --git a/ttmath/ttmath.h b/ttmath/ttmath.h index 34284b8..b687138 100644 --- a/ttmath/ttmath.h +++ b/ttmath/ttmath.h @@ -1,3 +1,4 @@ + /* * This file is a part of TTMath Bignum Library * and is distributed under the (new) BSD licence. @@ -467,6 +468,21 @@ namespace ttmath PrepareSin( x, change_sign ); ValueType result = Sin0pi05( x ); + if( PrepareSin( x, change_sign ) ) + { + // x is too big, we cannnot reduce the 2*PI period + // prior to version 0.8.5 the result was zero + + // result has NaN flag set by default + + if( err ) + *err = err_overflow; // maybe another error code? + + return result; // NaN is set by default + } + + result = Sin0pi05( x ); + one.SetOne(); // after calculations there can be small distortions in the result @@ -497,7 +513,13 @@ namespace ttmath x.Add( pi05 ); - return Sin(x); + if( c ) + { + if( err ) + *err = err_overflow; + } + + return ValueType(); // result is undefined (NaN is set by default) } @@ -521,6 +543,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + result.SetNan(); + return result; } @@ -561,6 +585,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + result.SetNan(); + return result; } @@ -748,7 +774,7 @@ namespace ttmath { using namespace auxiliaryfunctions; - ValueType one; + ValueType result, one; one.SetOne(); bool change_sign = false; @@ -757,7 +783,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return one; + return result; // NaN is set by default } if( x.IsSign() ) @@ -768,8 +794,6 @@ namespace ttmath one.exponent.SubOne(); // =0.5 - ValueType result; - // asin(-x) = -asin(x) if( x.GreaterWithoutSignThan(one) ) result = ASin_1(x); @@ -1149,7 +1173,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return x; + return ValueType(); // NaN is set by default } ValueType ex, emx, nominator, denominator; @@ -1238,7 +1262,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return result; + return result; // NaN is set by default } c += xx.Mul(x); @@ -1279,7 +1303,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return result; + return result; // NaN is set by default } c += nominator.Add(one); @@ -1324,7 +1348,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return result; + return result; // NaN is set by default } c += nominator.Add(one); @@ -1443,7 +1467,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return delimiter; + return delimiter; // NaN is set by default } multipler = 60; @@ -1624,7 +1648,7 @@ namespace ttmath if( err ) *err = err_improper_argument; - return x; + return ValueType(); // NaN is set by default } if( x.IsZero() ) @@ -1662,6 +1686,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + x.SetNan(); + return true; } @@ -1680,6 +1706,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + x.SetNan(); + return true; } @@ -1729,6 +1757,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + x.SetNan(); + return true; } @@ -1777,6 +1807,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + x.SetNan(); + return true; } } @@ -1861,6 +1893,7 @@ namespace ttmath while( !carry && multiplerWasStopSignal() ) { if( err ) @@ -1893,6 +1926,7 @@ namespace ttmath while( !carry && multipler < x ) { + // !! the test here we don't have to make in all iterations (performance) if( stop && stop->WasStopSignal() ) { if( err ) @@ -1936,6 +1970,8 @@ namespace ttmath if( err ) *err = err_improper_argument; + result.SetNan(); + return result; } @@ -1947,6 +1983,8 @@ namespace ttmath if( err ) *err = err_overflow; + result.SetNan(); + return result; } @@ -1967,8 +2005,11 @@ namespace ttmath status = FactorialMore(x, err, stop, result); if( status == 2 ) + { // the calculation has been interrupted + result.SetNan(); return result; + } err_tmp = status==1 ? err_overflow : err_ok; history.Add(x, result, err_tmp); diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index b97e238..2c1e4b8 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -91,14 +91,35 @@ tchar_t info; /*! the number of a bit from 'info' which means that a value is with a sign (when the bit is set) - - /at the moment the rest bits from 'info' are not used/ */ #define TTMATH_BIG_SIGN 128 +/*! + Not a number + if this bit is set that there is no a valid number +*/ +#define TTMATH_BIG_NAN 64 + + + /*! + this method sets NaN if there was a carry (and returns 1 in such a case) + + c can be 0, 1 or other value different from zero + */ + uint CheckCarry(uint c) + { + if( c != 0 ) + { + SetNan(); + return 1; + } + + return 0; + } + public: @@ -122,8 +143,9 @@ public: return 0; uint comp = mantissa.CompensationToLeft(); + uint c = exponent.Sub( comp ); - return exponent.Sub( comp ); + return CheckCarry(c); } @@ -188,6 +210,15 @@ public: } + /*! + this method sets NaN flag (Not a Number) + when this flag is set that means there is no a valid number + */ + void SetNan() + { + info |= TTMATH_BIG_NAN; + } + private: @@ -508,6 +539,7 @@ public: { /* we only have to test the mantissa + also we don't check the NaN flag */ return mantissa.IsZero(); } @@ -515,6 +547,7 @@ public: /*! this method returns true when there's the sign set + also we don't check the NaN flag */ bool IsSign() const { @@ -522,6 +555,16 @@ public: } + /*! + this method returns true when there is not a valid number + */ + bool IsNan() const + { + return (info & TTMATH_BIG_NAN) == TTMATH_BIG_NAN; + } + + + /*! this method clears the sign (there'll be an absolute value) @@ -544,6 +587,9 @@ public: */ void Sgn() { + if( IsNan() ) + return; + if( IsSign() ) { SetOne(); @@ -618,6 +664,9 @@ public: uint c = 0; + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + exp_offset.Sub( ss2.exponent ); exp_offset.Abs(); @@ -659,12 +708,12 @@ public: // there shouldn't be a carry here because // (1) (2) guarantee that the mantissa of this // is greater than or equal to the mantissa of the ss2 - TTMATH_VERIFY( mantissa.Sub(ss2.mantissa) == 0 ) + TTMATH_VERIFY( mantissa.Sub(ss2.mantissa) >= 0 ) } c += Standardizing(); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -692,6 +741,9 @@ public: */ uint BitAnd(Big ss2) { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + if( IsSign() || ss2.IsSign() ) return 2; @@ -725,7 +777,7 @@ public: c += Standardizing(); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -740,6 +792,9 @@ public: */ uint BitOr(Big ss2) { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + if( IsSign() || ss2.IsSign() ) return 2; @@ -770,7 +825,7 @@ public: c += Standardizing(); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -785,6 +840,9 @@ public: */ uint BitXor(Big ss2) { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + if( IsSign() || ss2.IsSign() ) return 2; @@ -815,7 +873,7 @@ public: c += Standardizing(); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -830,6 +888,9 @@ public: UInt man_result; uint i,c = 0; + if( IsNan() ) + return 1; + // man_result = mantissa * ss2.mantissa mantissa.MulInt(ss2, man_result); @@ -858,7 +919,7 @@ public: c += Standardizing(); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -869,6 +930,9 @@ public: */ uint MulInt(sint ss2) { + if( IsNan() ) + return 1; + if( ss2 == 0 ) { SetZero(); @@ -908,6 +972,9 @@ public: UInt man_result; uint i,c; + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + // man_result = mantissa * ss2.mantissa mantissa.MulBig(ss2.mantissa, man_result); @@ -938,7 +1005,7 @@ public: c += Standardizing(); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -956,11 +1023,8 @@ public: UInt man2; uint i,c; - if( ss2.IsZero() ) - { - // we don't divide by zero - return 1; - } + if( IsNan() || ss2.IsNan() || ss2.IsZero() ) + return CheckCarry(1); for(i=0 ; i & ss2) { @@ -1013,14 +1077,23 @@ public: uint c = 0; - Big temp(*this); + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); - c += temp.Div(ss2); - temp.SkipFraction(); - c += temp.Mul(ss2); - c += Sub(temp); + if( !SmallerWithoutSignThan(ss2) ) + { + Big temp(*this); - return (c==0)? 0 : 1; + c = temp.Div(ss2); + temp.SkipFraction(); + c += temp.Mul(ss2); + c += Sub(temp); + + if( !SmallerWithoutSignThan( ss2 ) ) + c += 1; + } + + return CheckCarry(c); } @@ -1039,30 +1112,35 @@ public: template uint Pow(UInt pow) { + if( IsNan() ) + return 1; + if(pow.IsZero() && IsZero()) + { // we don't define zero^zero + SetNan(); return 2; + } Big start(*this), start_temp; Big result; result.SetOne(); + uint c = 0; - while( !pow.IsZero() ) + while( !c && !pow.IsZero() ) { if( pow.table[0] & 1 ) - if( result.Mul(start) ) - return 1; + c += result.Mul(start); start_temp = start; - if( start.Mul(start_temp) ) - return 1; + c += start.Mul(start_temp); pow.Rcr(1); } *this = result; - return 0; + return CheckCarry(c); } @@ -1078,27 +1156,29 @@ public: template uint Pow(Int pow) { + if( IsNan() ) + return 1; + if( !pow.IsSign() ) return Pow( UInt(pow) ); if( IsZero() ) + { // if 'p' is negative then // 'this' must be different from zero + SetNan(); return 2; + } - if( pow.ChangeSign() ) - return 1; + uint c = pow.ChangeSign(); Big t(*this); - uint c_temp = t.Pow( UInt(pow) ); - if( c_temp > 0 ) - return c_temp; + c += t.Pow( UInt(pow) ); // here can only be a carry (return:1) SetOne(); - if( Div(t) ) - return 1; + c += Div(t); - return 0; + return CheckCarry(c); } @@ -1135,8 +1215,14 @@ public: */ uint PowUInt(Big pow) { + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + if( pow.IsZero() && IsZero() ) + { + SetNan(); return 2; + } if( pow.IsSign() ) pow.Abs(); @@ -1145,27 +1231,26 @@ public: Big result; Big one; Int e_one; + uint c = 0; e_one.SetOne(); one.SetOne(); result = one; - while( pow >= one ) + while( !c && pow >= one ) { if( pow.Mod2() ) - if( result.Mul(start) ) - return 1; + c += result.Mul(start); start_temp = start; - if( start.Mul(start_temp) ) - return 1; + c += start.Mul(start_temp); - pow.exponent.Sub( e_one ); + c += pow.exponent.Sub( e_one ); } *this = result; - return 0; + return CheckCarry(c); } @@ -1183,24 +1268,27 @@ public: { TTMATH_REFERENCE_ASSERT( pow ) + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + if( !pow.IsSign() ) return PowUInt(pow); if( IsZero() ) + { // if 'pow' is negative then // 'this' must be different from zero + SetNan(); return 2; + } Big temp(*this); - uint c_temp = temp.PowUInt(pow); - if( c_temp > 0 ) - return c_temp; + uint c = temp.PowUInt(pow); // here can only be a carry (result:1) SetOne(); - if( Div(temp) ) - return 1; + c += Div(temp); - return 0; + return CheckCarry(c); } @@ -1218,16 +1306,22 @@ public: { TTMATH_REFERENCE_ASSERT( pow ) + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + Big temp; uint c = temp.Ln(*this); - if( c!= 0 ) + if( c != 0 ) // can be 2 from Ln() + { + SetNan(); return c; + } c += temp.Mul(pow); c += Exp(temp); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -1245,11 +1339,17 @@ public: { TTMATH_REFERENCE_ASSERT( pow ) + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + if( IsZero() ) { // 0^pow will be 0 only for pow>0 if( pow.IsSign() || pow.IsZero() ) + { + SetNan(); return 2; + } SetZero(); @@ -1271,7 +1371,7 @@ public: private: -#ifdef CONSTANTSGENERATOR +#ifdef TTMATH_CONSTANTSGENERATOR public: #endif @@ -1299,7 +1399,7 @@ public: old_value = *this; // we begin from 1 in order to not testing at the beginning - #ifdef CONSTANTSGENERATOR + #ifdef TTMATH_CONSTANTSGENERATOR for(i=1 ; true ; ++i) #else for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) @@ -1360,6 +1460,9 @@ public: { uint c = 0; + if( x.IsNan() ) + return CheckCarry(1); + if( x.IsZero() ) { SetOne(); @@ -1412,7 +1515,7 @@ public: c += PowUInt(e_); } - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -1420,7 +1523,7 @@ public: private: -#ifdef CONSTANTSGENERATOR +#ifdef TTMATH_CONSTANTSGENERATOR public: #endif @@ -1462,7 +1565,7 @@ public: uint i; - #ifdef CONSTANTSGENERATOR + #ifdef TTMATH_CONSTANTSGENERATOR for(i=1 ; true ; ++i) #else // we begin from 1 in order to not testing at the beginning @@ -1525,15 +1628,21 @@ public: return values: 0 - ok - 1 - overflow + 1 - overflow (carry) 2 - incorrect argument (x<=0) */ uint Ln(const Big & x) { TTMATH_REFERENCE_ASSERT( x ) + if( x.IsNan() ) + return CheckCarry(1); + if( x.IsSign() || x.IsZero() ) + { + SetNan(); return 2; + } // m will be the value of the mantissa in range <1,2) Big m(x); @@ -1552,7 +1661,7 @@ public: c += exponent_temp.Mul(ln2); c += Add(exponent_temp); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -1574,14 +1683,23 @@ public: TTMATH_REFERENCE_ASSERT( base ) TTMATH_REFERENCE_ASSERT( x ) + if( x.IsNan() || base.IsNan() ) + return CheckCarry(1); + if( x.IsSign() || x.IsZero() ) + { + SetNan(); return 2; + } Big denominator;; denominator.SetOne(); if( base.IsSign() || base.IsZero() || base==denominator ) + { + SetNan(); return 3; + } if( x == denominator ) // (this is: if x == 1) { @@ -1590,14 +1708,14 @@ public: return 0; } - // another error values we've tested at the start - // there can be only a carry + // another error values we've tested at the beginning + // there can only be a carry uint c = Ln(x); c += denominator.Ln(base); c += Div(denominator); - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -1618,9 +1736,15 @@ public: { info = another.info; - if( exponent.FromInt(another.exponent) ) + if( IsNan() ) return 1; + if( exponent.FromInt(another.exponent) ) + { + SetNan(); + return 1; + } + uint man_len_min = (man < another_man)? man : another_man; uint i; uint c = 0; @@ -1634,7 +1758,7 @@ public: // MS Visual Express 2005 reports a warning (in the lines with 'uint man_diff = ...'): // warning C4307: '*' : integral constant overflow - // but we're using 'if( man > another_man )' and 'if( man < another_man )' and there'll be no such a situation here + // but we're using 'if( man > another_man )' and 'if( man < another_man )' and there'll be no such situation here #ifndef __GNUC__ #pragma warning( disable: 4307 ) #endif @@ -1658,7 +1782,7 @@ public: // mantissa doesn't have to be standardized (either the highest bit is set or all bits are equal zero) CorrectZero(); - return (c == 0 )? 0 : 1; + return CheckCarry(c); } @@ -2467,13 +2591,16 @@ public: FromBig(value); } + /*! a default constructor - warning: we don't set any of the members to zero etc. + we don't set any of the members to zero + only NaN flag is set */ Big() { + SetNan(); } @@ -2566,8 +2693,15 @@ public: tchar_t decimal_point = TTMATH_COMMA_CHARACTER_1 ) const { static tchar_t error_overflow_msg[] = TTMATH_TEXT("overflow"); + static char error_nan_msg[] = "NaN"; result.erase(); + if( IsNan() ) + { + result = error_nan_msg; + return 0; + } + if(base<2 || base>16) { result = error_overflow_msg; @@ -3263,6 +3397,8 @@ public: if( base<2 || base>16 ) { + SetNan(); + if( after_source ) *after_source = source; @@ -3292,7 +3428,7 @@ public: if( value_read ) *value_read = value_read_temp; - return (c==0)? 0 : 1; + return CheckCarry(c); } @@ -3593,6 +3729,7 @@ public: and returns the result (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag */ bool SmallerWithoutSignThan(const Big & ss2) const { @@ -3627,6 +3764,7 @@ public: and returns the result (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag */ bool GreaterWithoutSignThan(const Big & ss2) const { @@ -3661,6 +3799,7 @@ public: and returns the result (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag */ bool EqualWithoutSign(const Big & ss2) const { @@ -3867,7 +4006,7 @@ public: */ void SkipFraction() { - if( IsZero() ) + if( IsNan() || IsZero() ) return; if( !exponent.IsSign() ) @@ -3901,7 +4040,7 @@ public: */ void RemainFraction() { - if( IsZero() ) + if( IsNan() || IsZero() ) return; if( !exponent.IsSign() ) @@ -3951,6 +4090,9 @@ public: Big half; uint c; + if( IsNan() ) + return 1; + half.Set05(); if( IsSign() ) @@ -3966,7 +4108,7 @@ public: SkipFraction(); - return c; + return CheckCarry(c); } diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h index 9c18bc9..bf3845e 100644 --- a/ttmath/ttmathuint.h +++ b/ttmath/ttmathuint.h @@ -971,8 +971,9 @@ public: Mul2Big(ss2, result); // copying result - for(i=0 ; i