Browse Source

- update to current root trunc's version

- update to root trunc's UNICODE support

git-svn-id: svn://ttmath.org/publicrep/ttmath/branches/chk@182 e52654a7-88a9-db11-a3e9-0013d4bc506e
chk
Christian Kaiser 13 years ago
parent
commit
51e938eaa7
  1. 25
      CHANGELOG
  2. 727
      ttmath/ttmath.h
  3. 181
      ttmath/ttmathbig.h
  4. 20
      ttmath/ttmathconfig.h
  5. 45
      ttmath/ttmathint.h
  6. 143
      ttmath/ttmathobjects.h
  7. 331
      ttmath/ttmathparser.h
  8. 106
      ttmath/ttmathtypes.h
  9. 85
      ttmath/ttmathuint.h
  10. 1894
      ttmath/ttmathuint_noasm.h
  11. 6
      ttmath/ttmathuint_x86.h
  12. 103
      ttmath/ttmathuint_x86_64.h

25
CHANGELOG

@ -1,3 +1,28 @@
Version 0.9.0 prerelease (2009.07.16):
* added: support for wide characters (wchar_t)
wide characters are used when macro TTMATH_USE_WCHAR is defined
this macro is defined automatically when there is macro UNICODE or _UNICODE defined
some types have been changed
char -> tt_char
std::string -> tt_string
std::ostringstream -> tt_ostringstream
std::ostream -> tt_ostream
std::istream -> tt_istream
normally tt_char is equal char but when you are using wide characters then tt_char will be wchar_t (and so on)
(all typedef's are in ttmathtypes.h)
* added: Big::IsInteger()
returns true if the value is integer (without fraction)
(NaN flag is not checked)
* added: global Gamma() function
* added: gamma() function to the parser
* added: CGamma<ValueType> class
is used with Gamma() and Factorial() in multithreaded environment
* changed: Factorial() is using the Gamma() function now
* removed: Parser<>::SetFactorialMax() method
the factorial() is such a fast now that we don't need the method longer
* removed: ErrorCode::err_too_big_factorial
Version 0.8.5 (2009.06.16):
* fixed: Big::Mod(x) didn't correctly return a carry
and the result was sometimes very big (even greater than x)

727
ttmath/ttmath.h

@ -1,7 +1,7 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
@ -45,12 +45,14 @@
\brief Mathematics functions.
*/
#include "ttmathconfig.h"
#ifdef _MSC_VER
//warning C4127: conditional expression is constant
#pragma warning( disable: 4127 )
#endif
#include "ttmathbig.h"
#include "ttmathobjects.h"
#include <string>
namespace ttmath
{
@ -72,7 +74,7 @@ namespace ttmath
/*!
this method skips the fraction from x
this function skips the fraction from x
e.g 2.2 = 2
2.7 = 2
-2.2 = 2
@ -89,7 +91,7 @@ namespace ttmath
/*!
this method rounds to the nearest integer value
this function rounds to the nearest integer value
e.g 2.2 = 2
2.7 = 3
-2.2 = -2
@ -221,7 +223,7 @@ namespace ttmath
/*!
this method calculates the natural logarithm (logarithm with the base 'e')
this function calculates the natural logarithm (logarithm with the base 'e')
*/
template<class ValueType>
ValueType Ln(const ValueType & x, ErrorCode * err = 0)
@ -262,7 +264,7 @@ namespace ttmath
/*!
this method calculates the logarithm
this function calculates the logarithm
*/
template<class ValueType>
ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0)
@ -303,7 +305,7 @@ namespace ttmath
/*!
this method calculates the expression e^x
this function calculates the expression e^x
*/
template<class ValueType>
ValueType Exp(const ValueType & x, ErrorCode * err = 0)
@ -1936,10 +1938,7 @@ namespace ttmath
template<class ValueType>
bool RootCheckIndexFrac(ValueType & x, const ValueType & index, ErrorCode * err)
{
ValueType indexfrac(index);
indexfrac.RemainFraction();
if( !indexfrac.IsZero() )
if( !index.IsInteger() )
{
// index must be integer
if( err )
@ -2071,212 +2070,709 @@ namespace ttmath
/*!
absolute value of x
e.g. -2 = 2
2 = 2
*/
template<class ValueType>
ValueType Abs(const ValueType & x)
{
ValueType result( x );
result.Abs();
return result;
}
/*!
it returns the sign of the value
e.g. -2 = -1
0 = 0
10 = 1
*/
template<class ValueType>
ValueType Sgn(ValueType x)
{
x.Sgn();
return x;
}
/*!
the remainder from a division
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
mod(-12.6 ; -3) = -0.6
*/
template<class ValueType>
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;
}
namespace auxiliaryfunctions
{
/*!
this function is used to store factorials in a given container
'more' means how many values should be added at the end
e.g.
std::vector<ValueType> fact;
SetFactorialSequence(fact, 3);
// now the container has three values: 1 1 2
SetFactorialSequence(fact, 2);
// now the container has five values: 1 1 2 6 24
*/
template<class ValueType>
uint FactorialInt( const ValueType & x, ErrorCode * err,
const volatile StopCalculating * stop,
ValueType & result)
void SetFactorialSequence(std::vector<ValueType> & fact, uint more = 20)
{
uint maxvalue = TTMATH_UINT_MAX_VALUE;
if( more == 0 )
more = 1;
if( x < TTMATH_UINT_MAX_VALUE )
x.ToUInt(maxvalue);
uint start = static_cast<uint>(fact.size());
fact.resize(fact.size() + more);
uint multipler = 1;
uint carry = 0;
if( start == 0 )
{
fact[0] = 1;
++start;
}
while( !carry && multipler<maxvalue )
for(uint i=start ; i<fact.size() ; ++i)
{
if( stop && (multipler & 127)==0 ) // it means 'stop && (multipler % 128)==0'
fact[i] = fact[i-1];
fact[i].MulInt(i);
}
}
/*!
an auxiliary function used to calculate Bernoulli numbers
this function returns a sum:
sum(m) = sum_{k=0}^{m-1} {2^k * (m k) * B(k)} k in [0, m-1] (m k) means binomial coefficient = (m! / (k! * (m-k)!))
you should have sufficient factorials in cgamma.fact
(cgamma.fact should have at least m items)
n_ should be equal 2
*/
template<class ValueType>
ValueType SetBernoulliNumbersSum(CGamma<ValueType> & cgamma, const ValueType & n_, uint m,
const volatile StopCalculating * stop = 0)
{
// after each 128 iterations we make a test
ValueType k_, temp, temp2, temp3, sum;
sum.SetZero();
for(uint k=0 ; k<m ; ++k) // k<m means k<=m-1
{
if( stop && (k & 15)==0 ) // means: k % 16 == 0
if( stop->WasStopSignal() )
return ValueType(); // NaN
if( k>1 && (k & 1) == 1 ) // for that k the Bernoulli number is zero
continue;
k_ = k;
temp = n_; // n_ is equal 2
temp.Pow(k_);
// temp = 2^k
temp2 = cgamma.fact[m];
temp3 = cgamma.fact[k];
temp3.Mul(cgamma.fact[m-k]);
temp2.Div(temp3);
// temp2 = (m k) = m! / ( k! * (m-k)! )
temp.Mul(temp2);
temp.Mul(cgamma.bern[k]);
sum.Add(temp);
// sum += 2^k * (m k) * B(k)
if( sum.IsNan() )
break;
}
return sum;
}
/*!
an auxiliary function used to calculate Bernoulli numbers
start is >= 2
we use the recurrence formula:
B(m) = 1 / (2*(1 - 2^m)) * sum(m)
where sum(m) is calculated by SetBernoulliNumbersSum()
*/
template<class ValueType>
bool SetBernoulliNumbersMore(CGamma<ValueType> & cgamma, uint start, const volatile StopCalculating * stop = 0)
{
if( err )
*err = err_interrupt;
ValueType denominator, temp, temp2, temp3, m_, sum, sum2, n_, k_;
return 2;
const uint n = 2;
n_ = n;
// start is >= 2
for(uint m=start ; m<cgamma.bern.size() ; ++m)
{
if( (m & 1) == 1 )
{
cgamma.bern[m].SetZero();
}
else
{
m_ = m;
temp = n_; // n_ = 2
temp.Pow(m_);
// temp = 2^m
denominator.SetOne();
denominator.Sub(temp);
if( denominator.exponent.AddOne() ) // it means: denominator.MulInt(2)
denominator.SetNan();
// denominator = 2 * (1 - 2^m)
cgamma.bern[m] = SetBernoulliNumbersSum(cgamma, n_, m, stop);
if( stop && stop->WasStopSignal() )
{
cgamma.bern.resize(m); // valid numbers are in [0, m-1]
return false;
}
++multipler;
carry += result.MulUInt(multipler);
cgamma.bern[m].Div(denominator);
}
}
if( err )
*err = carry ? err_overflow : err_ok;
return true;
}
/*!
this function is used to calculate Bernoulli numbers,
returns false if there was a stop signal,
'more' means how many values should be added at the end
e.g.
typedef Big<1,2> MyBig;
CGamma<MyBig> cgamma;
SetBernoulliNumbers(cgamma, 3);
// now we have three first Bernoulli numbers: 1 -0.5 0.16667
SetBernoulliNumbers(cgamma, 4);
// now we have 7 Bernoulli numbers: 1 -0.5 0.16667 0 -0.0333 0 0.0238
*/
template<class ValueType>
bool SetBernoulliNumbers(CGamma<ValueType> & cgamma, uint more = 20, const volatile StopCalculating * stop = 0)
{
if( more == 0 )
more = 1;
uint start = static_cast<uint>(cgamma.bern.size());
cgamma.bern.resize(cgamma.bern.size() + more);
if( start == 0 )
{
cgamma.bern[0].SetOne();
++start;
}
if( cgamma.bern.size() == 1 )
return true;
if( start == 1 )
{
cgamma.bern[1].Set05();
cgamma.bern[1].ChangeSign();
++start;
}
// we should have sufficient factorials in cgamma.fact
if( cgamma.fact.size() < cgamma.bern.size() )
SetFactorialSequence(cgamma.fact, static_cast<uint>(cgamma.bern.size() - cgamma.fact.size()));
return carry ? 1 : 0;
return SetBernoulliNumbersMore(cgamma, start, stop);
}
/*!
an auxiliary function used to calculate the Gamma() function
we calculate a sum:
sum(n) = sum_{m=2} { B(m) / ( (m^2 - m) * n^(m-1) ) } = 1/(12*n) - 1/(360*n^3) + 1/(1260*n^5) + ...
B(m) means a mth Bernoulli number
the sum starts from m=2, we calculate as long as the value will not change after adding a next part
*/
template<class ValueType>
int FactorialMore( const ValueType & x, ErrorCode * err,
const volatile StopCalculating * stop,
ValueType & result)
ValueType GammaFactorialHighSum(const ValueType & n, CGamma<ValueType> & cgamma, ErrorCode & err,
const volatile StopCalculating * stop)
{
ValueType multipler(TTMATH_UINT_MAX_VALUE);
ValueType one;
ValueType temp, temp2, denominator, sum, oldsum;
one.SetOne();
uint carry = 0;
uint iter = 1; // only for testing the stop object
sum.SetZero();
while( !carry && multipler < x )
for(uint m=2 ; m<TTMATH_ARITHMETIC_MAX_LOOP ; m+=2)
{
if( stop && (iter & 31)==0 ) // it means 'stop && (iter % 32)==0'
{
// after each 32 iterations we make a test
if( stop && (m & 3)==0 ) // (m & 3)==0 means: (m % 4)==0
if( stop->WasStopSignal() )
{
if( err )
*err = err_interrupt;
err = err_interrupt;
return ValueType(); // NaN
}
temp = (m-1);
denominator = n;
denominator.Pow(temp);
// denominator = n ^ (m-1)
return 2;
temp = m;
temp2 = temp;
temp.Mul(temp2);
temp.Sub(temp2);
// temp = m^2 - m
denominator.Mul(temp);
// denominator = (m^2 - m) * n ^ (m-1)
if( m >= cgamma.bern.size() )
{
if( !SetBernoulliNumbers(cgamma, m - cgamma.bern.size() + 1 + 3, stop) ) // 3 more than needed
{
// there was the stop signal
err = err_interrupt;
return ValueType(); // NaN
}
}
carry += multipler.Add(one);
carry += result.Mul(multipler);
++iter;
temp = cgamma.bern[m];
temp.Div(denominator);
oldsum = sum;
sum.Add(temp);
if( sum.IsNan() || oldsum==sum )
break;
}
if( err )
*err = carry ? err_overflow : err_ok;
return sum;
}
return carry ? 1 : 0;
/*!
an auxiliary function used to calculate the Gamma() function
we calculate a helper function GammaFactorialHigh() by using Stirling's series:
n! = (n/e)^n * sqrt(2*pi*n) * exp( sum(n) )
where n is a real number (not only an integer) and is sufficient large (greater than TTMATH_GAMMA_BOUNDARY)
and sum(n) is calculated by GammaFactorialHighSum()
*/
template<class ValueType>
ValueType GammaFactorialHigh(const ValueType & n, CGamma<ValueType> & cgamma, ErrorCode & err,
const volatile StopCalculating * stop)
{
ValueType temp, temp2, temp3, denominator, sum;
temp.Set2Pi();
temp.Mul(n);
temp2 = Sqrt(temp);
// temp2 = sqrt(2*pi*n)
temp = n;
temp3.SetE();
temp.Div(temp3);
temp.Pow(n);
// temp = (n/e)^n
sum = GammaFactorialHighSum(n, cgamma, err, stop);
temp3.Exp(sum);
// temp3 = exp(sum)
temp.Mul(temp2);
temp.Mul(temp3);
return temp;
}
} // namespace
/*!
an auxiliary function used to calculate the Gamma() function
Gamma(x) = GammaFactorialHigh(x-1)
*/
template<class ValueType>
ValueType GammaPlusHigh(ValueType n, CGamma<ValueType> & cgamma, ErrorCode & err, const volatile StopCalculating * stop)
{
ValueType one;
one.SetOne();
n.Sub(one);
return GammaFactorialHigh(n, cgamma, err, stop);
}
/*!
the factorial from given 'x'
an auxiliary function used to calculate the Gamma() function
we use this function when n is integer and a small value (from 0 to TTMATH_GAMMA_BOUNDARY]
we use the formula:
gamma(n) = (n-1)! = 1 * 2 * 3 * ... * (n-1)
*/
template<class ValueType>
ValueType GammaPlusLowIntegerInt(uint n, CGamma<ValueType> & cgamma)
{
TTMATH_ASSERT( n > 0 )
if( n - 1 < static_cast<uint>(cgamma.fact.size()) )
return cgamma.fact[n - 1];
ValueType res;
uint start = 2;
if( cgamma.fact.size() < 2 )
{
res.SetOne();
}
else
{
start = static_cast<uint>(cgamma.fact.size());
res = cgamma.fact[start-1];
}
for(uint i=start ; i<n ; ++i)
res.MulInt(i);
return res;
}
/*!
an auxiliary function used to calculate the Gamma() function
we use this function when n is integer and a small value (from 0 to TTMATH_GAMMA_BOUNDARY]
*/
template<class ValueType>
ValueType GammaPlusLowInteger(const ValueType & n, CGamma<ValueType> & cgamma)
{
sint n_;
n.ToInt(n_);
return GammaPlusLowIntegerInt(n_, cgamma);
}
/*!
an auxiliary function used to calculate the Gamma() function
we use this function when n is a small value (from 0 to TTMATH_GAMMA_BOUNDARY]
we use a recurrence formula:
gamma(z+1) = z * gamma(z)
then: gamma(z) = gamma(z+1) / z
e.g.
Factorial(4) = 4! = 1*2*3*4
gamma(3.89) = gamma(2001.89) / ( 3.89 * 4.89 * 5.89 * ... * 1999.89 * 2000.89 )
*/
template<class ValueType>
ValueType Factorial(const ValueType & x, ErrorCode * err = 0, const volatile StopCalculating * stop = 0)
ValueType GammaPlusLow(ValueType n, CGamma<ValueType> & cgamma, ErrorCode & err, const volatile StopCalculating * stop)
{
using namespace auxiliaryfunctions;
ValueType one, denominator, temp, boundary;
static History<ValueType> history;
ValueType result;
if( n.IsInteger() )
return GammaPlusLowInteger(n, cgamma);
if( x.IsNan() || x.IsSign() )
one.SetOne();
denominator = n;
boundary = TTMATH_GAMMA_BOUNDARY;
while( n < boundary )
{
if( err )
*err = err_improper_argument;
n.Add(one);
denominator.Mul(n);
}
return result; // NaN set by default
n.Add(one);
// now n is sufficient big
temp = GammaPlusHigh(n, cgamma, err, stop);
temp.Div(denominator);
return temp;
}
result.SetOne();
if( !x.exponent.IsSign() && !x.exponent.IsZero() )
/*!
an auxiliary function used to calculate the Gamma() function
*/
template<class ValueType>
ValueType GammaPlus(const ValueType & n, CGamma<ValueType> & cgamma, ErrorCode & err, const volatile StopCalculating * stop)
{
// when x.exponent>0 there's no sense to calculate the formula
// (we can't add one into the x bacause
// we don't have enough bits in the mantissa)
if( err )
*err = err_overflow;
if( n > TTMATH_GAMMA_BOUNDARY )
return GammaPlusHigh(n, cgamma, err, stop);
result.SetNan();
return GammaPlusLow(n, cgamma, err, stop);
}
return result;
/*!
an auxiliary function used to calculate the Gamma() function
this function is used when n is negative
we use the reflection formula:
gamma(1-z) * gamma(z) = pi / sin(pi*z)
then: gamma(z) = pi / (sin(pi*z) * gamma(1-z))
*/
template<class ValueType>
ValueType GammaMinus(const ValueType & n, CGamma<ValueType> & cgamma, ErrorCode & err, const volatile StopCalculating * stop)
{
ValueType pi, denominator, temp, temp2;
if( n.IsInteger() )
{
// gamma function is not defined when n is negative and integer
err = err_improper_argument;
return temp; // NaN
}
ErrorCode err_tmp;
pi.SetPi();
temp = pi;
temp.Mul(n);
temp2 = Sin(temp);
// temp2 = sin(pi * n)
temp.SetOne();
temp.Sub(n);
temp = GammaPlus(temp, cgamma, err, stop);
// temp = gamma(1 - n)
temp.Mul(temp2);
pi.Div(temp);
return pi;
}
} // namespace auxiliaryfunctions
/*!
this function calculates the Gamma function
it's multithread safe, you should create a CGamma<> object and use it whenever you call the Gamma()
e.g.
typedef Big<1,2> MyBig;
MyBig x=234, y=345.53;
CGamma<MyBig> cgamma;
std::cout << Gamma(x, cgamma) << std::endl;
std::cout << Gamma(y, cgamma) << std::endl;
in the CGamma<> object the function stores some coefficients (factorials, Bernoulli numbers),
and they will be reused in next calls to the function
each thread should have its own CGamma<> object, and you can use these objects with Factorial() function too
*/
template<class ValueType>
ValueType Gamma(const ValueType & n, CGamma<ValueType> & cgamma, ErrorCode * err = 0,
const volatile StopCalculating * stop = 0)
{
using namespace auxiliaryfunctions;
ValueType result;
ErrorCode err_tmp;
TTMATH_USE_THREADSAFE_OBJ(history);
if( n.IsNan() )
{
if( err )
*err = err_improper_argument;
return result; // NaN is set by default
}
TTMATH_USE_THREADSAFE_OBJ(cgamma.history);
if( history.Get(x, result, err_tmp) )
if( cgamma.history.Get(n, result, err_tmp) )
{
if( err )
*err = err_tmp;
return result;
}
uint status = FactorialInt(x, err, stop, result);
if( status == 0 )
status = FactorialMore(x, err, stop, result);
err_tmp = err_ok;
if( status == 2 )
if( n.IsSign() )
{
// the calculation has been interrupted
result = GammaMinus(n, cgamma, err_tmp, stop);
}
else
if( n.IsZero() )
{
err_tmp = err_improper_argument;
result.SetNan();
return result;
}
else
{
result = GammaPlus(n, cgamma, err_tmp, stop);
}
err_tmp = status==1 ? err_overflow : err_ok;
history.Add(x, result, err_tmp);
if( result.IsNan() && err_tmp==err_ok )
err_tmp = err_overflow;
if( err )
*err = err_tmp;
if( stop && !stop->WasStopSignal() )
cgamma.history.Add(n, result, err_tmp);
return result;
}
/*!
absolute value of x
e.g. -2 = 2
2 = 2
this function calculates the Gamma function
note: this function should be used only in a single-thread environment
*/
template<class ValueType>
ValueType Abs(const ValueType & x)
ValueType Gamma(const ValueType & n, ErrorCode * err = 0)
{
ValueType result( x );
result.Abs();
// warning: this static object is not thread safe
static CGamma<ValueType> cgamma;
return result;
return Gamma(n, cgamma, err);
}
namespace auxiliaryfunctions
{
/*!
it returns the sign of the value
e.g. -2 = -1
0 = 0
10 = 1
an auxiliary function for calculating the factorial function
we use the formula:
x! = gamma(x+1)
*/
template<class ValueType>
ValueType Sgn(ValueType x)
ValueType Factorial2(ValueType x, CGamma<ValueType> * cgamma = 0, ErrorCode * err = 0,
const volatile StopCalculating * stop = 0)
{
x.Sgn();
ValueType result, one;
return x;
if( x.IsNan() || x.IsSign() || !x.IsInteger() )
{
if( err )
*err = err_improper_argument;
return result; // NaN set by default
}
one.SetOne();
x.Add(one);
if( cgamma )
return Gamma(x, *cgamma, err, stop);
return Gamma(x, err);
}
} // namespace auxiliaryfunctions
/*!
the remainder from a division
the factorial from given 'x'
e.g.
Factorial(4) = 4! = 1*2*3*4
it's multithread safe, you should create a CGamma<> object and use it whenever you call the Factorial()
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
mod(-12.6 ; -3) = -0.6
typedef Big<1,2> MyBig;
MyBig x=234, y=345.53;
CGamma<MyBig> cgamma;
std::cout << Factorial(x, cgamma) << std::endl;
std::cout << Factorial(y, cgamma) << std::endl;
in the CGamma<> object the function stores some coefficients (factorials, Bernoulli numbers),
and they will be reused in next calls to the function
each thread should have its own CGamma<> object, and you can use these objects with Gamma() function too
*/
template<class ValueType>
ValueType Mod(ValueType a, const ValueType & b, ErrorCode * err = 0)
ValueType Factorial(const ValueType & x, CGamma<ValueType> & cgamma, ErrorCode * err = 0,
const volatile StopCalculating * stop = 0)
{
if( a.IsNan() || b.IsNan() )
{
if( err )
*err = err_improper_argument;
return auxiliaryfunctions::Factorial2(x, &cgamma, err, stop);
}
return ValueType(); // NaN is set by default
}
uint c = a.Mod(b);
/*!
the factorial from given 'x'
e.g.
Factorial(4) = 4! = 1*2*3*4
if( err )
*err = c ? err_overflow : err_ok;
note: this function should be used only in a single-thread environment
*/
template<class ValueType>
ValueType Factorial(const ValueType & x, ErrorCode * err = 0)
{
return auxiliaryfunctions::Factorial2(x, 0, err, 0);
}
return a;
/*!
this method prepares some coefficients: factorials and Bernoulli numbers
stored in 'fact' and 'bern' objects
we're defining the method here because we're using Gamma() function which
is not available in ttmathobjects.h
read the doc info in ttmathobjects.h file where CGamma<> struct is declared
*/
template<class ValueType>
void CGamma<ValueType>::InitAll()
{
ValueType x = TTMATH_GAMMA_BOUNDARY + 1;
// history.Remove(x) removes only one object
// we must be sure that there are not others objects with the key 'x'
while( history.Remove(x) )
{
}
// the simplest way to initialize is to call the Gamma function with (TTMATH_GAMMA_BOUNDARY + 1)
// when x is larger then less coefficients we need
Gamma(x, *this);
}
@ -2296,5 +2792,4 @@ namespace ttmath
//warning C4127: conditional expression is constant
#endif
#endif

181
ttmath/ttmathbig.h

@ -1,7 +1,7 @@
/*
* This file is a part of TTMath Bignum Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
* Author: Tomasz Sowa <t.sowa@ttmath.org>
*/
/*
@ -38,6 +38,8 @@
#ifndef headerfilettmathbig
#define headerfilettmathbig
#include "ttmathconfig.h"
/*!
\file ttmathbig.h
\brief A Class for representing floating point numbers
@ -85,7 +87,7 @@ public:
Int<exp> exponent;
UInt<man> mantissa;
tchar_t info;
tt_char info;
/*!
@ -271,7 +273,7 @@ private:
// 3101 digits were taken from this website
// (later the digits were compared with:
// http://www.eveandersson.com/pi/digits/1000000 and http://www.geom.uiuc.edu/~huberty/math5337/groupe/digits.html )
// and they were set into Big<1,400> type (using operator=(const tchar_t*) on a 32bit platform)
// and they were set into Big<1,400> type (using operator=(const tt_char*) on a 32bit platform)
// and then the first 256 words were taken into this table
// (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256,
// and on 64bit platform value 128 (256/2=128))
@ -1369,10 +1371,7 @@ public:
if( pow.exponent>-int(man*TTMATH_BITS_PER_UINT) && pow.exponent<=0 )
{
Big<exp, man> pow_frac( pow );
pow_frac.RemainFraction();
if( pow_frac.IsZero() )
if( pow.IsInteger() )
return PowInt( pow );
}
@ -2718,20 +2717,20 @@ public:
output:
return value:
0 - ok and 'result' will be an object of type tstr_t which holds the value
0 - ok and 'result' will be an object of type std::string (or std::wstring) which holds the value
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( tstr_t & result,
uint ToString( tt_string & result,
uint base = 10,
bool always_scientific = false,
sint when_scientific = 15,
sint max_digit_after_comma = -1,
bool remove_trailing_zeroes = true,
tchar_t decimal_point = TTMATH_COMMA_CHARACTER_1 ) const
tt_char decimal_point = TTMATH_COMMA_CHARACTER_1 ) const
{
static tchar_t error_overflow_msg[] = TTMATH_TEXT("overflow");
static tchar_t error_nan_msg[] = TTMATH_TEXT("NaN");
static tt_char error_overflow_msg[] = TTMATH_TEXT("overflow");
static tt_char error_nan_msg[] = TTMATH_TEXT("NaN");
result.erase();
if( IsNan() )
@ -2748,7 +2747,7 @@ public:
if( IsZero() )
{
result = TTMATH_TEXT("0");
result = '0';
return 0;
}
@ -2873,7 +2872,7 @@ private:
but we need 'new'exp' as integer then we take:
new_exp = [log base (2^exponent)] + 1 <- where [x] means integer value from x
*/
uint ToString_CreateNewMantissaAndExponent( tstr_t & new_man, uint base,
uint ToString_CreateNewMantissaAndExponent( tt_string & new_man, uint base,
Int<exp+1> & new_exp) const
{
uint c = 0;
@ -3057,7 +3056,7 @@ private:
(we can make that speciality when the base is 4,8 or 16 as well
but maybe in further time)
*/
uint ToString_CreateNewMantissaAndExponent_Base2( tstr_t & new_man,
uint ToString_CreateNewMantissaAndExponent_Base2( tt_string & new_man,
Int<exp+1> & new_exp ) const
{
for( sint i=man-1 ; i>=0 ; --i )
@ -3087,13 +3086,13 @@ private:
this method roundes the last character from the new mantissa
(it's used in systems where the base is different from 2)
*/
uint ToString_RoundMantissa(tstr_t & new_man, uint base, Int<exp+1> & new_exp, tchar_t decimal_point) const
uint ToString_RoundMantissa(tt_string & new_man, uint base, Int<exp+1> & new_exp, tt_char decimal_point) const
{
// we must have minimum two characters
if( new_man.length() < 2 )
return 0;
tstr_t::size_type i = new_man.length() - 1;
tt_string::size_type i = new_man.length() - 1;
// we're erasing the last character
uint digit = UInt<man>::CharToDigit( new_man[i] );
@ -3114,7 +3113,7 @@ private:
this method addes one into the new mantissa
*/
void ToString_RoundMantissa_AddOneIntoMantissa(tstr_t & new_man, uint base, tchar_t decimal_point) const
void ToString_RoundMantissa_AddOneIntoMantissa(tt_string & new_man, uint base, tt_char decimal_point) const
{
if( new_man.empty() )
return;
@ -3138,7 +3137,7 @@ private:
else
was_carry = false;
new_man[i] = static_cast<char>( UInt<man>::DigitToChar(digit) );
new_man[i] = static_cast<tt_char>( UInt<man>::DigitToChar(digit) );
}
if( i<0 && was_carry )
@ -3152,13 +3151,13 @@ private:
this method sets the comma operator and/or puts the exponent
into the string
*/
uint ToString_SetCommaAndExponent( tstr_t & new_man, uint base,
uint ToString_SetCommaAndExponent( tt_string & new_man, uint base,
Int<exp+1> & new_exp,
bool always_scientific,
sint when_scientific,
sint max_digit_after_comma,
bool remove_trailing_zeroes,
tchar_t decimal_point) const
tt_char decimal_point) const
{
uint carry = 0;
@ -3198,12 +3197,12 @@ private:
an auxiliary method for converting into the string
*/
void ToString_SetCommaAndExponent_Normal(
tstr_t & new_man,
tt_string & new_man,
uint base,
Int<exp+1> & new_exp,
sint max_digit_after_comma,
bool remove_trailing_zeroes,
tchar_t decimal_point) const
tt_char decimal_point) const
{
if( !new_exp.IsSign() ) //if( new_exp >= 0 )
return ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp);
@ -3215,7 +3214,7 @@ private:
/*!
an auxiliary method for converting into the string
*/
void ToString_SetCommaAndExponent_Normal_AddingZero(tstr_t & new_man,
void ToString_SetCommaAndExponent_Normal_AddingZero(tt_string & new_man,
Int<exp+1> & new_exp) const
{
// we're adding zero characters at the end
@ -3235,12 +3234,12 @@ private:
an auxiliary method for converting into the string
*/
void ToString_SetCommaAndExponent_Normal_SetCommaInside(
tstr_t & new_man,
tt_string & new_man,
uint base,
Int<exp+1> & new_exp,
sint max_digit_after_comma,
bool remove_trailing_zeroes,
tchar_t decimal_point) const
tt_char decimal_point) const
{
// new_exp is < 0
@ -3259,7 +3258,7 @@ private:
// we're adding zero characters before the mantissa
uint how_many = e - new_man_len;
tstr_t man_temp(how_many+1, '0');
tt_string man_temp(how_many+1, '0');
man_temp.insert( man_temp.begin()+1, decimal_point);
new_man.insert(0, man_temp);
@ -3272,12 +3271,12 @@ private:
/*!
an auxiliary method for converting into the string
*/
void ToString_SetCommaAndExponent_Scientific( tstr_t & new_man,
void ToString_SetCommaAndExponent_Scientific( tt_string & new_man,
uint base,
Int<exp+1> & scientific_exp,
sint max_digit_after_comma,
bool remove_trailing_zeroes,
tchar_t decimal_point) const
tt_char decimal_point) const
{
if( new_man.empty() )
return;
@ -3291,7 +3290,7 @@ private:
new_man += 'e';
if( !scientific_exp.IsSign() )
new_man += TTMATH_TEXT("+");
new_man += '+';
}
else
{
@ -3300,7 +3299,7 @@ private:
new_man += TTMATH_TEXT("*10^");
}
tstr_t temp_exp;
tt_string temp_exp;
scientific_exp.ToString( temp_exp, base );
new_man += temp_exp;
@ -3310,11 +3309,11 @@ private:
/*!
an auxiliary method for converting into the string
*/
void ToString_CorrectDigitsAfterComma( tstr_t & new_man,
void ToString_CorrectDigitsAfterComma( tt_string & new_man,
uint base,
sint max_digit_after_comma,
bool remove_trailing_zeroes,
tchar_t decimal_point) const
tt_char decimal_point) const
{
if( max_digit_after_comma >= 0 )
ToString_CorrectDigitsAfterComma_Round(new_man, base, max_digit_after_comma, decimal_point);
@ -3328,8 +3327,8 @@ private:
an auxiliary method for converting into the string
*/
void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(
tstr_t & new_man,
tchar_t decimal_point) const
tt_string & new_man,
tt_char decimal_point) const
{
// minimum two characters
if( new_man.length() < 2 )
@ -3347,7 +3346,7 @@ private:
// we must have a comma
// (the comma can be removed by ToString_CorrectDigitsAfterComma_Round
// which is called before)
if( new_man.find_last_of(decimal_point, i) == tstr_t::npos )
if( new_man.find_last_of(decimal_point, i) == tt_string::npos )
return;
// if directly before the first zero is the comma operator
@ -3363,26 +3362,26 @@ private:
an auxiliary method for converting into the string
*/
void ToString_CorrectDigitsAfterComma_Round(
tstr_t & new_man,
tt_string & new_man,
uint base,
sint max_digit_after_comma,
tchar_t decimal_point) const
tt_char decimal_point) const
{
// first we're looking for the comma operator
tstr_t::size_type index = new_man.find(decimal_point, 0);
tt_string::size_type index = new_man.find(decimal_point, 0);
if( index == tstr_t::npos )
if( index == tt_string::npos )
// nothing was found (actually there can't be this situation)
return;
// we're calculating how many digits there are at the end (after the comma)
// 'after_comma' will be greater than zero because at the end
// we have at least one digit
tstr_t::size_type after_comma = new_man.length() - index - 1;
tt_string::size_type after_comma = new_man.length() - index - 1;
// if 'max_digit_after_comma' is greater than 'after_comma' (or equal)
// we don't have anything for cutting
if( tstr_t::size_type(max_digit_after_comma) >= after_comma )
if( tt_string::size_type(max_digit_after_comma) >= after_comma )
return;
uint last_digit = UInt<man>::CharToDigit( new_man[ index + max_digit_after_comma + 1 ], base );
@ -3418,6 +3417,7 @@ public:
all digits after the comma we can ignore
'source' - pointer to the string for parsing
'const char*' or 'const wchar_t*'
if 'after_source' is set that when this method finishes
it sets the pointer to the new first character after parsed value
@ -3428,7 +3428,7 @@ public:
no value has been read (there are no digits)
on other words if 'value_read' is true -- there is at least one digit in the string
*/
uint FromString(const tchar_t * source, uint base = 10, const tchar_t ** after_source = 0, bool * value_read = 0)
uint FromString(const tt_char * source, uint base = 10, const tt_char ** after_source = 0, bool * value_read = 0)
{
bool is_sign;
bool value_read_temp = false;
@ -3479,7 +3479,7 @@ private:
(this method is used from 'FromString_ReadPartScientific' too)
*/
void FromString_TestSign( const tchar_t * & source, bool & is_sign )
void FromString_TestSign( const tt_char * & source, bool & is_sign )
{
UInt<man>::SkipWhiteCharacters(source);
@ -3501,7 +3501,7 @@ private:
/*!
we're testing whether there's a comma operator
*/
bool FromString_TestCommaOperator(const tchar_t * & source)
bool FromString_TestCommaOperator(const tt_char * & source)
{
if( (*source == TTMATH_COMMA_CHARACTER_1) ||
(*source == TTMATH_COMMA_CHARACTER_2 && TTMATH_COMMA_CHARACTER_2 != 0 ) )
@ -3519,7 +3519,7 @@ private:
this method reads the first part of a string
(before the comma operator)
*/
uint FromString_ReadPartBeforeComma( const tchar_t * & source, uint base, bool & value_read )
uint FromString_ReadPartBeforeComma( const tt_char * & source, uint base, bool & value_read )
{
sint character;
Big<exp, man> temp;
@ -3548,7 +3548,7 @@ private:
this method reads the second part of a string
(after the comma operator)
*/
uint FromString_ReadPartAfterComma( const tchar_t * & source, uint base, bool & value_read )
uint FromString_ReadPartAfterComma( const tt_char * & source, uint base, bool & value_read )
{
sint character;
uint c = 0, index = 1;
@ -3606,12 +3606,12 @@ private:
it is called when the base is 10 and some digits were read before
*/
int FromString_ReadScientificIfExists(const tchar_t * & source)
uint FromString_ReadScientificIfExists(const tt_char * & source)
{
uint c = 0;
bool scientific_read = false;
const tchar_t * before_scientific = source;
const tt_char * before_scientific = source;
if( FromString_TestScientific(source) )
c += FromString_ReadPartScientific( source, scientific_read );
@ -3629,7 +3629,7 @@ private:
this character is only allowed when we're using the base equals 10
*/
bool FromString_TestScientific(const tchar_t * & source)
bool FromString_TestScientific(const tt_char * & source)
{
UInt<man>::SkipWhiteCharacters(source);
@ -3648,7 +3648,7 @@ private:
this method reads the exponent (after 'e' character) when there's a scientific
format of value and only when we're using the base equals 10
*/
uint FromString_ReadPartScientific( const tchar_t * & source, bool & scientific_read )
uint FromString_ReadPartScientific( const tt_char * & source, bool & scientific_read )
{
uint c = 0;
Big<exp, man> new_exponent, temp;
@ -3675,7 +3675,7 @@ private:
this method reads the value of the extra exponent when scientific format is used
(only when base == 10)
*/
uint FromString_ReadPartScientific_ReadExponent( const tchar_t * & source, Big<exp, man> & new_exponent, bool & scientific_read )
uint FromString_ReadPartScientific_ReadExponent( const tt_char * & source, Big<exp, man> & new_exponent, bool & scientific_read )
{
sint character;
Big<exp, man> base, temp;
@ -3708,7 +3708,7 @@ public:
/*!
a method for converting a string into its value
*/
uint FromString(const tstr_t & string, uint base = 10)
uint FromString(const tt_string & string, uint base = 10)
{
return FromString( string.c_str(), base );
}
@ -3717,7 +3717,7 @@ public:
/*!
a constructor for converting a string into this class
*/
Big(const tchar_t * string)
Big(const tt_char * string)
{
FromString( string );
}
@ -3726,7 +3726,7 @@ public:
/*!
a constructor for converting a string into this class
*/
Big(const tstr_t & string)
Big(const tt_string & string)
{
FromString( string.c_str() );
}
@ -3735,7 +3735,7 @@ public:
/*!
an operator= for converting a string into its value
*/
Big<exp, man> & operator=(const tchar_t * string)
Big<exp, man> & operator=(const tt_char * string)
{
FromString( string );
@ -3746,7 +3746,7 @@ public:
/*!
an operator= for converting a string into its value
*/
Big<exp, man> & operator=(const tstr_t & string)
Big<exp, man> & operator=(const tt_string & string)
{
FromString( string.c_str() );
@ -3905,7 +3905,7 @@ public:
mandiff = man2;
mandiff.Sub(man1);
break;
case 0:
default:
if (man2 > man1)
{
mandiff = man2;
@ -4175,6 +4175,47 @@ public:
/*!
this method returns true if the value is integer
(there is no a fraction)
(we don't check nan)
*/
bool IsInteger() const
{
if( IsZero() )
return true;
if( !exponent.IsSign() )
// exponent >=0 -- the value don't have any fractions
return true;
if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) )
// the value is from (-1,1)
return false;
// exponent is in range (-man*TTMATH_BITS_PER_UINT, 0)
sint e = exponent.ToInt();
e = -e; // e means how many bits we must check
uint len = e / TTMATH_BITS_PER_UINT;
uint rest = e % TTMATH_BITS_PER_UINT;
uint i = 0;
for( ; i<len ; ++i )
if( mantissa.table[i] != 0 )
return false;
if( rest > 0 )
{
uint rest_mask = TTMATH_UINT_MAX_VALUE >> (TTMATH_BITS_PER_UINT - rest);
if( (mantissa.table[i] & rest_mask) != 0 )
return false;
}
return true;
}
/*!
this method rounds to the nearest integer value
@ -4223,9 +4264,14 @@ public:
*
*/
friend tostrm_t & operator<<(tostrm_t & s, const Big<exp,man> & l)
/*!
output for standard streams
tt_ostream is either std::ostream or std::wostream
*/
friend tt_ostream & operator<<(tt_ostream & s, const Big<exp,man> & l)
{
tstr_t ss;
tt_string ss;
l.ToString(ss);
s << ss;
@ -4234,12 +4280,17 @@ public:
}
friend tistrm_t & operator>>(tistrm_t & s, Big<exp,man> & l)
/*!
input from standard streams
tt_istream is either std::istream or std::wistream
*/
friend tt_istream & operator>>(tt_istream & s, Big<exp,man> & l)
{
tstr_t ss;
tt_string ss;