fixed: Sqrt(), Root() and Factorial() didn't correctly treat the NaN flag

fixed: some methods should set 'err_improper_argument' when the argument is a NaN object
       (was: err_overflow)
changed: version of the library: 0.8.5 now



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@163 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2009-06-16 18:31:39 +00:00
parent 019a902fed
commit 8972fdfdb3
3 changed files with 228 additions and 19 deletions

View File

@ -102,6 +102,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
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
}
ValueType result( x ); ValueType result( x );
uint c = result.Round(); uint c = result.Round();
@ -127,6 +135,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Ceil(const ValueType & x, ErrorCode * err = 0) ValueType Ceil(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType result(x); ValueType result(x);
uint c = 0; uint c = 0;
@ -166,6 +182,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Floor(const ValueType & x, ErrorCode * err = 0) ValueType Floor(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType result(x); ValueType result(x);
uint c = 0; uint c = 0;
@ -206,8 +230,15 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Ln(const ValueType & x, ErrorCode * err = 0) ValueType Ln(const ValueType & x, ErrorCode * err = 0)
{ {
ValueType result; if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType result;
uint state = result.Ln(x); uint state = result.Ln(x);
if( err ) if( err )
@ -240,8 +271,15 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0) ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0)
{ {
ValueType result; if( x.IsNan() || base.IsNan() )
{
if( err )
*err = err_improper_argument;
return ValueType(); // default NaN
}
ValueType result;
uint state = result.Log(x, base); uint state = result.Log(x, base);
if( err ) if( err )
@ -274,8 +312,15 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Exp(const ValueType & x, ErrorCode * err = 0) ValueType Exp(const ValueType & x, ErrorCode * err = 0)
{ {
ValueType result; if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType result;
uint c = result.Exp(x); uint c = result.Exp(x);
if( err ) if( err )
@ -471,6 +516,14 @@ namespace ttmath
ValueType one, result; ValueType one, result;
bool change_sign; bool change_sign;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
if( err ) if( err )
*err = err_ok; *err = err_ok;
@ -482,7 +535,7 @@ namespace ttmath
// result has NaN flag set by default // result has NaN flag set by default
if( err ) if( err )
*err = err_overflow; // maybe another error code? *err = err_overflow; // maybe another error code? err_improper_argument?
return result; // NaN is set by default return result; // NaN is set by default
} }
@ -514,6 +567,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
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
}
ValueType pi05; ValueType pi05;
pi05.Set05Pi(); pi05.Set05Pi();
@ -786,6 +847,14 @@ namespace ttmath
one.SetOne(); one.SetOne();
bool change_sign = false; bool change_sign = false;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
if( x.GreaterWithoutSignThan(one) ) if( x.GreaterWithoutSignThan(one) )
{ {
if( err ) if( err )
@ -830,7 +899,7 @@ namespace ttmath
ValueType temp; ValueType temp;
temp.Set05Pi(); temp.Set05Pi();
temp.Sub(ASin(x,err)); temp.Sub(ASin(x, err));
return temp; return temp;
} }
@ -1008,6 +1077,9 @@ namespace ttmath
one.SetOne(); one.SetOne();
bool change_sign = false; bool change_sign = false;
if( x.IsNan() )
return result; // NaN is set by default
// if x is negative we're using the formula: // if x is negative we're using the formula:
// atan(-x) = -atan(x) // atan(-x) = -atan(x)
if( x.IsSign() ) if( x.IsSign() )
@ -1088,6 +1160,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Sinh(const ValueType & x, ErrorCode * err = 0) ValueType Sinh(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType ex, emx; ValueType ex, emx;
uint c = 0; uint c = 0;
@ -1112,6 +1192,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Cosh(const ValueType & x, ErrorCode * err = 0) ValueType Cosh(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType ex, emx; ValueType ex, emx;
uint c = 0; uint c = 0;
@ -1136,6 +1224,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Tanh(const ValueType & x, ErrorCode * err = 0) ValueType Tanh(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType ex, emx, nominator, denominator; ValueType ex, emx, nominator, denominator;
uint c = 0; uint c = 0;
@ -1176,6 +1272,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Coth(const ValueType & x, ErrorCode * err = 0) ValueType Coth(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
if( x.IsZero() ) if( x.IsZero() )
{ {
if( err ) if( err )
@ -1233,6 +1337,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType ASinh(const ValueType & x, ErrorCode * err = 0) ValueType ASinh(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType xx(x), one, result; ValueType xx(x), one, result;
uint c = 0; uint c = 0;
one.SetOne(); one.SetOne();
@ -1261,6 +1373,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType ACosh(const ValueType & x, ErrorCode * err = 0) ValueType ACosh(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType xx(x), one, result; ValueType xx(x), one, result;
uint c = 0; uint c = 0;
one.SetOne(); one.SetOne();
@ -1302,6 +1422,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType ATanh(const ValueType & x, ErrorCode * err = 0) ValueType ATanh(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType nominator(x), denominator, one, result; ValueType nominator(x), denominator, one, result;
uint c = 0; uint c = 0;
one.SetOne(); one.SetOne();
@ -1347,6 +1475,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType ACoth(const ValueType & x, ErrorCode * err = 0) ValueType ACoth(const ValueType & x, ErrorCode * err = 0)
{ {
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return x; // NaN
}
ValueType nominator(x), denominator(x), one, result; ValueType nominator(x), denominator(x), one, result;
uint c = 0; uint c = 0;
one.SetOne(); one.SetOne();
@ -1405,6 +1541,14 @@ namespace ttmath
ValueType result, temp; ValueType result, temp;
uint c = 0; uint c = 0;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
result = x; result = x;
// it is better to make division first and then multiplication // it is better to make division first and then multiplication
@ -1433,6 +1577,14 @@ namespace ttmath
ValueType result, delimiter; ValueType result, delimiter;
uint c = 0; uint c = 0;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
result = 180; result = 180;
c += result.Mul(x); c += result.Mul(x);
@ -1470,12 +1622,12 @@ namespace ttmath
ValueType delimiter, multipler; ValueType delimiter, multipler;
uint c = 0; uint c = 0;
if( m.IsSign() || s.IsSign() ) if( d.IsNan() || m.IsNan() || s.IsNan() || m.IsSign() || s.IsSign() )
{ {
if( err ) if( err )
*err = err_improper_argument; *err = err_improper_argument;
return delimiter; // NaN is set by default return delimiter ; // NaN is set by default
} }
multipler = 60; multipler = 60;
@ -1524,6 +1676,14 @@ namespace ttmath
ValueType result, temp; ValueType result, temp;
uint c = 0; uint c = 0;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
result = x; result = x;
// it is better to make division first and then multiplication // it is better to make division first and then multiplication
@ -1552,6 +1712,14 @@ namespace ttmath
ValueType result, delimiter; ValueType result, delimiter;
uint c = 0; uint c = 0;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
result = 200; result = 200;
c += result.Mul(x); c += result.Mul(x);
@ -1576,6 +1744,14 @@ namespace ttmath
ValueType result, temp; ValueType result, temp;
uint c = 0; uint c = 0;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
result = x; result = x;
temp = 200; temp = 200;
@ -1618,6 +1794,14 @@ namespace ttmath
ValueType result, temp; ValueType result, temp;
uint c = 0; uint c = 0;
if( x.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
result = x; result = x;
temp = 180; temp = 180;
@ -1651,7 +1835,7 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Sqrt(ValueType x, ErrorCode * err = 0) ValueType Sqrt(ValueType x, ErrorCode * err = 0)
{ {
if( x.IsSign() ) if( x.IsNan() || x.IsSign() )
{ {
if( err ) if( err )
*err = err_improper_argument; *err = err_improper_argument;
@ -1847,6 +2031,14 @@ namespace ttmath
{ {
using namespace auxiliaryfunctions; using namespace auxiliaryfunctions;
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( RootCheckIndexSign(x, index, err) ) return x;
if( RootCheckIndexZero(x, index, err) ) return x; if( RootCheckIndexZero(x, index, err) ) return x;
if( RootCheckIndexOne ( index, err) ) return x; if( RootCheckIndexOne ( index, err) ) return x;
@ -1980,18 +2172,16 @@ namespace ttmath
static History<ValueType> history; static History<ValueType> history;
ValueType result; ValueType result;
result.SetOne(); if( x.IsNan() || x.IsSign() )
if( x.IsSign() )
{ {
if( err ) if( err )
*err = err_improper_argument; *err = err_improper_argument;
result.SetNan(); return result; // NaN set by default
return result;
} }
result.SetOne();
if( !x.exponent.IsSign() && !x.exponent.IsZero() ) if( !x.exponent.IsSign() && !x.exponent.IsZero() )
{ {
// when x.exponent>0 there's no sense to calculate the formula // when x.exponent>0 there's no sense to calculate the formula
@ -2075,6 +2265,14 @@ namespace ttmath
template<class ValueType> template<class ValueType>
ValueType Mod(ValueType a, const ValueType & b, ErrorCode * err = 0) 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); uint c = a.Mod(b);
if( err ) if( err )
@ -2097,6 +2295,7 @@ namespace ttmath
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning( default: 4127 ) #pragma warning( default: 4127 )
//warning C4127: conditional expression is constant
#endif #endif
#endif #endif

View File

@ -139,9 +139,8 @@ public:
return 0; return 0;
uint comp = mantissa.CompensationToLeft(); uint comp = mantissa.CompensationToLeft();
uint c = exponent.Sub( comp );
return CheckCarry(c); return exponent.Sub( comp );
} }
@ -536,6 +535,7 @@ public:
/* /*
we only have to test the mantissa we only have to test the mantissa
also we don't check the NaN flag also we don't check the NaN flag
(maybe this method should return false if there is NaN flag set?)
*/ */
return mantissa.IsZero(); return mantissa.IsZero();
} }
@ -583,6 +583,7 @@ public:
*/ */
void Sgn() void Sgn()
{ {
// we have to check the NaN flag, because the next SetOne() method would clear it
if( IsNan() ) if( IsNan() )
return; return;
@ -618,6 +619,7 @@ public:
/*! /*!
this method changes the sign this method changes the sign
when there is a value of zero then the sign is not changed
e.g. e.g.
-1 -> 1 -1 -> 1
@ -625,6 +627,8 @@ public:
*/ */
void ChangeSign() void ChangeSign()
{ {
// we don't have to check the NaN flag here
if( info & TTMATH_BIG_SIGN ) if( info & TTMATH_BIG_SIGN )
{ {
info &= ~TTMATH_BIG_SIGN; info &= ~TTMATH_BIG_SIGN;
@ -2627,7 +2631,12 @@ public:
*/ */
Big() Big()
{ {
SetNan(); info = TTMATH_BIG_NAN;
/*
we're directly setting 'info' (instead of calling SetNan())
in order to get rid of a warning saying that 'info' is uninitialized
*/
} }
@ -2697,7 +2706,8 @@ public:
output: output:
return value: return value:
0 - ok and 'result' will be an object of type std::string which holds the value 0 - ok and 'result' will be an object of type std::string which holds the value
1 - if there was a carry 1 - if there was a carry (shoudn't be in a normal situation - if is that means there
is somewhere an error in the library)
*/ */
uint ToString( std::string & result, uint ToString( std::string & result,
uint base = 10, uint base = 10,

View File

@ -65,7 +65,7 @@
#define TTMATH_MAJOR_VER 0 #define TTMATH_MAJOR_VER 0
#define TTMATH_MINOR_VER 8 #define TTMATH_MINOR_VER 8
#define TTMATH_REVISION_VER 5 #define TTMATH_REVISION_VER 5
#define TTMATH_PRERELEASE_VER 1 #define TTMATH_PRERELEASE_VER 0
/*! /*!