changed: algorithms in Big::Sqrt() and ttmath::Root(x ; n)
they were not too much accurate for some integers e.g. Root(16;4) returned a value very closed to 2 (not exactly 2) git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@231 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
parent
4f1763d773
commit
4b4b30392a
|
@ -45,12 +45,16 @@ Version 0.9.0 prerelease (2009.11.01):
|
||||||
uint FromString(const std::string & string, const Conv & conv, const wchar_t **, bool *)
|
uint FromString(const std::string & string, const Conv & conv, const wchar_t **, bool *)
|
||||||
uint FromString(const std::wstring & string, const Conv & conv, const wchar_t **, bool *)
|
uint FromString(const std::wstring & string, const Conv & conv, const wchar_t **, bool *)
|
||||||
* added: UInt::Sqrt() - a new algorithm for calculating the square root
|
* added: UInt::Sqrt() - a new algorithm for calculating the square root
|
||||||
* added: to the parser: function frac() - remains fraction
|
* added: to the parser: function frac() - returns a value without the integer part
|
||||||
|
(only fraction remains)
|
||||||
* changed: Factorial() is using the Gamma() function now
|
* changed: Factorial() is using the Gamma() function now
|
||||||
* changed: Big::Div(ss2)
|
* changed: Big::Div(ss2)
|
||||||
Big::Mod(ss2)
|
Big::Mod(ss2)
|
||||||
they return 2 when ss2 is zero
|
they return 2 when ss2 is zero
|
||||||
previously returned 1
|
previously returned 1
|
||||||
|
* changed: algorithms in Big::Sqrt() and ttmath::Root(x ; n)
|
||||||
|
they were not too much accurate for some integers
|
||||||
|
e.g. Root(16;4) returned a value very closed to 2 (not exactly 2)
|
||||||
* 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
|
||||||
|
|
304
ttmath/ttmath.h
304
ttmath/ttmath.h
|
@ -1856,146 +1856,189 @@ namespace ttmath
|
||||||
namespace auxiliaryfunctions
|
namespace auxiliaryfunctions
|
||||||
{
|
{
|
||||||
|
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
bool RootCheckIndexSign(ValueType & x, const ValueType & index, ErrorCode * err)
|
bool RootCheckIndexSign(ValueType & x, const ValueType & index, ErrorCode * err)
|
||||||
|
{
|
||||||
|
if( index.IsSign() )
|
||||||
{
|
{
|
||||||
if( index.IsSign() )
|
// index cannot be negative
|
||||||
{
|
if( err )
|
||||||
// index cannot be negative
|
*err = err_improper_argument;
|
||||||
if( err )
|
|
||||||
*err = err_improper_argument;
|
|
||||||
|
|
||||||
x.SetNan();
|
x.SetNan();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
template<class ValueType>
|
}
|
||||||
bool RootCheckIndexZero(ValueType & x, const ValueType & index, ErrorCode * err)
|
|
||||||
{
|
|
||||||
if( index.IsZero() )
|
|
||||||
{
|
|
||||||
if( x.IsZero() )
|
|
||||||
{
|
|
||||||
// there isn't root(0;0) - we assume it's not defined
|
|
||||||
if( err )
|
|
||||||
*err = err_improper_argument;
|
|
||||||
|
|
||||||
x.SetNan();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// root(x;0) is 1 (if x!=0)
|
|
||||||
x.SetOne();
|
|
||||||
|
|
||||||
if( err )
|
|
||||||
*err = err_ok;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class ValueType>
|
template<class ValueType>
|
||||||
bool RootCheckIndexOne(const ValueType & index, ErrorCode * err)
|
bool RootCheckIndexZero(ValueType & x, const ValueType & index, ErrorCode * err)
|
||||||
{
|
{
|
||||||
ValueType one;
|
if( index.IsZero() )
|
||||||
one.SetOne();
|
|
||||||
|
|
||||||
if( index == one )
|
|
||||||
{
|
|
||||||
//root(x;1) is x
|
|
||||||
// we do it because if we used the PowFrac function
|
|
||||||
// we would lose the precision
|
|
||||||
if( err )
|
|
||||||
*err = err_ok;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
bool RootCheckIndexFrac(ValueType & x, const ValueType & index, ErrorCode * err)
|
|
||||||
{
|
|
||||||
if( !index.IsInteger() )
|
|
||||||
{
|
|
||||||
// index must be integer
|
|
||||||
if( err )
|
|
||||||
*err = err_improper_argument;
|
|
||||||
|
|
||||||
x.SetNan();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<class ValueType>
|
|
||||||
bool RootCheckXZero(ValueType & x, ErrorCode * err)
|
|
||||||
{
|
{
|
||||||
if( x.IsZero() )
|
if( x.IsZero() )
|
||||||
{
|
{
|
||||||
// root(0;index) is zero (if index!=0)
|
// there isn't root(0;0) - we assume it's not defined
|
||||||
// RootCheckIndexZero() must be called beforehand
|
|
||||||
x.SetZero();
|
|
||||||
|
|
||||||
if( err )
|
if( err )
|
||||||
*err = err_ok;
|
*err = err_improper_argument;
|
||||||
|
|
||||||
|
x.SetNan();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// root(x;0) is 1 (if x!=0)
|
||||||
|
x.SetOne();
|
||||||
|
|
||||||
return false;
|
if( err )
|
||||||
}
|
*err = err_ok;
|
||||||
|
|
||||||
|
return true;
|
||||||
template<class ValueType>
|
|
||||||
bool RootCheckIndex(ValueType & x, const ValueType & index, ErrorCode * err, bool * change_sign)
|
|
||||||
{
|
|
||||||
*change_sign = false;
|
|
||||||
|
|
||||||
if( index.Mod2() )
|
|
||||||
{
|
|
||||||
// index is odd (1,3,5...)
|
|
||||||
if( x.IsSign() )
|
|
||||||
{
|
|
||||||
*change_sign = true;
|
|
||||||
x.Abs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// index is even
|
|
||||||
// x cannot be negative
|
|
||||||
if( x.IsSign() )
|
|
||||||
{
|
|
||||||
if( err )
|
|
||||||
*err = err_improper_argument;
|
|
||||||
|
|
||||||
x.SetNan();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
bool RootCheckIndexOne(const ValueType & index, ErrorCode * err)
|
||||||
|
{
|
||||||
|
ValueType one;
|
||||||
|
one.SetOne();
|
||||||
|
|
||||||
|
if( index == one )
|
||||||
|
{
|
||||||
|
//root(x;1) is x
|
||||||
|
// we do it because if we used the PowFrac function
|
||||||
|
// we would lose the precision
|
||||||
|
if( err )
|
||||||
|
*err = err_ok;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
bool RootCheckIndexTwo(ValueType & x, const ValueType & index, ErrorCode * err)
|
||||||
|
{
|
||||||
|
if( index == 2 )
|
||||||
|
{
|
||||||
|
x = Sqrt(x, err);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
bool RootCheckIndexFrac(ValueType & x, const ValueType & index, ErrorCode * err)
|
||||||
|
{
|
||||||
|
if( !index.IsInteger() )
|
||||||
|
{
|
||||||
|
// index must be integer
|
||||||
|
if( err )
|
||||||
|
*err = err_improper_argument;
|
||||||
|
|
||||||
|
x.SetNan();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
bool RootCheckXZero(ValueType & x, ErrorCode * err)
|
||||||
|
{
|
||||||
|
if( x.IsZero() )
|
||||||
|
{
|
||||||
|
// root(0;index) is zero (if index!=0)
|
||||||
|
// RootCheckIndexZero() must be called beforehand
|
||||||
|
x.SetZero();
|
||||||
|
|
||||||
|
if( err )
|
||||||
|
*err = err_ok;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
bool RootCheckIndex(ValueType & x, const ValueType & index, ErrorCode * err, bool * change_sign)
|
||||||
|
{
|
||||||
|
*change_sign = false;
|
||||||
|
|
||||||
|
if( index.Mod2() )
|
||||||
|
{
|
||||||
|
// index is odd (1,3,5...)
|
||||||
|
if( x.IsSign() )
|
||||||
|
{
|
||||||
|
*change_sign = true;
|
||||||
|
x.Abs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// index is even
|
||||||
|
// x cannot be negative
|
||||||
|
if( x.IsSign() )
|
||||||
|
{
|
||||||
|
if( err )
|
||||||
|
*err = err_improper_argument;
|
||||||
|
|
||||||
|
x.SetNan();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<class ValueType>
|
||||||
|
uint RootCorrectInteger(ValueType & old_x, ValueType & x, const ValueType & index)
|
||||||
|
{
|
||||||
|
if( !old_x.IsInteger() || x.IsInteger() || !index.exponent.IsSign() )
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// old_x is integer,
|
||||||
|
// x is not integer,
|
||||||
|
// index is relatively small (index.exponent<0 or index.exponent<=0)
|
||||||
|
// (because we're using a special powering algorithm Big::PowUInt())
|
||||||
|
|
||||||
|
uint c = 0;
|
||||||
|
|
||||||
|
ValueType temp(x);
|
||||||
|
c += temp.Round();
|
||||||
|
|
||||||
|
ValueType temp_round(temp);
|
||||||
|
c += temp.PowUInt(index);
|
||||||
|
|
||||||
|
if( temp == old_x )
|
||||||
|
x = temp_round;
|
||||||
|
|
||||||
|
return (c==0)? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace auxiliaryfunctions
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
indexth Root of x
|
indexth Root of x
|
||||||
index must be integer and not negative <0;1;2;3....)
|
index must be integer and not negative <0;1;2;3....)
|
||||||
|
@ -2026,30 +2069,33 @@ namespace ttmath
|
||||||
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;
|
||||||
|
if( RootCheckIndexTwo (x, index, err) ) return x;
|
||||||
if( RootCheckIndexFrac(x, 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
|
// index integer and index!=0
|
||||||
// x!=0
|
// x!=0
|
||||||
|
|
||||||
uint c = 0;
|
ValueType old_x(x);
|
||||||
bool change_sign;
|
bool change_sign;
|
||||||
|
|
||||||
if( RootCheckIndex(x, index, err, &change_sign ) ) return x;
|
if( RootCheckIndex(x, index, err, &change_sign ) ) return x;
|
||||||
|
|
||||||
ValueType newindex;
|
ValueType temp;
|
||||||
newindex.SetOne();
|
uint c = 0;
|
||||||
c += newindex.Div(index);
|
|
||||||
c += x.PowFrac(newindex); // here can only be a carry
|
// we're using the formula: root(x ; n) = exp( ln(x) / n )
|
||||||
|
c += temp.Ln(x);
|
||||||
|
c += temp.Div(index);
|
||||||
|
c += x.Exp(temp);
|
||||||
|
|
||||||
if( change_sign )
|
if( change_sign )
|
||||||
{
|
{
|
||||||
// the value of x should be different from zero
|
// x is different from zero
|
||||||
// (x is actually tested by RootCheckXZero)
|
|
||||||
TTMATH_ASSERT( x.IsZero() == false )
|
|
||||||
|
|
||||||
x.SetSign();
|
x.SetSign();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c += RootCorrectInteger(old_x, x, index);
|
||||||
|
|
||||||
if( err )
|
if( err )
|
||||||
*err = c ? err_overflow : err_ok;
|
*err = c ? err_overflow : err_ok;
|
||||||
|
|
|
@ -1511,8 +1511,7 @@ public:
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
this function calculates the square root
|
this function calculates the square root
|
||||||
|
e.g. let this=9 then this.Sqrt() gives 3
|
||||||
Sqrt(9) = 3
|
|
||||||
|
|
||||||
return: 0 - ok
|
return: 0 - ok
|
||||||
1 - carry
|
1 - carry
|
||||||
|
@ -1529,11 +1528,33 @@ public:
|
||||||
if( IsZero() )
|
if( IsZero() )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
Big<exp, man> pow;
|
Big<exp, man> old(*this);
|
||||||
pow.Set05();
|
Big<exp, man> ln;
|
||||||
|
uint c = 0;
|
||||||
|
|
||||||
// PowFrac can return only a carry because x is greater than zero
|
// we're using the formula: sqrt(x) = e ^ (ln(x) / 2)
|
||||||
return PowFrac(pow);
|
c += ln.Ln(*this);
|
||||||
|
c += ln.exponent.SubOne(); // ln = ln / 2
|
||||||
|
c += Exp(ln);
|
||||||
|
|
||||||
|
// above formula doesn't give accurate results for some integers
|
||||||
|
// e.g. Sqrt(81) would not be 9 but a value very closed to 9
|
||||||
|
// we're rounding the result, calculating result*result and comparing
|
||||||
|
// with the old value, if they are equal then the result is an integer too
|
||||||
|
|
||||||
|
if( !c && old.IsInteger() && !IsInteger() )
|
||||||
|
{
|
||||||
|
Big<exp, man> temp(*this);
|
||||||
|
c += temp.Round();
|
||||||
|
|
||||||
|
Big<exp, man> temp2(temp);
|
||||||
|
c += temp.Mul(temp2);
|
||||||
|
|
||||||
|
if( temp == old )
|
||||||
|
*this = temp2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CheckCarry(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue