added: UInt::MulInt(int, UInt<int another_size>::&)

added: Big::MulUInt(uint)
changed: Big::MulInt(sint)
added: Big::ToUInt(uint &)
changed: Big::ToInt(sint&)
changed: Factorial() it uses Big::MulUInt() at the beginning
         (faster now especially more on a 32bit platform)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@33 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2007-04-07 22:21:31 +00:00
parent c97ebf282f
commit e40ed603c6
4 changed files with 233 additions and 50 deletions

View File

@ -1529,9 +1529,76 @@ namespace ttmath
namespace auxiliaryfunctions
{
template<class ValueType>
uint FactorialInt( const ValueType & x, ErrorCode * err,
const volatile StopCalculating * stop,
ValueType & result)
{
uint maxvalue = TTMATH_UINT_MAX_VALUE;
if( x < TTMATH_UINT_MAX_VALUE )
x.ToUInt(maxvalue);
uint multipler = 1;
uint carry = 0;
while( !carry && multipler<maxvalue )
{
if( stop && stop->WasStopSignal() )
{
if( err )
*err = err_interrupt;
return 2;
}
++multipler;
carry += result.MulUInt(multipler);
}
if( err )
*err = carry ? err_overflow : err_ok;
return carry ? 1 : 0;
}
template<class ValueType>
int FactorialMore( const ValueType & x, ErrorCode * err,
const volatile StopCalculating * stop,
ValueType & result)
{
ValueType multipler(TTMATH_UINT_MAX_VALUE);
ValueType one;
one.SetOne();
uint carry = 0;
while( !carry && multipler < x )
{
if( stop && stop->WasStopSignal() )
{
if( err )
*err = err_interrupt;
return 2;
}
carry += multipler.Add(one);
carry += result.Mul(multipler);
}
if( err )
*err = carry ? err_overflow : err_ok;
return carry ? 1 : 0;
}
} // namespace
@ -1543,6 +1610,8 @@ namespace ttmath
template<class ValueType>
ValueType Factorial(const ValueType & x, ErrorCode * err = 0, const volatile StopCalculating * stop = 0)
{
using namespace auxiliaryfunctions;
static History<ValueType> history;
ValueType result;
@ -1577,33 +1646,17 @@ namespace ttmath
return result;
}
ValueType multipler;
ValueType one;
uint carry = 0;
one = result; // =1
multipler = result; // =1
while( !carry && multipler < x )
{
if( stop && stop->WasStopSignal() )
{
if( err )
*err = err_interrupt;
uint status = FactorialInt(x, err, stop, result);
if( status == 0 )
status = FactorialMore(x, err, stop, result);
if( status == 2 )
// the calculation has been interrupted
return result;
}
carry += multipler.Add(one);
carry += result.Mul(multipler);
}
err_tmp = carry ? err_overflow : err_ok;
err_tmp = status==1 ? err_overflow : err_ok;
history.Add(x, result, err_tmp);
if( err )
*err = carry ? err_overflow : err_ok;
return result;
}

View File

