diff --git a/ttmath/ttmath.h b/ttmath/ttmath.h index 69d94ca..9379d90 100644 --- a/ttmath/ttmath.h +++ b/ttmath/ttmath.h @@ -1529,10 +1529,77 @@ namespace ttmath + namespace auxiliaryfunctions + { + + template + 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 && multiplerWasStopSignal() ) + { + 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 + 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 ValueType Factorial(const ValueType & x, ErrorCode * err = 0, const volatile StopCalculating * stop = 0) { + using namespace auxiliaryfunctions; + static History 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; } diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index 1fcf6fb..8bed6e3 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -593,7 +593,74 @@ public: return Add(ss2); } - + + /*! + Multiplication this = this * ss2 (ss2 is uint) + + ss2 without a sign + */ + uint MulUInt(uint ss2) + { + UInt man_result; + uint i,c = 0; + + // man_result = mantissa * ss2.mantissa + mantissa.MulInt(ss2, man_result); + + int bit = UInt::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 maxbit + sint(TTMATH_BITS_PER_UINT) ) + // if exponent > (maxbit + sint(TTMATH_BITS_PER_UINT)) the value can't be passed + // into the 'sint' type (it's too big) + return 1; + + if( exponent <= maxbit ) + // our value is from the range of (-1,1) and we return zero + return 0; + + UInt mantissa_temp(mantissa); + // 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 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 @@ -1284,42 +1393,23 @@ public: uint ToInt(sint & result) const { result = 0; + uint result_uint; - if( IsZero() ) - return 0; - - sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); - - if( exponent > maxbit + sint(TTMATH_BITS_PER_UINT) ) - // if exponent > (maxbit + sint(TTMATH_BITS_PER_UINT)) the value can't be passed - // into the 'sint' type (it's too big) + if( ToUInt(result_uint, false) ) return 1; - if( exponent <= maxbit ) - // our value is from range (-1,1) and we return zero - return 0; - - UInt mantissa_temp(mantissa); - // exponent is from a range of (-maxbit,0> - 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 - mantissa_temp.Rcr( how_many_bits % TTMATH_BITS_PER_UINT, 0 ); - result = mantissa_temp.table[ man-1 ]; + result = static_cast( 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' type (it's too big) - return 1; if( exponent <= maxbit ) // our value is from range (-1,1) and we return zero diff --git a/ttmath/ttmathparser.h b/ttmath/ttmathparser.h index 51ddfbc..a1772f6 100644 --- a/ttmath/ttmathparser.h +++ b/ttmath/ttmathparser.h @@ -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(); diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h index 43a6013..26ea0af 100644 --- a/ttmath/ttmathuint.h +++ b/ttmath/ttmathuint.h @@ -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 MulInt(uint ss2, UInt & 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