@ -594,6 +594,73 @@ public:
}
/*!
Multiplication this = this * ss2 (ss2 is uint)
ss2 without a sign
*/
uint MulUInt(uint ss2)
{
UInt<man+1> man_result;
uint i,c = 0;
// man_result = mantissa * ss2.mantissa
mantissa.MulInt(ss2, man_result);
int bit = UInt<man>::FindLeadingBitInWord(man_result.table[man]); // man - last word
if( bit!=-1 && uint(bit) > (TTMATH_BITS_PER_UINT/2) )
{
// 'i' will be from 0 to TTMATH_BITS_PER_UINT
i = man_result.CompensationToLeft();
c = exponent.Add( TTMATH_BITS_PER_UINT - i );
for(i=0 ; i<man ; ++i)
mantissa.table[i] = man_result.table[i+1];
}
else
{
if( bit != -1 )
{
man_result.Rcr(bit+1, 0);
c += exponent.Add(bit+1);
}
for(i=0 ; i<man ; ++i)
mantissa.table[i] = man_result.table[i];
}
c += Standardizing();
return (c==0)? 0 : 1;
}
/*!
Multiplication this = this * ss2 (ss2 is sint)
ss2 with a sign
*/
uint MulInt(sint ss2)
{
if( IsSign() == (ss2<0) )
{
// the signs are the same, the result is positive
Abs();
}
else
{
// the signs are different, the result is negative
SetSign();
}
if( ss2<0 )
ss2 = 0 - ss2;
return MulUInt( uint(ss2) );
}
/*!
multiplication this = this * ss2
this method returns carry
@ -1275,19 +1342,22 @@ public:
*
*/
/*!
this method sets 'result' as the one word of type sint
this method sets 'result' as the one word of type uint
if the value is too big this method returns a carry (1)
*/
uint ToInt(sint & result) const
uint ToUInt(uint & result, bool test_sign = true) const
{
result = 0;
if( IsZero() )
return 0;
if( test_sign && IsSign() )
// the result should be positive
return 1;
sint maxbit = -sint(man*TTMATH_BITS_PER_UINT);
if( exponent > maxbit + sint(TTMATH_BITS_PER_UINT) )
@ -1296,30 +1366,50 @@ public:
return 1;
if( exponent <= maxbit )
// our value is from range (-1,1) and we return zero
// our value is from the range of (-1,1) and we return zero
return 0;
UInt<man> mantissa_temp(mantissa);
// exponent is from a range of (-maxbit,0>
// exponent is from a range of (maxbit, maxbit + sint(TTMATH_BITS_PER_UINT) >
sint how_many_bits = exponent.ToInt();
// how_many_bits is negative, we'll make it positive
how_many_bits = -how_many_bits;
// we're taking into an account only the last word in a mantissa table
// we're taking into account only the last word in a mantissa table
mantissa_temp.Rcr( how_many_bits % TTMATH_BITS_PER_UINT, 0 );
result = mantissa_temp.table[ man-1 ];
return 0;
}
/*!
this method sets 'result' as the one word of type sint
if the value is too big this method returns a carry (1)
*/
uint ToInt(sint & result) const
{
result = 0;
uint result_uint;
if( ToUInt(result_uint, false) )
return 1;
result = static_cast<sint>( result_uint );
// the exception for the minimal value
if( IsSign() && result == TTMATH_UINT_HIGHEST_BIT )
if( IsSign() && result_uint == TTMATH_UINT_HIGHEST_BIT )
return 0;
if( (result & TTMATH_UINT_HIGHEST_BIT) != 0 )
if( (result_uint & TTMATH_UINT_HIGHEST_BIT) != 0 )
// the value is too big
return 1;
if( IsSign() )
result = -sint(result);
result = -result;
return 0;
}
@ -1343,7 +1433,6 @@ public:
if( exponent > maxbit + sint(int_size*TTMATH_BITS_PER_UINT) )
// if exponent > (maxbit + sint(int_size*TTMATH_BITS_PER_UINT)) the value can't be passed
// into the 'Int<int_size>' type (it's too big)
return 1;
if( exponent <= maxbit )
// our value is from range (-1,1) and we return zero

View File

@ -618,6 +618,7 @@ void Factorial(int sindex, int amount_of_args, ValueType & result)
Error( err );
}
void Abs(int sindex, int amount_of_args, ValueType & result)
{
if( amount_of_args != 1 )
@ -2126,7 +2127,6 @@ ErrorCode Parse(const char * str)
stack.resize( default_stack_size );
try
{
Parse();

View File

@ -1442,6 +1442,47 @@ public:
return 0;
}
/*!
multiplication: result = this * ss2
we're using this method only when result_size is greater than value_size
if so there will not be a carry
*/
template<uint result_size>
uint MulInt(uint ss2, UInt<result_size> & result)
{
uint r2,r1;
uint x1size=value_size;
uint x1start=0;
if( value_size >= result_size )
return 1;
result.SetZero();
if( value_size > 2 )
{
// if the value_size is smaller than or equal to 2
// there is no sense to set x1size and x1start to another values
for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size);
if( x1size==0 )
return 0;
for(x1start=0 ; x1start<x1size && table[x1start]==0 ; ++x1start);
}
for(uint x1=x1start ; x1<x1size ; ++x1)
{
MulTwoWords(table[x1], ss2, &r2, &r1 );
result.AddTwoInts(r2,r1,x1);
}
return 0;
}
/*!
the multiplication 'this' = 'this' * ss2