From d286182d253c99a286e044bdc10189f7e3a662e0 Mon Sep 17 00:00:00 2001 From: RD42 <42702181+dashr9230@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:32:38 +0800 Subject: [PATCH] Add ttmath 0.9.1 library --- saco/saco.vcproj | 10 + server/server.vcproj | 10 + ttmath/ttmath.h | 2835 ++++++++++++++++ ttmath/ttmathbig.h | 5236 +++++++++++++++++++++++++++++ ttmath/ttmathint.h | 1547 +++++++++ ttmath/ttmathmisc.h | 243 ++ ttmath/ttmathobjects.h | 766 +++++ ttmath/ttmathparser.h | 2754 +++++++++++++++ ttmath/ttmaththreads.h | 250 ++ ttmath/ttmathtypes.h | 646 ++++ ttmath/ttmathuint.h | 3520 +++++++++++++++++++ ttmath/ttmathuint_noasm.h | 1013 ++++++ ttmath/ttmathuint_x86.h | 1602 +++++++++ ttmath/ttmathuint_x86_64.h | 1222 +++++++ ttmath/ttmathuint_x86_64_msvc.asm | 548 +++ 15 files changed, 22202 insertions(+) create mode 100644 ttmath/ttmath.h create mode 100644 ttmath/ttmathbig.h create mode 100644 ttmath/ttmathint.h create mode 100644 ttmath/ttmathmisc.h create mode 100644 ttmath/ttmathobjects.h create mode 100644 ttmath/ttmathparser.h create mode 100644 ttmath/ttmaththreads.h create mode 100644 ttmath/ttmathtypes.h create mode 100644 ttmath/ttmathuint.h create mode 100644 ttmath/ttmathuint_noasm.h create mode 100644 ttmath/ttmathuint_x86.h create mode 100644 ttmath/ttmathuint_x86_64.h create mode 100644 ttmath/ttmathuint_x86_64_msvc.asm diff --git a/saco/saco.vcproj b/saco/saco.vcproj index 1bfd1ee..615add3 100644 --- a/saco/saco.vcproj +++ b/saco/saco.vcproj @@ -230,6 +230,16 @@ RelativePath=".\archive\TinyEncrypt.h"> + + + + + + diff --git a/server/server.vcproj b/server/server.vcproj index b4daa51..0c1b618 100644 --- a/server/server.vcproj +++ b/server/server.vcproj @@ -108,6 +108,16 @@ + + + + + + diff --git a/ttmath/ttmath.h b/ttmath/ttmath.h new file mode 100644 index 0000000..8bd24f5 --- /dev/null +++ b/ttmath/ttmath.h @@ -0,0 +1,2835 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#ifndef headerfilettmathmathtt +#define headerfilettmathmathtt + +/*! + \file ttmath.h + \brief Mathematics functions. +*/ + +#ifdef _MSC_VER +//warning C4127: conditional expression is constant +#pragma warning( disable: 4127 ) +//warning C4702: unreachable code +#pragma warning( disable: 4702 ) +//warning C4800: forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable: 4800 ) +#endif + + +#include "ttmathbig.h" +#include "ttmathobjects.h" + + +namespace ttmath +{ + /* + * + * functions defined here are used only with Big<> types + * + * + */ + + + /* + * + * functions for rounding + * + * + */ + + + /*! + this function skips the fraction from x + e.g 2.2 = 2 + 2.7 = 2 + -2.2 = 2 + -2.7 = 2 + */ + template + ValueType SkipFraction(const ValueType & x) + { + ValueType result( x ); + result.SkipFraction(); + + return result; + } + + + /*! + this function rounds to the nearest integer value + e.g 2.2 = 2 + 2.7 = 3 + -2.2 = -2 + -2.7 = -3 + */ + template + ValueType Round(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result( x ); + uint c = result.Round(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + + /*! + this function returns a value representing the smallest integer + that is greater than or equal to x + + Ceil(-3.7) = -3 + Ceil(-3.1) = -3 + Ceil(-3.0) = -3 + Ceil(4.0) = 4 + Ceil(4.2) = 5 + Ceil(4.8) = 5 + */ + template + ValueType Ceil(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result(x); + uint c = 0; + + result.SkipFraction(); + + if( result != x ) + { + // x is with fraction + // if x is negative we don't have to do anything + if( !x.IsSign() ) + { + ValueType one; + one.SetOne(); + + c += result.Add(one); + } + } + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function returns a value representing the largest integer + that is less than or equal to x + + Floor(-3.6) = -4 + Floor(-3.1) = -4 + Floor(-3) = -3 + Floor(2) = 2 + Floor(2.3) = 2 + Floor(2.8) = 2 + */ + template + ValueType Floor(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result(x); + uint c = 0; + + result.SkipFraction(); + + if( result != x ) + { + // x is with fraction + // if x is positive we don't have to do anything + if( x.IsSign() ) + { + ValueType one; + one.SetOne(); + + c += result.Sub(one); + } + } + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + + /* + * + * logarithms and the exponent + * + * + */ + + + /*! + this function calculates the natural logarithm (logarithm with the base 'e') + */ + template + ValueType Ln(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result; + uint state = result.Ln(x); + + if( err ) + { + switch( state ) + { + case 0: + *err = err_ok; + break; + case 1: + *err = err_overflow; + break; + case 2: + *err = err_improper_argument; + break; + default: + *err = err_internal_error; + break; + } + } + + + return result; + } + + + /*! + this function calculates the logarithm + */ + template + ValueType Log(const ValueType & x, const ValueType & base, ErrorCode * err = 0) + { + if( x.IsNan() || base.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // default NaN + } + + ValueType result; + uint state = result.Log(x, base); + + if( err ) + { + switch( state ) + { + case 0: + *err = err_ok; + break; + case 1: + *err = err_overflow; + break; + case 2: + case 3: + *err = err_improper_argument; + break; + default: + *err = err_internal_error; + break; + } + } + + return result; + } + + + /*! + this function calculates the expression e^x + */ + template + ValueType Exp(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType result; + uint c = result.Exp(x); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + * + * trigonometric functions + * + */ + + + /* + this namespace consists of auxiliary functions + (something like 'private' in a class) + */ + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the Sine + (you don't have to call this function) + */ + template + uint PrepareSin(ValueType & x, bool & change_sign) + { + ValueType temp; + + change_sign = false; + + if( x.IsSign() ) + { + // we're using the formula 'sin(-x) = -sin(x)' + change_sign = !change_sign; + x.ChangeSign(); + } + + // we're reducing the period 2*PI + // (for big values there'll always be zero) + temp.Set2Pi(); + + if( x.Mod(temp) ) + return 1; + + + // we're setting 'x' as being in the range of <0, 0.5PI> + + temp.SetPi(); + + if( x > temp ) + { + // x is in (pi, 2*pi> + x.Sub( temp ); + change_sign = !change_sign; + } + + temp.Set05Pi(); + + if( x > temp ) + { + // x is in (0.5pi, pi> + x.Sub( temp ); + x = temp - x; + } + + return 0; + } + + + /*! + an auxiliary function for calculating the Sine + (you don't have to call this function) + + it returns Sin(x) where 'x' is from <0, PI/2> + we're calculating the Sin with using Taylor series in zero or PI/2 + (depending on which point of these two points is nearer to the 'x') + + Taylor series: + sin(x) = sin(a) + cos(a)*(x-a)/(1!) + - sin(a)*((x-a)^2)/(2!) - cos(a)*((x-a)^3)/(3!) + + sin(a)*((x-a)^4)/(4!) + ... + + when a=0 it'll be: + sin(x) = (x)/(1!) - (x^3)/(3!) + (x^5)/(5!) - (x^7)/(7!) + (x^9)/(9!) ... + + and when a=PI/2: + sin(x) = 1 - ((x-PI/2)^2)/(2!) + ((x-PI/2)^4)/(4!) - ((x-PI/2)^6)/(6!) ... + */ + template + ValueType Sin0pi05(const ValueType & x) + { + ValueType result; + ValueType numerator, denominator; + ValueType d_numerator, d_denominator; + ValueType one, temp, old_result; + + // temp = pi/4 + temp.Set05Pi(); + temp.exponent.SubOne(); + + one.SetOne(); + + if( x < temp ) + { + // we're using the Taylor series with a=0 + result = x; + numerator = x; + denominator = one; + + // d_numerator = x^2 + d_numerator = x; + d_numerator.Mul(x); + + d_denominator = 2; + } + else + { + // we're using the Taylor series with a=PI/2 + result = one; + numerator = one; + denominator = one; + + // d_numerator = (x-pi/2)^2 + ValueType pi05; + pi05.Set05Pi(); + + temp = x; + temp.Sub( pi05 ); + d_numerator = temp; + d_numerator.Mul( temp ); + + d_denominator = one; + } + + uint c = 0; + bool addition = false; + + old_result = result; + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + // we're starting from a second part of the formula + c += numerator. Mul( d_numerator ); + c += denominator. Mul( d_denominator ); + c += d_denominator.Add( one ); + c += denominator. Mul( d_denominator ); + c += d_denominator.Add( one ); + temp = numerator; + c += temp.Div(denominator); + + if( c ) + // Sin is from <-1,1> and cannot make an overflow + // but the carry can be from the Taylor series + // (then we only break our calculations) + break; + + if( addition ) + result.Add( temp ); + else + result.Sub( temp ); + + + addition = !addition; + + // we're testing whether the result has changed after adding + // the next part of the Taylor formula, if not we end the loop + // (it means 'x' is zero or 'x' is PI/2 or this part of the formula + // is too small) + if( result == old_result ) + break; + + old_result = result; + } + + return result; + } + + } // namespace auxiliaryfunctions + + + + /*! + this function calculates the Sine + */ + template + ValueType Sin(ValueType x, ErrorCode * err = 0) + { + using namespace auxiliaryfunctions; + + ValueType one, result; + bool change_sign; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( err ) + *err = err_ok; + + if( PrepareSin( x, change_sign ) ) + { + // x is too big, we cannnot reduce the 2*PI period + // prior to version 0.8.5 the result was zero + + // result has NaN flag set by default + + if( err ) + *err = err_overflow; // maybe another error code? err_improper_argument? + + return result; // NaN is set by default + } + + result = Sin0pi05( x ); + + one.SetOne(); + + // after calculations there can be small distortions in the result + if( result > one ) + result = one; + else + if( result.IsSign() ) + // we've calculated the sin from <0, pi/2> and the result + // should be positive + result.SetZero(); + + if( change_sign ) + result.ChangeSign(); + + return result; + } + + + /*! + this function calulates the Cosine + we're using the formula cos(x) = sin(x + PI/2) + */ + template + ValueType Cos(ValueType x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType pi05; + pi05.Set05Pi(); + + uint c = x.Add( pi05 ); + + if( c ) + { + if( err ) + *err = err_overflow; + + return ValueType(); // result is undefined (NaN is set by default) + } + + return Sin(x, err); + } + + + /*! + this function calulates the Tangent + we're using the formula tan(x) = sin(x) / cos(x) + + it takes more time than calculating the Tan directly + from for example Taylor series but should be a bit preciser + because Tan receives its values from -infinity to +infinity + and when we calculate it from any series then we can make + a greater mistake than calculating 'sin/cos' + */ + template + ValueType Tan(const ValueType & x, ErrorCode * err = 0) + { + ValueType result = Cos(x, err); + + if( err && *err != err_ok ) + return result; + + if( result.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + result.SetNan(); + + return result; + } + + return Sin(x, err) / result; + } + + + /*! + this function calulates the Tangent + look at the description of Tan(...) + + (the abbreviation of Tangent can be 'tg' as well) + */ + template + ValueType Tg(const ValueType & x, ErrorCode * err = 0) + { + return Tan(x, err); + } + + + /*! + this function calulates the Cotangent + we're using the formula tan(x) = cos(x) / sin(x) + + (why do we make it in this way? + look at information in Tan() function) + */ + template + ValueType Cot(const ValueType & x, ErrorCode * err = 0) + { + ValueType result = Sin(x, err); + + if( err && *err != err_ok ) + return result; + + if( result.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + result.SetNan(); + + return result; + } + + return Cos(x, err) / result; + } + + + /*! + this function calulates the Cotangent + look at the description of Cot(...) + + (the abbreviation of Cotangent can be 'ctg' as well) + */ + template + ValueType Ctg(const ValueType & x, ErrorCode * err = 0) + { + return Cot(x, err); + } + + + /* + * + * inverse trigonometric functions + * + * + */ + + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the Arc Sine + + we're calculating asin from the following formula: + asin(x) = x + (1*x^3)/(2*3) + (1*3*x^5)/(2*4*5) + (1*3*5*x^7)/(2*4*6*7) + ... + where abs(x) <= 1 + + we're using this formula when x is from <0, 1/2> + */ + template + ValueType ASin_0(const ValueType & x) + { + ValueType nominator, denominator, nominator_add, nominator_x, denominator_add, denominator_x; + ValueType two, result(x), x2(x); + ValueType nominator_temp, denominator_temp, old_result = result; + uint c = 0; + + x2.Mul(x); + two = 2; + + nominator.SetOne(); + denominator = two; + nominator_add = nominator; + denominator_add = denominator; + nominator_x = x; + denominator_x = 3; + + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + c += nominator_x.Mul(x2); + nominator_temp = nominator_x; + c += nominator_temp.Mul(nominator); + denominator_temp = denominator; + c += denominator_temp.Mul(denominator_x); + c += nominator_temp.Div(denominator_temp); + + // if there is a carry somewhere we only break the calculating + // the result should be ok -- it's from <-pi/2, pi/2> + if( c ) + break; + + result.Add(nominator_temp); + + if( result == old_result ) + // there's no sense to calculate more + break; + + old_result = result; + + + c += nominator_add.Add(two); + c += denominator_add.Add(two); + c += nominator.Mul(nominator_add); + c += denominator.Mul(denominator_add); + c += denominator_x.Add(two); + } + + return result; + } + + + + /*! + an auxiliary function for calculating the Arc Sine + + we're calculating asin from the following formula: + asin(x) = pi/2 - sqrt(2)*sqrt(1-x) * asin_temp + asin_temp = 1 + (1*(1-x))/((2*3)*(2)) + (1*3*(1-x)^2)/((2*4*5)*(4)) + (1*3*5*(1-x)^3)/((2*4*6*7)*(8)) + ... + + where abs(x) <= 1 + + we're using this formula when x is from (1/2, 1> + */ + template + ValueType ASin_1(const ValueType & x) + { + ValueType nominator, denominator, nominator_add, nominator_x, nominator_x_add, denominator_add, denominator_x; + ValueType denominator2; + ValueType one, two, result; + ValueType nominator_temp, denominator_temp, old_result; + uint c = 0; + + two = 2; + + one.SetOne(); + nominator = one; + result = one; + old_result = result; + denominator = two; + nominator_add = nominator; + denominator_add = denominator; + nominator_x = one; + nominator_x.Sub(x); + nominator_x_add = nominator_x; + denominator_x = 3; + denominator2 = two; + + + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + nominator_temp = nominator_x; + c += nominator_temp.Mul(nominator); + denominator_temp = denominator; + c += denominator_temp.Mul(denominator_x); + c += denominator_temp.Mul(denominator2); + c += nominator_temp.Div(denominator_temp); + + // if there is a carry somewhere we only break the calculating + // the result should be ok -- it's from <-pi/2, pi/2> + if( c ) + break; + + result.Add(nominator_temp); + + if( result == old_result ) + // there's no sense to calculate more + break; + + old_result = result; + + c += nominator_x.Mul(nominator_x_add); + c += nominator_add.Add(two); + c += denominator_add.Add(two); + c += nominator.Mul(nominator_add); + c += denominator.Mul(denominator_add); + c += denominator_x.Add(two); + c += denominator2.Mul(two); + } + + + nominator_x_add.exponent.AddOne(); // *2 + one.exponent.SubOne(); // =0.5 + nominator_x_add.Pow(one); // =sqrt(nominator_x_add) + result.Mul(nominator_x_add); + + one.Set05Pi(); + one.Sub(result); + + return one; + } + + + } // namespace auxiliaryfunctions + + + /*! + this function calculates the Arc Sine + x is from <-1,1> + */ + template + ValueType ASin(ValueType x, ErrorCode * err = 0) + { + using namespace auxiliaryfunctions; + + ValueType result, one; + one.SetOne(); + 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( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( x.IsSign() ) + { + change_sign = true; + x.Abs(); + } + + one.exponent.SubOne(); // =0.5 + + // asin(-x) = -asin(x) + if( x.GreaterWithoutSignThan(one) ) + result = ASin_1(x); + else + result = ASin_0(x); + + if( change_sign ) + result.ChangeSign(); + + if( err ) + *err = err_ok; + + return result; + } + + + /*! + this function calculates the Arc Cosine + + we're using the formula: + acos(x) = pi/2 - asin(x) + */ + template + ValueType ACos(const ValueType & x, ErrorCode * err = 0) + { + ValueType temp; + + temp.Set05Pi(); + temp.Sub(ASin(x, err)); + + return temp; + } + + + + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the Arc Tangent + + arc tan (x) where x is in <0; 0.5) + (x can be in (-0.5 ; 0.5) too) + + we're using the Taylor series expanded in zero: + atan(x) = x - (x^3)/3 + (x^5)/5 - (x^7)/7 + ... + */ + template + ValueType ATan0(const ValueType & x) + { + ValueType nominator, denominator, nominator_add, denominator_add, temp; + ValueType result, old_result; + bool adding = false; + uint c = 0; + + result = x; + old_result = result; + nominator = x; + nominator_add = x; + nominator_add.Mul(x); + + denominator.SetOne(); + denominator_add = 2; + + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + { + c += nominator.Mul(nominator_add); + c += denominator.Add(denominator_add); + + temp = nominator; + c += temp.Div(denominator); + + if( c ) + // the result should be ok + break; + + if( adding ) + result.Add(temp); + else + result.Sub(temp); + + if( result == old_result ) + // there's no sense to calculate more + break; + + old_result = result; + adding = !adding; + } + + return result; + } + + + /*! + an auxiliary function for calculating the Arc Tangent + + where x is in <0 ; 1> + */ + template + ValueType ATan01(const ValueType & x) + { + ValueType half; + half.Set05(); + + /* + it would be better if we chose about sqrt(2)-1=0.41... instead of 0.5 here + + because as you can see below: + when x = sqrt(2)-1 + abs(x) = abs( (x-1)/(1+x) ) + so when we're calculating values around x + then they will be better converged to each other + + for example if we have x=0.4999 then during calculating ATan0(0.4999) + we have to make about 141 iterations but when we have x=0.5 + then during calculating ATan0( (x-1)/(1+x) ) we have to make + only about 89 iterations (both for Big<3,9>) + + in the future this 0.5 can be changed + */ + if( x.SmallerWithoutSignThan(half) ) + return ATan0(x); + + + /* + x>=0.5 and x<=1 + (x can be even smaller than 0.5) + + y = atac(x) + x = tan(y) + + tan(y-b) = (tan(y)-tab(b)) / (1+tan(y)*tan(b)) + y-b = atan( (tan(y)-tab(b)) / (1+tan(y)*tan(b)) ) + y = b + atan( (x-tab(b)) / (1+x*tan(b)) ) + + let b = pi/4 + tan(b) = tan(pi/4) = 1 + y = pi/4 + atan( (x-1)/(1+x) ) + + so + atac(x) = pi/4 + atan( (x-1)/(1+x) ) + when x->1 (x converges to 1) the (x-1)/(1+x) -> 0 + and we can use ATan0() function here + */ + + ValueType n(x),d(x),one,result; + + one.SetOne(); + n.Sub(one); + d.Add(one); + n.Div(d); + + result = ATan0(n); + + n.Set05Pi(); + n.exponent.SubOne(); // =pi/4 + result.Add(n); + + return result; + } + + + /*! + an auxiliary function for calculating the Arc Tangent + where x > 1 + + we're using the formula: + atan(x) = pi/2 - atan(1/x) for x>0 + */ + template + ValueType ATanGreaterThanPlusOne(const ValueType & x) + { + ValueType temp, atan; + + temp.SetOne(); + + if( temp.Div(x) ) + { + // if there was a carry here that means x is very big + // and atan(1/x) fast converged to 0 + atan.SetZero(); + } + else + atan = ATan01(temp); + + temp.Set05Pi(); + temp.Sub(atan); + + return temp; + } + + } // namespace auxiliaryfunctions + + + /*! + this function calculates the Arc Tangent + */ + template + ValueType ATan(ValueType x) + { + using namespace auxiliaryfunctions; + + ValueType one, result; + one.SetOne(); + bool change_sign = false; + + if( x.IsNan() ) + return result; // NaN is set by default + + // if x is negative we're using the formula: + // atan(-x) = -atan(x) + if( x.IsSign() ) + { + change_sign = true; + x.Abs(); + } + + if( x.GreaterWithoutSignThan(one) ) + result = ATanGreaterThanPlusOne(x); + else + result = ATan01(x); + + if( change_sign ) + result.ChangeSign(); + + return result; + } + + + /*! + this function calculates the Arc Tangent + look at the description of ATan(...) + + (the abbreviation of Arc Tangent can be 'atg' as well) + */ + template + ValueType ATg(const ValueType & x) + { + return ATan(x); + } + + + /*! + this function calculates the Arc Cotangent + + we're using the formula: + actan(x) = pi/2 - atan(x) + */ + template + ValueType ACot(const ValueType & x) + { + ValueType result; + + result.Set05Pi(); + result.Sub(ATan(x)); + + return result; + } + + + /*! + this function calculates the Arc Cotangent + look at the description of ACot(...) + + (the abbreviation of Arc Cotangent can be 'actg' as well) + */ + template + ValueType ACtg(const ValueType & x) + { + return ACot(x); + } + + + /* + * + * hyperbolic functions + * + * + */ + + + /*! + this function calculates the Hyperbolic Sine + + we're using the formula sinh(x)= ( e^x - e^(-x) ) / 2 + */ + template + ValueType Sinh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType ex, emx; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + c += ex.Sub(emx); + c += ex.exponent.SubOne(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return ex; + } + + + /*! + this function calculates the Hyperbolic Cosine + + we're using the formula cosh(x)= ( e^x + e^(-x) ) / 2 + */ + template + ValueType Cosh(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + ValueType ex, emx; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + c += ex.Add(emx); + c += ex.exponent.SubOne(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return ex; + } + + + /*! + this function calculates the Hyperbolic Tangent + + we're using the formula tanh(x)= ( e^x - e^(-x) ) / ( e^x + e^(-x) ) + */ + template + 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; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + nominator = ex; + c += nominator.Sub(emx); + denominator = ex; + c += denominator.Add(emx); + + c += nominator.Div(denominator); + + if( err ) + *err = c ? err_overflow : err_ok; + + return nominator; + } + + + /*! + this function calculates the Hyperbolic Tangent + look at the description of Tanh(...) + + (the abbreviation of Hyperbolic Tangent can be 'tgh' as well) + */ + template + ValueType Tgh(const ValueType & x, ErrorCode * err = 0) + { + return Tanh(x, err); + } + + /*! + this function calculates the Hyperbolic Cotangent + + we're using the formula coth(x)= ( e^x + e^(-x) ) / ( e^x - e^(-x) ) + */ + template + ValueType Coth(const ValueType & x, ErrorCode * err = 0) + { + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return x; // NaN + } + + if( x.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + ValueType ex, emx, nominator, denominator; + uint c = 0; + + c += ex.Exp(x); + c += emx.Exp(-x); + + nominator = ex; + c += nominator.Add(emx); + denominator = ex; + c += denominator.Sub(emx); + + c += nominator.Div(denominator); + + if( err ) + *err = c ? err_overflow : err_ok; + + return nominator; + } + + + /*! + this function calculates the Hyperbolic Cotangent + look at the description of Coth(...) + + (the abbreviation of Hyperbolic Cotangent can be 'ctgh' as well) + */ + template + ValueType Ctgh(const ValueType & x, ErrorCode * err = 0) + { + return Coth(x, err); + } + + + /* + * + * inverse hyperbolic functions + * + * + */ + + + /*! + inverse hyperbolic sine + + asinh(x) = ln( x + sqrt(x^2 + 1) ) + */ + template + 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; + uint c = 0; + one.SetOne(); + + c += xx.Mul(x); + c += xx.Add(one); + one.exponent.SubOne(); // one=0.5 + // xx is >= 1 + c += xx.PowFrac(one); // xx=sqrt(xx) + c += xx.Add(x); + c += result.Ln(xx); // xx > 0 + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic cosine + + acosh(x) = ln( x + sqrt(x^2 - 1) ) x in <1, infinity) + */ + template + 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; + uint c = 0; + one.SetOne(); + + if( x < one ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + c += xx.Mul(x); + c += xx.Sub(one); + // xx is >= 0 + // we can't call a PowFrac when the 'x' is zero + // if x is 0 the sqrt(0) is 0 + if( !xx.IsZero() ) + { + one.exponent.SubOne(); // one=0.5 + c += xx.PowFrac(one); // xx=sqrt(xx) + } + c += xx.Add(x); + c += result.Ln(xx); // xx >= 1 + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic tangent + + atanh(x) = 0.5 * ln( (1+x) / (1-x) ) x in (-1, 1) + */ + template + 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; + uint c = 0; + one.SetOne(); + + if( !x.SmallerWithoutSignThan(one) ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + c += nominator.Add(one); + denominator = one; + c += denominator.Sub(x); + c += nominator.Div(denominator); + c += result.Ln(nominator); + c += result.exponent.SubOne(); + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic tantent + */ + template + ValueType ATgh(const ValueType & x, ErrorCode * err = 0) + { + return ATanh(x, err); + } + + + /*! + inverse hyperbolic cotangent + + acoth(x) = 0.5 * ln( (x+1) / (x-1) ) x in (-infinity, -1) or (1, infinity) + */ + template + 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; + uint c = 0; + one.SetOne(); + + if( !x.GreaterWithoutSignThan(one) ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + c += nominator.Add(one); + c += denominator.Sub(one); + c += nominator.Div(denominator); + c += result.Ln(nominator); + c += result.exponent.SubOne(); + + // here can only be a carry + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + inverse hyperbolic cotantent + */ + template + ValueType ACtgh(const ValueType & x, ErrorCode * err = 0) + { + return ACoth(x, err); + } + + + + + + /* + * + * functions for converting between degrees, radians and gradians + * + * + */ + + + /*! + this function converts degrees to radians + + it returns: x * pi / 180 + */ + template + ValueType DegToRad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + // it is better to make division first and then multiplication + // the result is more accurate especially when x is: 90,180,270 or 360 + temp = 180; + c += result.Div(temp); + + temp.SetPi(); + c += result.Mul(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts radians to degrees + + it returns: x * 180 / pi + */ + template + ValueType RadToDeg(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, delimiter; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = 180; + c += result.Mul(x); + + delimiter.SetPi(); + c += result.Div(delimiter); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts degrees in the long format into one value + + long format: (degrees, minutes, seconds) + minutes and seconds must be greater than or equal zero + + result: + if d>=0 : result= d + ((s/60)+m)/60 + if d<0 : result= d - ((s/60)+m)/60 + + ((s/60)+m)/60 = (s+60*m)/3600 (second version is faster because + there's only one division) + + for example: + DegToDeg(10, 30, 0) = 10.5 + DegToDeg(10, 24, 35.6)=10.4098(8) + */ + template + ValueType DegToDeg( const ValueType & d, const ValueType & m, const ValueType & s, + ErrorCode * err = 0) + { + ValueType delimiter, multipler; + uint c = 0; + + if( d.IsNan() || m.IsNan() || s.IsNan() || m.IsSign() || s.IsSign() ) + { + if( err ) + *err = err_improper_argument; + + return delimiter ; // NaN is set by default + } + + multipler = 60; + delimiter = 3600; + + c += multipler.Mul(m); + c += multipler.Add(s); + c += multipler.Div(delimiter); + + if( d.IsSign() ) + multipler.ChangeSign(); + + c += multipler.Add(d); + + if( err ) + *err = c ? err_overflow : err_ok; + + return multipler; + } + + + /*! + this function converts degrees in the long format to radians + */ + template + ValueType DegToRad( const ValueType & d, const ValueType & m, const ValueType & s, + ErrorCode * err = 0) + { + ValueType temp_deg = DegToDeg(d,m,s,err); + + if( err && *err!=err_ok ) + return temp_deg; + + return DegToRad(temp_deg, err); + } + + + /*! + this function converts gradians to radians + + it returns: x * pi / 200 + */ + template + ValueType GradToRad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + // it is better to make division first and then multiplication + // the result is more accurate especially when x is: 100,200,300 or 400 + temp = 200; + c += result.Div(temp); + + temp.SetPi(); + c += result.Mul(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts radians to gradians + + it returns: x * 200 / pi + */ + template + ValueType RadToGrad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, delimiter; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = 200; + c += result.Mul(x); + + delimiter.SetPi(); + c += result.Div(delimiter); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts degrees to gradians + + it returns: x * 200 / 180 + */ + template + ValueType DegToGrad(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + temp = 200; + c += result.Mul(temp); + + temp = 180; + c += result.Div(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + /*! + this function converts degrees in the long format to gradians + */ + template + ValueType DegToGrad( const ValueType & d, const ValueType & m, const ValueType & s, + ErrorCode * err = 0) + { + ValueType temp_deg = DegToDeg(d,m,s,err); + + if( err && *err!=err_ok ) + return temp_deg; + + return DegToGrad(temp_deg, err); + } + + + /*! + this function converts degrees to gradians + + it returns: x * 180 / 200 + */ + template + ValueType GradToDeg(const ValueType & x, ErrorCode * err = 0) + { + ValueType result, temp; + uint c = 0; + + if( x.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + result = x; + + temp = 180; + c += result.Mul(temp); + + temp = 200; + c += result.Div(temp); + + if( err ) + *err = c ? err_overflow : err_ok; + + return result; + } + + + + + /* + * + * another functions + * + * + */ + + + /*! + this function calculates the square root + + Sqrt(9) = 3 + */ + template + ValueType Sqrt(ValueType x, ErrorCode * err = 0) + { + if( x.IsNan() || x.IsSign() ) + { + if( err ) + *err = err_improper_argument; + + return ValueType(); // NaN is set by default + } + + uint c = x.Sqrt(); + + if( err ) + *err = c ? err_overflow : err_ok; + + return x; + } + + + + namespace auxiliaryfunctions + { + + template + bool RootCheckIndexSign(ValueType & x, const ValueType & index, ErrorCode * err) + { + if( index.IsSign() ) + { + // index cannot be negative + if( err ) + *err = err_improper_argument; + + x.SetNan(); + + return true; + } + + return false; + } + + + template + 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 + 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 + bool RootCheckIndexTwo(ValueType & x, const ValueType & index, ErrorCode * err) + { + if( index == 2 ) + { + x = Sqrt(x, err); + + return true; + } + + return false; + } + + + template + 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 + 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 + 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 + 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 + index must be integer and not negative <0;1;2;3....) + + if index==0 the result is one + if x==0 the result is zero and we assume root(0;0) is not defined + + if index is even (2;4;6...) the result is x^(1/index) and x>0 + if index is odd (1;2;3;...) the result is either + -(abs(x)^(1/index)) if x<0 or + x^(1/index)) if x>0 + + (for index==1 the result is equal x) + */ + template + ValueType Root(ValueType x, const ValueType & index, ErrorCode * err = 0) + { + 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( RootCheckIndexZero(x, 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( RootCheckXZero (x, err) ) return x; + + // index integer and index!=0 + // x!=0 + + ValueType old_x(x); + bool change_sign; + + if( RootCheckIndex(x, index, err, &change_sign ) ) return x; + + ValueType temp; + uint c = 0; + + // 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 ) + { + // x is different from zero + x.SetSign(); + } + + c += RootCorrectInteger(old_x, x, index); + + if( err ) + *err = c ? err_overflow : err_ok; + + return x; + } + + + + /*! + absolute value of x + e.g. -2 = 2 + 2 = 2 + */ + template + 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 + 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 + 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 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 + void SetFactorialSequence(std::vector & fact, uint more = 20) + { + if( more == 0 ) + more = 1; + + uint start = static_cast(fact.size()); + fact.resize(fact.size() + more); + + if( start == 0 ) + { + fact[0] = 1; + ++start; + } + + for(uint i=start ; i + ValueType SetBernoulliNumbersSum(CGamma & cgamma, const ValueType & n_, uint m, + const volatile StopCalculating * stop = 0) + { + ValueType k_, temp, temp2, temp3, sum; + + sum.SetZero(); + + for(uint k=0 ; kWasStopSignal() ) + 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 + bool SetBernoulliNumbersMore(CGamma & cgamma, uint start, const volatile StopCalculating * stop = 0) + { + ValueType denominator, temp, temp2, temp3, m_, sum, sum2, n_, k_; + + const uint n = 2; + n_ = n; + + // start is >= 2 + for(uint m=start ; mWasStopSignal() ) + { + cgamma.bern.resize(m); // valid numbers are in [0, m-1] + return false; + } + + cgamma.bern[m].Div(denominator); + } + } + + 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 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 + bool SetBernoulliNumbers(CGamma & cgamma, uint more = 20, const volatile StopCalculating * stop = 0) + { + if( more == 0 ) + more = 1; + + uint start = static_cast(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(cgamma.bern.size() - cgamma.fact.size())); + + + 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 + ValueType GammaFactorialHighSum(const ValueType & n, CGamma & cgamma, ErrorCode & err, + const volatile StopCalculating * stop) + { + ValueType temp, temp2, denominator, sum, oldsum; + + sum.SetZero(); + + for(uint m=2 ; mWasStopSignal() ) + { + err = err_interrupt; + return ValueType(); // NaN + } + + temp = (m-1); + denominator = n; + denominator.Pow(temp); + // denominator = n ^ (m-1) + + 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 + } + } + + temp = cgamma.bern[m]; + temp.Div(denominator); + + oldsum = sum; + sum.Add(temp); + + if( sum.IsNan() || oldsum==sum ) + break; + } + + return sum; + } + + + /*! + 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 + ValueType GammaFactorialHigh(const ValueType & n, CGamma & 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; + } + + + /*! + an auxiliary function used to calculate the Gamma() function + + Gamma(x) = GammaFactorialHigh(x-1) + */ + template + ValueType GammaPlusHigh(ValueType n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + ValueType one; + + one.SetOne(); + n.Sub(one); + + return GammaFactorialHigh(n, cgamma, err, stop); + } + + + /*! + 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 + ValueType GammaPlusLowIntegerInt(uint n, CGamma & cgamma) + { + TTMATH_ASSERT( n > 0 ) + + if( n - 1 < static_cast(cgamma.fact.size()) ) + return cgamma.fact[n - 1]; + + ValueType res; + uint start = 2; + + if( cgamma.fact.size() < 2 ) + { + res.SetOne(); + } + else + { + start = static_cast(cgamma.fact.size()); + res = cgamma.fact[start-1]; + } + + for(uint i=start ; i + ValueType GammaPlusLowInteger(const ValueType & n, CGamma & 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. + gamma(3.89) = gamma(2001.89) / ( 3.89 * 4.89 * 5.89 * ... * 1999.89 * 2000.89 ) + */ + template + ValueType GammaPlusLow(ValueType n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + ValueType one, denominator, temp, boundary; + + if( n.IsInteger() ) + return GammaPlusLowInteger(n, cgamma); + + one.SetOne(); + denominator = n; + boundary = TTMATH_GAMMA_BOUNDARY; + + while( n < boundary ) + { + n.Add(one); + denominator.Mul(n); + } + + n.Add(one); + + // now n is sufficient big + temp = GammaPlusHigh(n, cgamma, err, stop); + temp.Div(denominator); + + return temp; + } + + + /*! + an auxiliary function used to calculate the Gamma() function + */ + template + ValueType GammaPlus(const ValueType & n, CGamma & cgamma, ErrorCode & err, const volatile StopCalculating * stop) + { + if( n > TTMATH_GAMMA_BOUNDARY ) + return GammaPlusHigh(n, cgamma, err, stop); + + return GammaPlusLow(n, cgamma, err, stop); + } + + + /*! + 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 + ValueType GammaMinus(const ValueType & n, CGamma & 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 + } + + 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 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 + ValueType Gamma(const ValueType & n, CGamma & cgamma, ErrorCode * err = 0, + const volatile StopCalculating * stop = 0) + { + using namespace auxiliaryfunctions; + + ValueType result; + ErrorCode err_tmp; + + if( n.IsNan() ) + { + if( err ) + *err = err_improper_argument; + + return result; // NaN is set by default + } + + if( cgamma.history.Get(n, result, err_tmp) ) + { + if( err ) + *err = err_tmp; + + return result; + } + + err_tmp = err_ok; + + if( n.IsSign() ) + { + result = GammaMinus(n, cgamma, err_tmp, stop); + } + else + if( n.IsZero() ) + { + err_tmp = err_improper_argument; + result.SetNan(); + } + else + { + result = GammaPlus(n, cgamma, err_tmp, stop); + } + + 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; + } + + + /*! + this function calculates the Gamma function + + note: this function should be used only in a single-thread environment + */ + template + ValueType Gamma(const ValueType & n, ErrorCode * err = 0) + { + // warning: this static object is not thread safe + static CGamma cgamma; + + return Gamma(n, cgamma, err); + } + + + + namespace auxiliaryfunctions + { + + /*! + an auxiliary function for calculating the factorial function + + we use the formula: + x! = gamma(x+1) + */ + template + ValueType Factorial2(ValueType x, + CGamma * cgamma = 0, + ErrorCode * err = 0, + const volatile StopCalculating * stop = 0) + { + ValueType result, one; + + 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 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. + typedef Big<1,2> MyBig; + MyBig x=234, y=54345; + CGamma 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 + ValueType Factorial(const ValueType & x, CGamma & cgamma, ErrorCode * err = 0, + const volatile StopCalculating * stop = 0) + { + return auxiliaryfunctions::Factorial2(x, &cgamma, err, stop); + } + + + /*! + the factorial from given 'x' + e.g. + Factorial(4) = 4! = 1*2*3*4 + + note: this function should be used only in a single-thread environment + */ + template + ValueType Factorial(const ValueType & x, ErrorCode * err = 0) + { + return auxiliaryfunctions::Factorial2(x, (CGamma*)0, err, 0); + } + + + /*! + 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 + void CGamma::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 fewer coefficients we need + Gamma(x, *this); + } + + + +} // namespace + + +/*! + this is for convenience for the user + he can only use '#include ' even if he uses the parser +*/ +#include "ttmathparser.h" + + +#ifdef _MSC_VER +//warning C4127: conditional expression is constant +#pragma warning( default: 4127 ) +//warning C4702: unreachable code +#pragma warning( default: 4702 ) +//warning C4800: forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( default: 4800 ) +#endif + +#endif diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h new file mode 100644 index 0000000..771f9c8 --- /dev/null +++ b/ttmath/ttmathbig.h @@ -0,0 +1,5236 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2010, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfilettmathbig +#define headerfilettmathbig + +/*! + \file ttmathbig.h + \brief A Class for representing floating point numbers +*/ + +#include "ttmathint.h" +#include "ttmaththreads.h" + +#include + +#ifdef TTMATH_MULTITHREADS +#include +#endif + +namespace ttmath +{ + + +/*! + \brief Big implements the floating point numbers +*/ +template +class Big +{ + +/* + value = mantissa * 2^exponent + + exponent - an integer value with a sign + mantissa - an integer value without a sing + + mantissa must be pushed into the left side that is the highest bit from + mantissa must be one (of course if there's another value than zero) -- this job + (pushing bits into the left side) making Standardizing() method + + for example: + if we want to store value one (1) into our Big object we must: + set mantissa to 1 + set exponent to 0 + set info to 0 + and call method Standardizing() +*/ + + +public: + +Int exponent; +UInt mantissa; +unsigned char info; + + +/*! + Sign + the mask of a bit from 'info' which means that there is a sign + (when the bit is set) +*/ +#define TTMATH_BIG_SIGN 128 + + +/*! + Not a number + if this bit is set that there is not a valid number +*/ +#define TTMATH_BIG_NAN 64 + + +/*! + Zero + if this bit is set that there is value zero + mantissa should be zero and exponent should be zero too + (the Standardizing() method does this) +*/ +#define TTMATH_BIG_ZERO 32 + + + /*! + this method sets NaN if there was a carry (and returns 1 in such a case) + + c can be 0, 1 or other value different from zero + */ + uint CheckCarry(uint c) + { + if( c != 0 ) + { + SetNan(); + return 1; + } + + return 0; + } + +public: + + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + static const char * LibTypeStr() + { + return UInt::LibTypeStr(); + } + + + /*! + returning the currect type of the library + */ + static LibTypeCode LibType() + { + return UInt::LibType(); + } + + + + /*! + this method moves all bits from mantissa into its left side + (suitably changes the exponent) or if the mantissa is zero + it sets the exponent to zero as well + (and clears the sign bit and sets the zero bit) + + it can return a carry + the carry will be when we don't have enough space in the exponent + + you don't have to use this method if you don't change the mantissa + and exponent directly + */ + uint Standardizing() + { + if( mantissa.IsTheHighestBitSet() ) + { + ClearInfoBit(TTMATH_BIG_ZERO); + return 0; + } + + if( CorrectZero() ) + return 0; + + uint comp = mantissa.CompensationToLeft(); + + return exponent.Sub( comp ); + } + + +private: + + /*! + if the mantissa is equal zero this method sets exponent to zero and + info without the sign + + it returns true if there was the correction + */ + bool CorrectZero() + { + if( mantissa.IsZero() ) + { + SetInfoBit(TTMATH_BIG_ZERO); + ClearInfoBit(TTMATH_BIG_SIGN); + exponent.SetZero(); + + return true; + } + else + { + ClearInfoBit(TTMATH_BIG_ZERO); + } + + return false; + } + + +public: + + /*! + this method clears a specific bit in the 'info' variable + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + */ + void ClearInfoBit(unsigned char bit) + { + info = info & (~bit); + } + + + /*! + this method sets a specific bit in the 'info' variable + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + + */ + void SetInfoBit(unsigned char bit) + { + info = info | bit; + } + + + /*! + this method returns true if a specific bit in the 'info' variable is set + + bit is one of: TTMATH_BIG_SIGN, TTMATH_BIG_NAN etc. + */ + bool IsInfoBit(unsigned char bit) const + { + return (info & bit) != 0; + } + + + /*! + this method sets zero + */ + void SetZero() + { + info = TTMATH_BIG_ZERO; + exponent.SetZero(); + mantissa.SetZero(); + + /* + we don't have to compensate zero + */ + } + + + /*! + this method sets one + */ + void SetOne() + { + FromUInt(1); + } + + + /*! + this method sets value 0.5 + */ + void Set05() + { + FromUInt(1); + exponent.SubOne(); + } + + + /*! + this method sets NaN flag (Not a Number) + when this flag is set that means there is no a valid number + */ + void SetNan() + { + SetInfoBit(TTMATH_BIG_NAN); + } + + +private: + + /*! + this method sets the mantissa of the value of pi + */ + void SetMantissaPi() + { + // this is a static table which represents the value of Pi (mantissa of it) + // (first is the highest word) + // we must define this table as 'unsigned int' because + // both on 32bit and 64bit platforms this table is 32bit + static const unsigned int temp_table[] = { + 0xc90fdaa2, 0x2168c234, 0xc4c6628b, 0x80dc1cd1, 0x29024e08, 0x8a67cc74, 0x020bbea6, 0x3b139b22, + 0x514a0879, 0x8e3404dd, 0xef9519b3, 0xcd3a431b, 0x302b0a6d, 0xf25f1437, 0x4fe1356d, 0x6d51c245, + 0xe485b576, 0x625e7ec6, 0xf44c42e9, 0xa637ed6b, 0x0bff5cb6, 0xf406b7ed, 0xee386bfb, 0x5a899fa5, + 0xae9f2411, 0x7c4b1fe6, 0x49286651, 0xece45b3d, 0xc2007cb8, 0xa163bf05, 0x98da4836, 0x1c55d39a, + 0x69163fa8, 0xfd24cf5f, 0x83655d23, 0xdca3ad96, 0x1c62f356, 0x208552bb, 0x9ed52907, 0x7096966d, + 0x670c354e, 0x4abc9804, 0xf1746c08, 0xca18217c, 0x32905e46, 0x2e36ce3b, 0xe39e772c, 0x180e8603, + 0x9b2783a2, 0xec07a28f, 0xb5c55df0, 0x6f4c52c9, 0xde2bcbf6, 0x95581718, 0x3995497c, 0xea956ae5, + 0x15d22618, 0x98fa0510, 0x15728e5a, 0x8aaac42d, 0xad33170d, 0x04507a33, 0xa85521ab, 0xdf1cba64, + 0xecfb8504, 0x58dbef0a, 0x8aea7157, 0x5d060c7d, 0xb3970f85, 0xa6e1e4c7, 0xabf5ae8c, 0xdb0933d7, + 0x1e8c94e0, 0x4a25619d, 0xcee3d226, 0x1ad2ee6b, 0xf12ffa06, 0xd98a0864, 0xd8760273, 0x3ec86a64, + 0x521f2b18, 0x177b200c, 0xbbe11757, 0x7a615d6c, 0x770988c0, 0xbad946e2, 0x08e24fa0, 0x74e5ab31, + 0x43db5bfc, 0xe0fd108e, 0x4b82d120, 0xa9210801, 0x1a723c12, 0xa787e6d7, 0x88719a10, 0xbdba5b26, + 0x99c32718, 0x6af4e23c, 0x1a946834, 0xb6150bda, 0x2583e9ca, 0x2ad44ce8, 0xdbbbc2db, 0x04de8ef9, + 0x2e8efc14, 0x1fbecaa6, 0x287c5947, 0x4e6bc05d, 0x99b2964f, 0xa090c3a2, 0x233ba186, 0x515be7ed, + 0x1f612970, 0xcee2d7af, 0xb81bdd76, 0x2170481c, 0xd0069127, 0xd5b05aa9, 0x93b4ea98, 0x8d8fddc1, + 0x86ffb7dc, 0x90a6c08f, 0x4df435c9, 0x34028492, 0x36c3fab4, 0xd27c7026, 0xc1d4dcb2, 0x602646de, + 0xc9751e76, 0x3dba37bd, 0xf8ff9406, 0xad9e530e, 0xe5db382f, 0x413001ae, 0xb06a53ed, 0x9027d831, + 0x179727b0, 0x865a8918, 0xda3edbeb, 0xcf9b14ed, 0x44ce6cba, 0xced4bb1b, 0xdb7f1447, 0xe6cc254b, + 0x33205151, 0x2bd7af42, 0x6fb8f401, 0x378cd2bf, 0x5983ca01, 0xc64b92ec, 0xf032ea15, 0xd1721d03, + 0xf482d7ce, 0x6e74fef6, 0xd55e702f, 0x46980c82, 0xb5a84031, 0x900b1c9e, 0x59e7c97f, 0xbec7e8f3, + 0x23a97a7e, 0x36cc88be, 0x0f1d45b7, 0xff585ac5, 0x4bd407b2, 0x2b4154aa, 0xcc8f6d7e, 0xbf48e1d8, + 0x14cc5ed2, 0x0f8037e0, 0xa79715ee, 0xf29be328, 0x06a1d58b, 0xb7c5da76, 0xf550aa3d, 0x8a1fbff0, + 0xeb19ccb1, 0xa313d55c, 0xda56c9ec, 0x2ef29632, 0x387fe8d7, 0x6e3c0468, 0x043e8f66, 0x3f4860ee, + 0x12bf2d5b, 0x0b7474d6, 0xe694f91e, 0x6dbe1159, 0x74a3926f, 0x12fee5e4, 0x38777cb6, 0xa932df8c, + 0xd8bec4d0, 0x73b931ba, 0x3bc832b6, 0x8d9dd300, 0x741fa7bf, 0x8afc47ed, 0x2576f693, 0x6ba42466, + 0x3aab639c, 0x5ae4f568, 0x3423b474, 0x2bf1c978, 0x238f16cb, 0xe39d652d, 0xe3fdb8be, 0xfc848ad9, + 0x22222e04, 0xa4037c07, 0x13eb57a8, 0x1a23f0c7, 0x3473fc64, 0x6cea306b, 0x4bcbc886, 0x2f8385dd, + 0xfa9d4b7f, 0xa2c087e8, 0x79683303, 0xed5bdd3a, 0x062b3cf5, 0xb3a278a6, 0x6d2a13f8, 0x3f44f82d, + 0xdf310ee0, 0x74ab6a36, 0x4597e899, 0xa0255dc1, 0x64f31cc5, 0x0846851d, 0xf9ab4819, 0x5ded7ea1, + 0xb1d510bd, 0x7ee74d73, 0xfaf36bc3, 0x1ecfa268, 0x359046f4, 0xeb879f92, 0x4009438b, 0x481c6cd7, + 0x889a002e, 0xd5ee382b, 0xc9190da6, 0xfc026e47, 0x9558e447, 0x5677e9aa, 0x9e3050e2, 0x765694df, + 0xc81f56e8, 0x80b96e71, 0x60c980dd, 0x98a573ea, 0x4472065a, 0x139cd290, 0x6cd1cb72, 0x9ec52a53 // last one was: 0x9ec52a52 + //0x86d44014, ... + // (the last word 0x9ec52a52 was rounded up because the next one is 0x86d44014 -- first bit is one 0x8..) + // 256 32bit words for the mantissa -- about 2464 valid decimal digits + }; + // the value of PI is comming from the website http://zenwerx.com/pi.php + // 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 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)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + } + +public: + + + /*! + this method sets the value of pi + */ + void SetPi() + { + SetMantissaPi(); + info = 0; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; + } + + + /*! + this method sets the value of 0.5 * pi + */ + void Set05Pi() + { + SetMantissaPi(); + info = 0; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 1; + } + + + /*! + this method sets the value of 2 * pi + */ + void Set2Pi() + { + SetMantissaPi(); + info = 0; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 3; + } + + + /*! + this method sets the value of e + (the base of the natural logarithm) + */ + void SetE() + { + static const unsigned int temp_table[] = { + 0xadf85458, 0xa2bb4a9a, 0xafdc5620, 0x273d3cf1, 0xd8b9c583, 0xce2d3695, 0xa9e13641, 0x146433fb, + 0xcc939dce, 0x249b3ef9, 0x7d2fe363, 0x630c75d8, 0xf681b202, 0xaec4617a, 0xd3df1ed5, 0xd5fd6561, + 0x2433f51f, 0x5f066ed0, 0x85636555, 0x3ded1af3, 0xb557135e, 0x7f57c935, 0x984f0c70, 0xe0e68b77, + 0xe2a689da, 0xf3efe872, 0x1df158a1, 0x36ade735, 0x30acca4f, 0x483a797a, 0xbc0ab182, 0xb324fb61, + 0xd108a94b, 0xb2c8e3fb, 0xb96adab7, 0x60d7f468, 0x1d4f42a3, 0xde394df4, 0xae56ede7, 0x6372bb19, + 0x0b07a7c8, 0xee0a6d70, 0x9e02fce1, 0xcdf7e2ec, 0xc03404cd, 0x28342f61, 0x9172fe9c, 0xe98583ff, + 0x8e4f1232, 0xeef28183, 0xc3fe3b1b, 0x4c6fad73, 0x3bb5fcbc, 0x2ec22005, 0xc58ef183, 0x7d1683b2, + 0xc6f34a26, 0xc1b2effa, 0x886b4238, 0x611fcfdc, 0xde355b3b, 0x6519035b, 0xbc34f4de, 0xf99c0238, + 0x61b46fc9, 0xd6e6c907, 0x7ad91d26, 0x91f7f7ee, 0x598cb0fa, 0xc186d91c, 0xaefe1309, 0x85139270, + 0xb4130c93, 0xbc437944, 0xf4fd4452, 0xe2d74dd3, 0x64f2e21e, 0x71f54bff, 0x5cae82ab, 0x9c9df69e, + 0xe86d2bc5, 0x22363a0d, 0xabc52197, 0x9b0deada, 0x1dbf9a42, 0xd5c4484e, 0x0abcd06b, 0xfa53ddef, + 0x3c1b20ee, 0x3fd59d7c, 0x25e41d2b, 0x669e1ef1, 0x6e6f52c3, 0x164df4fb, 0x7930e9e4, 0xe58857b6, + 0xac7d5f42, 0xd69f6d18, 0x7763cf1d, 0x55034004, 0x87f55ba5, 0x7e31cc7a, 0x7135c886, 0xefb4318a, + 0xed6a1e01, 0x2d9e6832, 0xa907600a, 0x918130c4, 0x6dc778f9, 0x71ad0038, 0x092999a3, 0x33cb8b7a, + 0x1a1db93d, 0x7140003c, 0x2a4ecea9, 0xf98d0acc, 0x0a8291cd, 0xcec97dcf, 0x8ec9b55a, 0x7f88a46b, + 0x4db5a851, 0xf44182e1, 0xc68a007e, 0x5e0dd902, 0x0bfd64b6, 0x45036c7a, 0x4e677d2c, 0x38532a3a, + 0x23ba4442, 0xcaf53ea6, 0x3bb45432, 0x9b7624c8, 0x917bdd64, 0xb1c0fd4c, 0xb38e8c33, 0x4c701c3a, + 0xcdad0657, 0xfccfec71, 0x9b1f5c3e, 0x4e46041f, 0x388147fb, 0x4cfdb477, 0xa52471f7, 0xa9a96910, + 0xb855322e, 0xdb6340d8, 0xa00ef092, 0x350511e3, 0x0abec1ff, 0xf9e3a26e, 0x7fb29f8c, 0x183023c3, + 0x587e38da, 0x0077d9b4, 0x763e4e4b, 0x94b2bbc1, 0x94c6651e, 0x77caf992, 0xeeaac023, 0x2a281bf6, + 0xb3a739c1, 0x22611682, 0x0ae8db58, 0x47a67cbe, 0xf9c9091b, 0x462d538c, 0xd72b0374, 0x6ae77f5e, + 0x62292c31, 0x1562a846, 0x505dc82d, 0xb854338a, 0xe49f5235, 0xc95b9117, 0x8ccf2dd5, 0xcacef403, + 0xec9d1810, 0xc6272b04, 0x5b3b71f9, 0xdc6b80d6, 0x3fdd4a8e, 0x9adb1e69, 0x62a69526, 0xd43161c1, + 0xa41d570d, 0x7938dad4, 0xa40e329c, 0xcff46aaa, 0x36ad004c, 0xf600c838, 0x1e425a31, 0xd951ae64, + 0xfdb23fce, 0xc9509d43, 0x687feb69, 0xedd1cc5e, 0x0b8cc3bd, 0xf64b10ef, 0x86b63142, 0xa3ab8829, + 0x555b2f74, 0x7c932665, 0xcb2c0f1c, 0xc01bd702, 0x29388839, 0xd2af05e4, 0x54504ac7, 0x8b758282, + 0x2846c0ba, 0x35c35f5c, 0x59160cc0, 0x46fd8251, 0x541fc68c, 0x9c86b022, 0xbb709987, 0x6a460e74, + 0x51a8a931, 0x09703fee, 0x1c217e6c, 0x3826e52c, 0x51aa691e, 0x0e423cfc, 0x99e9e316, 0x50c1217b, + 0x624816cd, 0xad9a95f9, 0xd5b80194, 0x88d9c0a0, 0xa1fe3075, 0xa577e231, 0x83f81d4a, 0x3f2fa457, + 0x1efc8ce0, 0xba8a4fe8, 0xb6855dfe, 0x72b0a66e, 0xded2fbab, 0xfbe58a30, 0xfafabe1c, 0x5d71a87e, + 0x2f741ef8, 0xc1fe86fe, 0xa6bbfde5, 0x30677f0d, 0x97d11d49, 0xf7a8443d, 0x0822e506, 0xa9f4614e, + 0x011e2a94, 0x838ff88c, 0xd68c8bb7, 0xc51eef6d, 0x49ea8ab4, 0xf2c3df5b, 0xb4e0735a, 0xb0d68749 + // 0x2fe26dd4, ... + // 256 32bit words for the mantissa -- about 2464 valid decimal digits + }; + + // above value was calculated using Big<1,400> type on a 32bit platform + // and then the first 256 words were taken, + // the calculating was made by using ExpSurrounding0(1) method + // which took 1420 iterations + // (the result was compared with e taken from http://antwrp.gsfc.nasa.gov/htmltest/gifcity/e.2mil) + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; + info = 0; + } + + + /*! + this method sets the value of ln(2) + the natural logarithm from 2 + */ + void SetLn2() + { + static const unsigned int temp_table[] = { + 0xb17217f7, 0xd1cf79ab, 0xc9e3b398, 0x03f2f6af, 0x40f34326, 0x7298b62d, 0x8a0d175b, 0x8baafa2b, + 0xe7b87620, 0x6debac98, 0x559552fb, 0x4afa1b10, 0xed2eae35, 0xc1382144, 0x27573b29, 0x1169b825, + 0x3e96ca16, 0x224ae8c5, 0x1acbda11, 0x317c387e, 0xb9ea9bc3, 0xb136603b, 0x256fa0ec, 0x7657f74b, + 0x72ce87b1, 0x9d6548ca, 0xf5dfa6bd, 0x38303248, 0x655fa187, 0x2f20e3a2, 0xda2d97c5, 0x0f3fd5c6, + 0x07f4ca11, 0xfb5bfb90, 0x610d30f8, 0x8fe551a2, 0xee569d6d, 0xfc1efa15, 0x7d2e23de, 0x1400b396, + 0x17460775, 0xdb8990e5, 0xc943e732, 0xb479cd33, 0xcccc4e65, 0x9393514c, 0x4c1a1e0b, 0xd1d6095d, + 0x25669b33, 0x3564a337, 0x6a9c7f8a, 0x5e148e82, 0x074db601, 0x5cfe7aa3, 0x0c480a54, 0x17350d2c, + 0x955d5179, 0xb1e17b9d, 0xae313cdb, 0x6c606cb1, 0x078f735d, 0x1b2db31b, 0x5f50b518, 0x5064c18b, + 0x4d162db3, 0xb365853d, 0x7598a195, 0x1ae273ee, 0x5570b6c6, 0x8f969834, 0x96d4e6d3, 0x30af889b, + 0x44a02554, 0x731cdc8e, 0xa17293d1, 0x228a4ef9, 0x8d6f5177, 0xfbcf0755, 0x268a5c1f, 0x9538b982, + 0x61affd44, 0x6b1ca3cf, 0x5e9222b8, 0x8c66d3c5, 0x422183ed, 0xc9942109, 0x0bbb16fa, 0xf3d949f2, + 0x36e02b20, 0xcee886b9, 0x05c128d5, 0x3d0bd2f9, 0x62136319, 0x6af50302, 0x0060e499, 0x08391a0c, + 0x57339ba2, 0xbeba7d05, 0x2ac5b61c, 0xc4e9207c, 0xef2f0ce2, 0xd7373958, 0xd7622658, 0x901e646a, + 0x95184460, 0xdc4e7487, 0x156e0c29, 0x2413d5e3, 0x61c1696d, 0xd24aaebd, 0x473826fd, 0xa0c238b9, + 0x0ab111bb, 0xbd67c724, 0x972cd18b, 0xfbbd9d42, 0x6c472096, 0xe76115c0, 0x5f6f7ceb, 0xac9f45ae, + 0xcecb72f1, 0x9c38339d, 0x8f682625, 0x0dea891e, 0xf07afff3, 0xa892374e, 0x175eb4af, 0xc8daadd8, + 0x85db6ab0, 0x3a49bd0d, 0xc0b1b31d, 0x8a0e23fa, 0xc5e5767d, 0xf95884e0, 0x6425a415, 0x26fac51c, + 0x3ea8449f, 0xe8f70edd, 0x062b1a63, 0xa6c4c60c, 0x52ab3316, 0x1e238438, 0x897a39ce, 0x78b63c9f, + 0x364f5b8a, 0xef22ec2f, 0xee6e0850, 0xeca42d06, 0xfb0c75df, 0x5497e00c, 0x554b03d7, 0xd2874a00, + 0x0ca8f58d, 0x94f0341c, 0xbe2ec921, 0x56c9f949, 0xdb4a9316, 0xf281501e, 0x53daec3f, 0x64f1b783, + 0x154c6032, 0x0e2ff793, 0x33ce3573, 0xfacc5fdc, 0xf1178590, 0x3155bbd9, 0x0f023b22, 0x0224fcd8, + 0x471bf4f4, 0x45f0a88a, 0x14f0cd97, 0x6ea354bb, 0x20cdb5cc, 0xb3db2392, 0x88d58655, 0x4e2a0e8a, + 0x6fe51a8c, 0xfaa72ef2, 0xad8a43dc, 0x4212b210, 0xb779dfe4, 0x9d7307cc, 0x846532e4, 0xb9694eda, + 0xd162af05, 0x3b1751f3, 0xa3d091f6, 0x56658154, 0x12b5e8c2, 0x02461069, 0xac14b958, 0x784934b8, + 0xd6cce1da, 0xa5053701, 0x1aa4fb42, 0xb9a3def4, 0x1bda1f85, 0xef6fdbf2, 0xf2d89d2a, 0x4b183527, + 0x8fd94057, 0x89f45681, 0x2b552879, 0xa6168695, 0xc12963b0, 0xff01eaab, 0x73e5b5c1, 0x585318e7, + 0x624f14a5, 0x1a4a026b, 0x68082920, 0x57fd99b6, 0x6dc085a9, 0x8ac8d8ca, 0xf9eeeea9, 0x8a2400ca, + 0xc95f260f, 0xd10036f9, 0xf91096ac, 0x3195220a, 0x1a356b2a, 0x73b7eaad, 0xaf6d6058, 0x71ef7afb, + 0x80bc4234, 0x33562e94, 0xb12dfab4, 0x14451579, 0xdf59eae0, 0x51707062, 0x4012a829, 0x62c59cab, + 0x347f8304, 0xd889659e, 0x5a9139db, 0x14efcc30, 0x852be3e8, 0xfc99f14d, 0x1d822dd6, 0xe2f76797, + 0xe30219c8, 0xaa9ce884, 0x8a886eb3, 0xc87b7295, 0x988012e8, 0x314186ed, 0xbaf86856, 0xccd3c3b6, + 0xee94e62f, 0x110a6783, 0xd2aae89c, 0xcc3b76fc, 0x435a0ce1, 0x34c2838f, 0xd571ec6c, 0x1366a993 // last one was: 0x1366a992 + //0xcbb9ac40, ... + // (the last word 0x1366a992 was rounded up because the next one is 0xcbb9ac40 -- first bit is one 0xc..) + // 256 32bit words for the mantissa -- about 2464 valid decimal digits + }; + + // above value was calculated using Big<1,400> type on a 32bit platform + // and then the first 256 words were taken, + // the calculating was made by using LnSurrounding1(2) method + // which took 4035 iterations + // (the result was compared with ln(2) taken from http://ja0hxv.calico.jp/pai/estart.html) + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT); + info = 0; + } + + + /*! + this method sets the value of ln(10) + the natural logarithm from 10 + + I introduced this constant especially to make the conversion ToString() + being faster. In fact the method ToString() is keeping values of logarithms + it has calculated but it must calculate the logarithm at least once. + If a program, which uses this library, is running for a long time this + would be ok, but for programs which are running shorter, for example for + CGI applications which only once are printing values, this would be much + inconvenience. Then if we're printing with base (radix) 10 and the mantissa + of our value is smaller than or equal to TTMATH_BUILTIN_VARIABLES_SIZE + we don't calculate the logarithm but take it from this constant. + */ + void SetLn10() + { + static const unsigned int temp_table[] = { + 0x935d8ddd, 0xaaa8ac16, 0xea56d62b, 0x82d30a28, 0xe28fecf9, 0xda5df90e, 0x83c61e82, 0x01f02d72, + 0x962f02d7, 0xb1a8105c, 0xcc70cbc0, 0x2c5f0d68, 0x2c622418, 0x410be2da, 0xfb8f7884, 0x02e516d6, + 0x782cf8a2, 0x8a8c911e, 0x765aa6c3, 0xb0d831fb, 0xef66ceb0, 0x4ab3c6fa, 0x5161bb49, 0xd219c7bb, + 0xca67b35b, 0x23605085, 0x8e93368d, 0x44789c4f, 0x5b08b057, 0xd5ede20f, 0x469ea58e, 0x9305e981, + 0xe2478fca, 0xad3aee98, 0x9cd5b42e, 0x6a271619, 0xa47ecb26, 0x978c5d4f, 0xdb1d28ea, 0x57d4fdc0, + 0xe40bf3cc, 0x1e14126a, 0x45765cde, 0x268339db, 0xf47fa96d, 0xeb271060, 0xaf88486e, 0xa9b7401e, + 0x3dfd3c51, 0x748e6d6e, 0x3848c8d2, 0x5faf1bca, 0xe88047f1, 0x7b0d9b50, 0xa949eaaa, 0xdf69e8a5, + 0xf77e3760, 0x4e943960, 0xe38a5700, 0xffde2db1, 0xad6bfbff, 0xd821ba0a, 0x4cb0466d, 0x61ba648e, + 0xef99c8e5, 0xf6974f36, 0x3982a78c, 0xa45ddfc8, 0x09426178, 0x19127a6e, 0x3b70fcda, 0x2d732d47, + 0xb5e4b1c8, 0xc0e5a10a, 0xaa6604a5, 0x324ec3dc, 0xbc64ea80, 0x6e198566, 0x1f1d366c, 0x20663834, + 0x4d5e843f, 0x20642b97, 0x0a62d18e, 0x478f7bd5, 0x8fcd0832, 0x4a7b32a6, 0xdef85a05, 0xeb56323a, + 0x421ef5e0, 0xb00410a0, 0xa0d9c260, 0x794a976f, 0xf6ff363d, 0xb00b6b33, 0xf42c58de, 0xf8a3c52d, + 0xed69b13d, 0xc1a03730, 0xb6524dc1, 0x8c167e86, 0x99d6d20e, 0xa2defd2b, 0xd006f8b4, 0xbe145a2a, + 0xdf3ccbb3, 0x189da49d, 0xbc1261c8, 0xb3e4daad, 0x6a36cecc, 0xb2d5ae5b, 0x89bf752f, 0xb5dfb353, + 0xff3065c4, 0x0cfceec8, 0x1be5a9a9, 0x67fddc57, 0xc4b83301, 0x006bf062, 0x4b40ed7a, 0x56c6cdcd, + 0xa2d6fe91, 0x388e9e3e, 0x48a93f5f, 0x5e3b6eb4, 0xb81c4a5b, 0x53d49ea6, 0x8e668aea, 0xba83c7f8, + 0xfb5f06c3, 0x58ac8f70, 0xfa9d8c59, 0x8c574502, 0xbaf54c96, 0xc84911f0, 0x0482d095, 0x1a0af022, + 0xabbab080, 0xec97efd3, 0x671e4e0e, 0x52f166b6, 0xcd5cd226, 0x0dc67795, 0x2e1e34a3, 0xf799677f, + 0x2c1d48f1, 0x2944b6c5, 0x2ba1307e, 0x704d67f9, 0x1c1035e4, 0x4e927c63, 0x03cf12bf, 0xe2cd2e31, + 0xf8ee4843, 0x344d51b0, 0xf37da42b, 0x9f0b0fd9, 0x134fb2d9, 0xf815e490, 0xd966283f, 0x23962766, + 0xeceab1e4, 0xf3b5fc86, 0x468127e2, 0xb606d10d, 0x3a45f4b6, 0xb776102d, 0x2fdbb420, 0x80c8fa84, + 0xd0ff9f45, 0xc58aef38, 0xdb2410fd, 0x1f1cebad, 0x733b2281, 0x52ca5f36, 0xddf29daa, 0x544334b8, + 0xdeeaf659, 0x4e462713, 0x1ed485b4, 0x6a0822e1, 0x28db471c, 0xa53938a8, 0x44c3bef7, 0xf35215c8, + 0xb382bc4e, 0x3e4c6f15, 0x6285f54c, 0x17ab408e, 0xccbf7f5e, 0xd16ab3f6, 0xced2846d, 0xf457e14f, + 0xbb45d9c5, 0x646ad497, 0xac697494, 0x145de32e, 0x93907128, 0xd263d521, 0x79efb424, 0xd64651d6, + 0xebc0c9f0, 0xbb583a44, 0xc6412c84, 0x85bb29a6, 0x4d31a2cd, 0x92954469, 0xa32b1abd, 0xf7f5202c, + 0xa4aa6c93, 0x2e9b53cf, 0x385ab136, 0x2741f356, 0x5de9c065, 0x6009901c, 0x88abbdd8, 0x74efcf73, + 0x3f761ad4, 0x35f3c083, 0xfd6b8ee0, 0x0bef11c7, 0xc552a89d, 0x58ce4a21, 0xd71e54f2, 0x4157f6c7, + 0xd4622316, 0xe98956d7, 0x450027de, 0xcbd398d8, 0x4b98b36a, 0x0724c25c, 0xdb237760, 0xe9324b68, + 0x7523e506, 0x8edad933, 0x92197f00, 0xb853a326, 0xb330c444, 0x65129296, 0x34bc0670, 0xe177806d, + 0xe338dac4, 0x5537492a, 0xe19add83, 0xcf45000f, 0x5b423bce, 0x6497d209, 0xe30e18a1, 0x3cbf0687, + 0x67973103, 0xd9485366, 0x81506bba, 0x2e93a9a4, 0x7dd59d3f, 0xf17cd746, 0x8c2075be, 0x552a4348 // last one was: 0x552a4347 + // 0xb4a638ef, ... + //(the last word 0x552a4347 was rounded up because the next one is 0xb4a638ef -- first bit is one 0xb..) + // 256 32bit words for the mantissa -- about 2464 valid digits (decimal) + }; + + // above value was calculated using Big<1,400> type on a 32bit platform + // and then the first 256 32bit words were taken, + // the calculating was made by using LnSurrounding1(10) method + // which took 22080 iterations + // (the result was compared with ln(10) taken from http://ja0hxv.calico.jp/pai/estart.html) + // (the formula used in LnSurrounding1(x) converges badly when + // the x is greater than one but in fact we can use it, only the + // number of iterations will be greater) + // (TTMATH_BUILTIN_VARIABLES_SIZE on 32bit platform should have the value 256, + // and on 64bit platform value 128 (256/2=128)) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(int)); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; + info = 0; + } + + + /*! + this method sets the maximum value which can be held in this type + */ + void SetMax() + { + info = 0; + mantissa.SetMax(); + exponent.SetMax(); + + // we don't have to use 'Standardizing()' because the last bit from + // the mantissa is set + } + + + /*! + this method sets the minimum value which can be held in this type + */ + void SetMin() + { + info = 0; + + mantissa.SetMax(); + exponent.SetMax(); + SetSign(); + + // we don't have to use 'Standardizing()' because the last bit from + // the mantissa is set + } + + + /*! + testing whether there is a value zero or not + */ + bool IsZero() const + { + return IsInfoBit(TTMATH_BIG_ZERO); + } + + + /*! + this method returns true when there's the sign set + also we don't check the NaN flag + */ + bool IsSign() const + { + return IsInfoBit(TTMATH_BIG_SIGN); + } + + + /*! + this method returns true when there is not a valid number + */ + bool IsNan() const + { + return IsInfoBit(TTMATH_BIG_NAN); + } + + + + /*! + this method clears the sign + (there'll be an absolute value) + + e.g. + -1 -> 1 + 2 -> 2 + */ + void Abs() + { + ClearInfoBit(TTMATH_BIG_SIGN); + } + + + /*! + this method remains the 'sign' of the value + e.g. -2 = -1 + 0 = 0 + 10 = 1 + */ + void Sgn() + { + // we have to check the NaN flag, because the next SetOne() method would clear it + if( IsNan() ) + return; + + if( IsSign() ) + { + SetOne(); + SetSign(); + } + else + if( IsZero() ) + SetZero(); + else + SetOne(); + } + + + + /*! + this method sets the sign + + e.g. + -1 -> -1 + 2 -> -2 + + we do not check whether there is a zero or not, if you're using this method + you must be sure that the value is (or will be afterwards) different from zero + */ + void SetSign() + { + SetInfoBit(TTMATH_BIG_SIGN); + } + + + /*! + this method changes the sign + when there is a value of zero then the sign is not changed + + e.g. + -1 -> 1 + 2 -> -2 + */ + void ChangeSign() + { + // we don't have to check the NaN flag here + + if( IsZero() ) + return; + + if( IsSign() ) + ClearInfoBit(TTMATH_BIG_SIGN); + else + SetInfoBit(TTMATH_BIG_SIGN); + } + + + +private: + + /*! + this method does the half-to-even rounding (banker's rounding) + + if is_half is: + true - that means the rest was equal the half (0.5 decimal) + false - that means the rest was greater than a half (greater than 0.5 decimal) + + if the rest was less than a half then don't call this method + (the rounding should does nothing then) + */ + uint RoundHalfToEven(bool is_half, bool rounding_up = true) + { + uint c = 0; + + if( !is_half || mantissa.IsTheLowestBitSet() ) + { + if( rounding_up ) + { + if( mantissa.AddOne() ) + { + mantissa.Rcr(1, 1); + c = exponent.AddOne(); + } + } + else + { + #ifdef TTMATH_DEBUG + uint c_from_zero = + #endif + mantissa.SubOne(); + + // we're using rounding_up=false in Add() when the mantissas have different signs + // mantissa can be zero only when previous mantissa was equal to ss2.mantissa + // but in such a case 'last_bit_set' will not be set and consequently 'do_rounding' will be false + TTMATH_ASSERT( c_from_zero == 0 ) + } + } + + return c; + } + + + + + + /*! + * + * basic mathematic functions + * + */ + +private: + + + /*! + an auxiliary method for adding + */ + void AddCheckExponents( Big & ss2, + Int & exp_offset, + bool & last_bit_set, + bool & rest_zero, + bool & do_adding, + bool & do_rounding) + { + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + if( exp_offset == mantissa_size_in_bits ) + { + last_bit_set = ss2.mantissa.IsTheHighestBitSet(); + rest_zero = ss2.mantissa.AreFirstBitsZero(man*TTMATH_BITS_PER_UINT - 1); + do_rounding = true; // we'are only rounding + } + else + if( exp_offset < mantissa_size_in_bits ) + { + uint moved = exp_offset.ToInt(); // how many times we must move ss2.mantissa + rest_zero = true; + + if( moved > 0 ) + { + last_bit_set = static_cast( ss2.mantissa.GetBit(moved-1) ); + + if( moved > 1 ) + rest_zero = ss2.mantissa.AreFirstBitsZero(moved - 1); + + // (2) moving 'exp_offset' times + ss2.mantissa.Rcr(moved, 0); + } + + do_adding = true; + do_rounding = true; + } + + // if exp_offset is greater than mantissa_size_in_bits then we do nothing + // ss2 is too small for taking into consideration in the sum + } + + + /*! + an auxiliary method for adding + */ + uint AddMantissas( Big & ss2, + bool & last_bit_set, + bool & rest_zero, + bool & rounding_up) + { + uint c = 0; + + if( IsSign() == ss2.IsSign() ) + { + // values have the same signs + if( mantissa.Add(ss2.mantissa) ) + { + // we have one bit more from addition (carry) + // now rest_zero means the old rest_zero with the old last_bit_set + rest_zero = (!last_bit_set && rest_zero); + last_bit_set = mantissa.Rcr(1,1); + c += exponent.AddOne(); + } + + rounding_up = true; + } + else + { + // values have different signs + // there shouldn't be a carry here because + // (1) (2) guarantee that the mantissa of this + // is greater than or equal to the mantissa of the ss2 + + #ifdef TTMATH_DEBUG + uint c_temp = + #endif + mantissa.Sub(ss2.mantissa); + + TTMATH_ASSERT( c_temp == 0 ) + } + + return c; + } + + +public: + + + /*! + Addition this = this + ss2 + + it returns carry if the sum is too big + */ + uint Add(Big ss2, bool round = true) + { + bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up; + Int exp_offset( exponent ); + uint c = 0; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // (1) abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + // !! use Swap here (not implemented yet) + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( ss2.IsZero() ) + return 0; + + last_bit_set = rest_zero = do_adding = do_rounding = rounding_up = false; + AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding); + + if( do_adding ) + c += AddMantissas(ss2, last_bit_set, rest_zero, rounding_up); + + if( !round || !last_bit_set ) + do_rounding = false; + + if( do_rounding ) + c += RoundHalfToEven(rest_zero, rounding_up); + + if( do_adding || do_rounding ) + c += Standardizing(); + + return CheckCarry(c); + } + + + + /*! + Subtraction this = this - ss2 + + it returns carry if the result is too big + */ + uint Sub(Big ss2, bool round = true) + { + ss2.ChangeSign(); + + return Add(ss2, round); + } + + + /*! + bitwise AND + + this and ss2 must be >= 0 + return values: + 0 - ok + 1 - carry + 2 - this or ss2 was negative + */ + uint BitAnd(Big ss2) + { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsSign() || ss2.IsSign() ) + return 2; + + if( IsZero() ) + return 0; + + if( ss2.IsZero() ) + { + SetZero(); + return 0; + } + + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + uint c = 0; + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( exp_offset >= mantissa_size_in_bits ) + { + // the second value is too small + SetZero(); + return 0; + } + + // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + mantissa.BitAnd(ss2.mantissa); + + c += Standardizing(); + + return CheckCarry(c); + } + + + /*! + bitwise OR + + this and ss2 must be >= 0 + return values: + 0 - ok + 1 - carry + 2 - this or ss2 was negative + */ + uint BitOr(Big ss2) + { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsSign() || ss2.IsSign() ) + return 2; + + if( IsZero() ) + { + *this = ss2; + return 0; + } + + if( ss2.IsZero() ) + return 0; + + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + uint c = 0; + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( exp_offset >= mantissa_size_in_bits ) + // the second value is too small + return 0; + + // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + mantissa.BitOr(ss2.mantissa); + + c += Standardizing(); + + return CheckCarry(c); + } + + + /*! + bitwise XOR + + this and ss2 must be >= 0 + return values: + 0 - ok + 1 - carry + 2 - this or ss2 was negative + */ + uint BitXor(Big ss2) + { + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsSign() || ss2.IsSign() ) + return 2; + + if( ss2.IsZero() ) + return 0; + + if( IsZero() ) + { + *this = ss2; + return 0; + } + + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); + + uint c = 0; + + exp_offset.Sub( ss2.exponent ); + exp_offset.Abs(); + + // abs(this) will be >= abs(ss2) + if( SmallerWithoutSignThan(ss2) ) + { + Big temp(ss2); + + ss2 = *this; + *this = temp; + } + + if( exp_offset >= mantissa_size_in_bits ) + // the second value is too small + return 0; + + // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + mantissa.BitXor(ss2.mantissa); + + c += Standardizing(); + + return CheckCarry(c); + } + + + + /*! + Multiplication this = this * ss2 (ss2 is uint) + + ss2 without a sign + */ + uint MulUInt(uint ss2) + { + UInt man_result; + uint i,c = 0; + + if( IsNan() ) + return 1; + + if( IsZero() ) + return 0; + + if( ss2 == 0 ) + { + SetZero(); + return 0; + } + + // man_result = mantissa * ss2.mantissa + mantissa.MulInt(ss2, man_result); + + sint 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 ; i0 && (tab[len-1] & TTMATH_UINT_HIGHEST_BIT)!=0 ) + + for(i=0 ; i & ss2, bool round = true) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + UInt man_result; + uint c = 0; + uint i; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( IsZero() ) + return 0; + + if( ss2.IsZero() ) + { + SetZero(); + return 0; + } + + // man_result = mantissa * ss2.mantissa + mantissa.MulBig(ss2.mantissa, man_result); + + // 'i' will be from 0 to man*TTMATH_BITS_PER_UINT + // because mantissa and ss2.mantissa are standardized + // (the highest bit in man_result is set to 1 or + // if there is a zero value in man_result the method CompensationToLeft() + // returns 0 but we'll correct this at the end in Standardizing() method) + i = man_result.CompensationToLeft(); + uint exp_add = man * TTMATH_BITS_PER_UINT - i; + + if( exp_add ) + c += exponent.Add( exp_add ); + + c += exponent.Add( ss2.exponent ); + + for(i=0 ; i & ss2, bool round = true) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + UInt man1; + UInt man2; + uint i,c = 0; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( ss2.IsZero() ) + { + SetNan(); + return 2; + } + + if( IsZero() ) + return 0; + + for(i=0 ; i & ss2) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + uint c = 0; + + if( IsNan() || ss2.IsNan() ) + return CheckCarry(1); + + if( ss2.IsZero() ) + { + SetNan(); + return 2; + } + + if( !SmallerWithoutSignThan(ss2) ) + { + Big temp(*this); + + c = temp.Div(ss2); + temp.SkipFraction(); + c += temp.Mul(ss2); + c += Sub(temp); + + if( !SmallerWithoutSignThan( ss2 ) ) + c += 1; + } + + return CheckCarry(c); + } + + + + + /*! + power this = this ^ pow + (pow without a sign) + + binary algorithm (r-to-l) + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments (0^0) + */ + template + uint Pow(UInt pow) + { + if( IsNan() ) + return 1; + + if( IsZero() ) + { + if( pow.IsZero() ) + { + // we don't define zero^zero + SetNan(); + return 2; + } + + // 0^(+something) is zero + return 0; + } + + Big start(*this), start_temp; + Big result; + result.SetOne(); + uint c = 0; + + while( !c ) + { + if( pow.table[0] & 1 ) + c += result.Mul(start); + + pow.Rcr(1); + + if( pow.IsZero() ) + break; + + start_temp = start; + c += start.Mul(start_temp); + } + + *this = result; + + return CheckCarry(c); + } + + + /*! + power this = this ^ pow + p can be negative + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + template + uint Pow(Int pow) + { + if( IsNan() ) + return 1; + + if( !pow.IsSign() ) + return Pow( UInt(pow) ); + + if( IsZero() ) + { + // if 'p' is negative then + // 'this' must be different from zero + SetNan(); + return 2; + } + + uint c = pow.ChangeSign(); + + Big t(*this); + c += t.Pow( UInt(pow) ); // here can only be a carry (return:1) + + SetOne(); + c += Div(t); + + return CheckCarry(c); + } + + + /*! + this method returns: 'this' mod 2 + (either zero or one) + + this method is much faster than using Mod( object_with_value_two ) + */ + uint Mod2() const + { + if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) ) + return 0; + + sint exp_int = exponent.ToInt(); + // 'exp_int' is negative (or zero), we set it as positive + exp_int = -exp_int; + + return mantissa.GetBit(exp_int); + } + + + + /*! + power this = this ^ abs([pow]) + pow is treated as a value without a sign and without a fraction + if pow has a sign then the method pow.Abs() is used + if pow has a fraction the fraction is skipped (not used in calculation) + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments (0^0) + */ + uint PowUInt(Big pow) + { + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + if( IsZero() ) + { + if( pow.IsZero() ) + { + SetNan(); + return 2; + } + + // 0^(+something) is zero + return 0; + } + + if( pow.IsSign() ) + pow.Abs(); + + Big start(*this), start_temp; + Big result; + Big one; + Int e_one; + uint c = 0; + + e_one.SetOne(); + one.SetOne(); + result = one; + + while( !c ) + { + if( pow.Mod2() ) + c += result.Mul(start); + + c += pow.exponent.Sub( e_one ); // !! may use SubOne() here? + + if( pow < one ) + break; + + start_temp = start; + c += start.Mul(start_temp); + } + + *this = result; + + return CheckCarry(c); + } + + + /*! + power this = this ^ [pow] + pow is treated as a value without a fraction + pow can be negative + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + uint PowInt(const Big & pow) + { + TTMATH_REFERENCE_ASSERT( pow ) + + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + if( !pow.IsSign() ) + return PowUInt(pow); + + if( IsZero() ) + { + // if 'pow' is negative then + // 'this' must be different from zero + SetNan(); + return 2; + } + + Big temp(*this); + uint c = temp.PowUInt(pow); // here can only be a carry (result:1) + + SetOne(); + c += Div(temp); + + return CheckCarry(c); + } + + + /*! + power this = this ^ pow + this must be greater than zero (this > 0) + pow can be negative and with fraction + + return values: + 0 - ok + 1 - carry + 2 - incorrect argument ('this' <= 0) + */ + uint PowFrac(const Big & pow) + { + TTMATH_REFERENCE_ASSERT( pow ) + + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + Big temp; + uint c = temp.Ln(*this); + + if( c != 0 ) // can be 2 from Ln() + { + SetNan(); + return c; + } + + c += temp.Mul(pow); + c += Exp(temp); + + return CheckCarry(c); + } + + + + /*! + power this = this ^ pow + pow can be negative and with fraction + + return values: + 0 - ok + 1 - carry + 2 - incorrect argument ('this' or 'pow') + */ + uint Pow(const Big & pow) + { + TTMATH_REFERENCE_ASSERT( pow ) + + if( IsNan() || pow.IsNan() ) + return CheckCarry(1); + + if( IsZero() ) + { + // 0^pow will be 0 only for pow>0 + if( pow.IsSign() || pow.IsZero() ) + { + SetNan(); + return 2; + } + + SetZero(); + + return 0; + } + + if( pow.exponent>-int(man*TTMATH_BITS_PER_UINT) && pow.exponent<=0 ) + { + if( pow.IsInteger() ) + return PowInt( pow ); + } + + return PowFrac(pow); + } + + + /*! + this function calculates the square root + e.g. let this=9 then this.Sqrt() gives 3 + + return: 0 - ok + 1 - carry + 2 - improper argument (this<0 or NaN) + */ + uint Sqrt() + { + if( IsNan() || IsSign() ) + { + SetNan(); + return 2; + } + + if( IsZero() ) + return 0; + + Big old(*this); + Big ln; + uint c = 0; + + // we're using the formula: sqrt(x) = e ^ (ln(x) / 2) + 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 temp(*this); + c += temp.Round(); + + Big temp2(temp); + c += temp.Mul(temp2); + + if( temp == old ) + *this = temp2; + } + + return CheckCarry(c); + } + + +private: + +#ifdef TTMATH_CONSTANTSGENERATOR +public: +#endif + + /*! + Exponent this = exp(x) = e^x where x is in (-1,1) + + we're using the formula exp(x) = 1 + (x)/(1!) + (x^2)/(2!) + (x^3)/(3!) + ... + */ + void ExpSurrounding0(const Big & x, uint * steps = 0) + { + TTMATH_REFERENCE_ASSERT( x ) + + Big denominator, denominator_i; + Big one, old_value, next_part; + Big numerator = x; + + SetOne(); + one.SetOne(); + denominator.SetOne(); + denominator_i.SetOne(); + + uint i; + old_value = *this; + + // we begin from 1 in order to not test at the beginning + #ifdef TTMATH_CONSTANTSGENERATOR + for(i=1 ; true ; ++i) + #else + for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + #endif + { + bool testing = ((i & 3) == 0); // it means '(i % 4) == 0' + + next_part = numerator; + + if( next_part.Div( denominator ) ) + // if there is a carry here we only break the loop + // however the result we return as good + // it means there are too many parts of the formula + break; + + // there shouldn't be a carry here + Add( next_part ); + + if( testing ) + { + if( old_value == *this ) + // we've added next few parts of the formula but the result + // is still the same then we break the loop + break; + else + old_value = *this; + } + + // we set the denominator and the numerator for a next part of the formula + if( denominator_i.Add(one) ) + // if there is a carry here the result we return as good + break; + + if( denominator.Mul(denominator_i) ) + break; + + if( numerator.Mul(x) ) + break; + } + + if( steps ) + *steps = i; + } + +public: + + + /*! + Exponent this = exp(x) = e^x + + we're using the fact that our value is stored in form of: + x = mantissa * 2^exponent + then + e^x = e^(mantissa* 2^exponent) or + e^x = (e^mantissa)^(2^exponent) + + 'Exp' returns a carry if we can't count the result ('x' is too big) + */ + uint Exp(const Big & x) + { + uint c = 0; + + if( x.IsNan() ) + return CheckCarry(1); + + if( x.IsZero() ) + { + SetOne(); + return 0; + } + + // m will be the value of the mantissa in range (-1,1) + Big m(x); + m.exponent = -sint(man*TTMATH_BITS_PER_UINT); + + // 'e_' will be the value of '2^exponent' + // e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; and + // e_.exponent.Add(1) mean: + // e_.mantissa.table[0] = 1; + // e_.Standardizing(); + // e_.exponent.Add(man*TTMATH_BITS_PER_UINT) + // (we must add 'man*TTMATH_BITS_PER_UINT' because we've taken it from the mantissa) + Big e_(x); + e_.mantissa.SetZero(); + e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; + c += e_.exponent.Add(1); + e_.Abs(); + + /* + now we've got: + m - the value of the mantissa in range (-1,1) + e_ - 2^exponent + + e_ can be as: + ...2^-2, 2^-1, 2^0, 2^1, 2^2 ... + ...1/4 , 1/2 , 1 , 2 , 4 ... + + above one e_ is integer + + if e_ is greater than 1 we calculate the exponent as: + e^(m * e_) = ExpSurrounding0(m) ^ e_ + and if e_ is smaller or equal one we calculate the exponent in this way: + e^(m * e_) = ExpSurrounding0(m* e_) + because if e_ is smaller or equal 1 then the product of m*e_ is smaller or equal m + */ + + if( e_ <= 1 ) + { + m.Mul(e_); + ExpSurrounding0(m); + } + else + { + ExpSurrounding0(m); + c += PowUInt(e_); + } + + return CheckCarry(c); + } + + + + +private: + +#ifdef TTMATH_CONSTANTSGENERATOR +public: +#endif + + /*! + Natural logarithm this = ln(x) where x in range <1,2) + + we're using the formula: + ln x = 2 * [ (x-1)/(x+1) + (1/3)((x-1)/(x+1))^3 + (1/5)((x-1)/(x+1))^5 + ... ] + */ + void LnSurrounding1(const Big & x, uint * steps = 0) + { + Big old_value, next_part, denominator, one, two, x1(x), x2(x); + + one.SetOne(); + + if( x == one ) + { + // LnSurrounding1(1) is 0 + SetZero(); + return; + } + + two = 2; + + x1.Sub(one); + x2.Add(one); + + x1.Div(x2); + x2 = x1; + x2.Mul(x1); + + denominator.SetOne(); + SetZero(); + + old_value = *this; + uint i; + + + #ifdef TTMATH_CONSTANTSGENERATOR + for(i=1 ; true ; ++i) + #else + // we begin from 1 in order to not test at the beginning + for(i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + #endif + { + bool testing = ((i & 3) == 0); // it means '(i % 4) == 0' + + next_part = x1; + + if( next_part.Div(denominator) ) + // if there is a carry here we only break the loop + // however the result we return as good + // it means there are too many parts of the formula + break; + + // there shouldn't be a carry here + Add(next_part); + + if( testing ) + { + if( old_value == *this ) + // we've added next (step_test) parts of the formula but the result + // is still the same then we break the loop + break; + else + old_value = *this; + } + + if( x1.Mul(x2) ) + // if there is a carry here the result we return as good + break; + + if( denominator.Add(two) ) + break; + } + + // this = this * 2 + // ( there can't be a carry here because we calculate the logarithm between <1,2) ) + exponent.AddOne(); + + if( steps ) + *steps = i; + } + + + + +public: + + + /*! + Natural logarithm this = ln(x) + (a logarithm with the base equal 'e') + + we're using the fact that our value is stored in form of: + x = mantissa * 2^exponent + then + ln(x) = ln (mantissa * 2^exponent) = ln (mantissa) + (exponent * ln (2)) + + the mantissa we'll show as a value from range <1,2) because the logarithm + is decreasing too fast when 'x' is going to 0 + + return values: + 0 - ok + 1 - overflow (carry) + 2 - incorrect argument (x<=0) + */ + uint Ln(const Big & x) + { + TTMATH_REFERENCE_ASSERT( x ) + + if( x.IsNan() ) + return CheckCarry(1); + + if( x.IsSign() || x.IsZero() ) + { + SetNan(); + return 2; + } + + // m will be the value of the mantissa in range <1,2) + Big m(x); + m.exponent = -sint(man*TTMATH_BITS_PER_UINT - 1); + + LnSurrounding1(m); + + Big exponent_temp; + exponent_temp.FromInt( x.exponent ); + + // we must add 'man*TTMATH_BITS_PER_UINT-1' because we've taken it from the mantissa + uint c = exponent_temp.Add(man*TTMATH_BITS_PER_UINT-1); + + Big ln2; + ln2.SetLn2(); + c += exponent_temp.Mul(ln2); + c += Add(exponent_temp); + + return CheckCarry(c); + } + + + + /*! + Logarithm from 'x' with a 'base' + + we're using the formula: + Log(x) with 'base' = ln(x) / ln(base) + + return values: + 0 - ok + 1 - overflow + 2 - incorrect argument (x<=0) + 3 - incorrect base (a<=0 lub a=1) + */ + uint Log(const Big & x, const Big & base) + { + TTMATH_REFERENCE_ASSERT( base ) + TTMATH_REFERENCE_ASSERT( x ) + + if( x.IsNan() || base.IsNan() ) + return CheckCarry(1); + + if( x.IsSign() || x.IsZero() ) + { + SetNan(); + return 2; + } + + Big denominator;; + denominator.SetOne(); + + if( base.IsSign() || base.IsZero() || base==denominator ) + { + SetNan(); + return 3; + } + + if( x == denominator ) // (this is: if x == 1) + { + // log(1) is 0 + SetZero(); + return 0; + } + + // another error values we've tested at the beginning + // there can only be a carry + uint c = Ln(x); + + c += denominator.Ln(base); + c += Div(denominator); + + return CheckCarry(c); + } + + + + + /*! + * + * converting methods + * + */ + + + /*! + converting from another type of a Big object + */ + template + uint FromBig(const Big & another) + { + info = another.info; + + if( IsNan() ) + return 1; + + if( exponent.FromInt(another.exponent) ) + { + SetNan(); + return 1; + } + + uint man_len_min = (man < another_man)? man : another_man; + uint i; + uint c = 0; + + for( i = 0 ; i another_man )' and 'if( man < another_man )' and there'll be no such situation here + #ifdef _MSC_VER + #pragma warning( disable: 4307 ) + #endif + + if( man > another_man ) + { + uint man_diff = (man - another_man) * TTMATH_BITS_PER_UINT; + c += exponent.SubInt(man_diff, 0); + } + else + if( man < another_man ) + { + uint man_diff = (another_man - man) * TTMATH_BITS_PER_UINT; + c += exponent.AddInt(man_diff, 0); + } + + #ifdef _MSC_VER + #pragma warning( default: 4307 ) + #endif + + // mantissa doesn't have to be standardized (either the highest bit is set or all bits are equal zero) + CorrectZero(); + + return CheckCarry(c); + } + + + /*! + this method converts 'this' into 'result' + + if the value is too big this method returns a carry (1) + */ + 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) ) + // 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 converts 'this' into 'result' + + 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( result_uint ); + + // the exception for the minimal value + if( IsSign() && result_uint == TTMATH_UINT_HIGHEST_BIT ) + return 0; + + if( (result_uint & TTMATH_UINT_HIGHEST_BIT) != 0 ) + // the value is too big + return 1; + + if( IsSign() ) + result = -result; + + return 0; + } + + + /*! + this method converts 'this' into 'result' + + if the value is too big this method returns a carry (1) + */ + template + uint ToInt(Int & result) const + { + result.SetZero(); + + if( IsZero() ) + return 0; + + sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); + + 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 + return 0; + + sint how_many_bits = exponent.ToInt(); + + if( how_many_bits < 0 ) + { + how_many_bits = -how_many_bits; + uint index = how_many_bits / TTMATH_BITS_PER_UINT; + + UInt mantissa_temp(mantissa); + mantissa_temp.Rcr( how_many_bits % TTMATH_BITS_PER_UINT, 0 ); + + for(uint i=index, a=0 ; i min; + min.SetMin(); + + if( result == min ) + return 0; + } + + if( (result.table[int_size-1] & TTMATH_UINT_HIGHEST_BIT) != 0 ) + // the value is too big + return 1; + + if( IsSign() ) + result.ChangeSign(); + + return 0; + } + + + /*! + a method for converting 'uint' to this class + */ + void FromUInt(uint value) + { + info = 0; + + for(uint i=0 ; i> 20; + uint m1 = ((temp.u[1] & 0xFFFFFu) << 11) | (temp.u[0] >> 21); + uint m2 = temp.u[0] << 11; + + if( e == 2047 ) + { + // If E=2047 and F is nonzero, then V=NaN ("Not a number") + // If E=2047 and F is zero and S is 1, then V=-Infinity + // If E=2047 and F is zero and S is 0, then V=Infinity + + // we do not support -Infinity and +Infinity + // we assume that there is always NaN + + SetNan(); + } + else + if( e > 0 ) + { + // If 0 m; + m.table[1] = m1; + m.table[0] = m2; + uint moved = m.CompensationToLeft(); + + FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0, + e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0, + m.table[1], m.table[2]); + } + else + { + // If E=0 and F is zero and S is 1, then V=-0 + // If E=0 and F is zero and S is 0, then V=0 + + // we do not support -0 or 0, only is one 0 + SetZero(); + } + } + } + + +private: + + void FromDouble_SetExpAndMan(bool is_sign, int e, uint mhighest, uint m1, uint m2) + { + exponent = e; + + if( man > 1 ) + { + mantissa.table[man-1] = m1 | mhighest; + mantissa.table[sint(man-2)] = m2; + // although man>1 we're using casting into sint + // to get rid from a warning which generates Microsoft Visual: + // warning C4307: '*' : integral constant overflow + + for(uint i=0 ; i> 52; + uint m = (temp.u & 0xFFFFFFFFFFFFFul) << 11; + + if( e == 2047 ) + { + // If E=2047 and F is nonzero, then V=NaN ("Not a number") + // If E=2047 and F is zero and S is 1, then V=-Infinity + // If E=2047 and F is zero and S is 0, then V=Infinity + + // we do not support -Infinity and +Infinity + // we assume that there is always NaN + + SetNan(); + } + else + if( e > 0 ) + { + // If 0= 1024 - e_correction ) + { + // +/- infinity + result = ToDouble_SetDouble( 0, 2047, 0, true); + + return 1; + } + else + if( exponent <= -1023 - 52 - e_correction ) + { + // too small value - we assume that there'll be a zero + result = 0; + + // and return a carry + return 1; + } + + sint e = exponent.ToInt() + e_correction; + + if( e <= -1023 ) + { + // -1023-52 < e <= -1023 (unnormalized value) + result = ToDouble_SetDouble( IsSign(), 0, -(e + 1023)); + } + else + { + // -1023 < e < 1024 + result = ToDouble_SetDouble( IsSign(), e + 1023, -1); + } + + return 0; + } + +private: + +#ifdef TTMATH_PLATFORM32 + + // 32bit platforms + double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false, bool nan = false) const + { + union + { + double d; + uint u[2]; // two 32bit words + } temp; + + temp.u[0] = temp.u[1] = 0; + + if( is_sign ) + temp.u[1] |= 0x80000000u; + + temp.u[1] |= (e << 20) & 0x7FF00000u; + + if( nan ) + { + temp.u[0] |= 1; + return temp.d; + } + + if( infinity ) + return temp.d; + + UInt<2> m; + m.table[1] = mantissa.table[man-1]; + m.table[0] = ( man > 1 ) ? mantissa.table[sint(man-2)] : 0; + // although man>1 we're using casting into sint + // to get rid from a warning which generates Microsoft Visual: + // warning C4307: '*' : integral constant overflow + + m.Rcr( 12 + move ); + m.table[1] &= 0xFFFFFu; // cutting the 20 bit (when 'move' was -1) + + temp.u[1] |= m.table[1]; + temp.u[0] |= m.table[0]; + + return temp.d; + } + +#else + + // 64bit platforms + double ToDouble_SetDouble(bool is_sign, uint e, sint move, bool infinity = false, bool nan = false) const + { + union + { + double d; + uint u; // 64bit word + } temp; + + temp.u = 0; + + if( is_sign ) + temp.u |= 0x8000000000000000ul; + + temp.u |= (e << 52) & 0x7FF0000000000000ul; + + if( nan ) + { + temp.u |= 1; + return temp.d; + } + + if( infinity ) + return temp.d; + + uint m = mantissa.table[man-1]; + + m >>= ( 12 + move ); + m &= 0xFFFFFFFFFFFFFul; // cutting the 20 bit (when 'move' was -1) + temp.u |= m; + + return temp.d; + } + +#endif + + +public: + + + /*! + an operator= for converting 'sint' to this class + */ + Big & operator=(sint value) + { + FromInt(value); + + return *this; + } + + + /*! + an operator= for converting 'uint' to this class + */ + Big & operator=(uint value) + { + FromUInt(value); + + return *this; + } + + + /*! + an operator= for converting 'double' to this class + */ + Big & operator=(double value) + { + FromDouble(value); + + return *this; + } + + + /*! + a constructor for converting 'sint' to this class + */ + Big(sint value) + { + FromInt(value); + } + + /*! + a constructor for converting 'uint' to this class + */ + Big(uint value) + { + FromUInt(value); + } + + + /*! + a constructor for converting 'double' to this class + */ + Big(double value) + { + FromDouble(value); + } + + +#ifdef TTMATH_PLATFORM64 + + /*! + in 64bit platforms we must define additional operators and contructors + in order to allow a user initializing the objects in this way: + Big<...> type = 20; + or + Big<...> type; + type = 30; + + decimal constants such as 20, 30 etc. are integer literal of type int, + if the value is greater it can even be long int, + 0 is an octal integer of type int + (ISO 14882 p2.13.1 Integer literals) + */ + + /*! + an operator= for converting 'signed int' to this class + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + + + */ + Big & operator=(signed int value) + { + FromInt(sint(value)); + + return *this; + } + + + /*! + an operator= for converting 'unsigned int' to this class + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Big & operator=(unsigned int value) + { + FromUInt(uint(value)); + + return *this; + } + + + /*! + a constructor for converting 'signed int' to this class + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Big(signed int value) + { + FromInt(sint(value)); + } + + /*! + a constructor for converting 'unsigned int' to this class + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Big(unsigned int value) + { + FromUInt(uint(value)); + } + +#endif + +private: + + /*! + an auxiliary method for converting from UInt and Int + + we assume that there'll never be a carry here + (we have an exponent and the value in Big can be bigger than + that one from the UInt) + */ + template + void FromUIntOrInt(const UInt & value, sint compensation) + { + uint minimum_size = (int_size < man)? int_size : man; + exponent = (sint(int_size)-sint(man)) * sint(TTMATH_BITS_PER_UINT) - compensation; + + // copying the highest words + uint i; + for(i=1 ; i<=minimum_size ; ++i) + mantissa.table[man-i] = value.table[int_size-i]; + + // setting the rest of mantissa.table into zero (if some has left) + for( ; i<=man ; ++i) + mantissa.table[man-i] = 0; + + // the highest bit is either one or zero (when the whole mantissa is zero) + // we can only call CorrectZero() + CorrectZero(); + } + + +public: + + + /*! + a method for converting from 'UInt' to this class + */ + template + void FromUInt(UInt value) + { + info = 0; + sint compensation = (sint)value.CompensationToLeft(); + + return FromUIntOrInt(value, compensation); + } + + + /*! + a method for converting from 'Int' to this class + */ + template + void FromInt(Int value) + { + info = 0; + bool is_sign = false; + + if( value.IsSign() ) + { + value.ChangeSign(); + is_sign = true; + } + + sint compensation = (sint)value.CompensationToLeft(); + FromUIntOrInt(value, compensation); + + if( is_sign ) + SetSign(); + } + + + /*! + an operator= for converting from 'Int' to this class + */ + template + Big & operator=(const Int & value) + { + FromInt(value); + + return *this; + } + + + /*! + a constructor for converting from 'Int' to this class + */ + template + Big(const Int & value) + { + FromInt(value); + } + + + /*! + an operator= for converting from 'UInt' to this class + */ + template + Big & operator=(const UInt & value) + { + FromUInt(value); + + return *this; + } + + + /*! + a constructor for converting from 'UInt' to this class + */ + template + Big(const UInt & value) + { + FromUInt(value); + } + + + /*! + an operator= for converting from 'Big' to this class + */ + template + Big & operator=(const Big & value) + { + FromBig(value); + + return *this; + } + + + /*! + a constructor for converting from 'Big' to this class + */ + template + Big(const Big & value) + { + FromBig(value); + } + + + /*! + a default constructor + + we don't set any of the members to zero + only NaN flag is set + */ + Big() + { + 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 + */ + } + + + /*! + a destructor + */ + ~Big() + { + } + + + /*! + the default assignment operator + */ + Big & operator=(const Big & value) + { + info = value.info; + exponent = value.exponent; + mantissa = value.mantissa; + + return *this; + } + + + /*! + a constructor for copying from another object of this class + */ + + Big(const Big & value) + { + operator=(value); + } + + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + + output: + return value: + 0 - ok and 'result' will be an object of type std::string (or std::wstring) which holds the value + 1 - if there is a carry (it shoudn't be in a normal situation - if it is that means there + is somewhere an error in the library) + */ + uint ToString( std::string & result, + uint base = 10, + bool scient = false, + sint scient_from = 15, + sint round = -1, + bool trim_zeroes = true, + wchar_t comma = '.' ) const + { + Conv conv; + + conv.base = base; + conv.scient = scient; + conv.scient_from = scient_from; + conv.round = round; + conv.trim_zeroes = trim_zeroes; + conv.comma = static_cast(comma); + + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + uint ToString( std::wstring & result, + uint base = 10, + bool scient = false, + sint scient_from = 15, + sint round = -1, + bool trim_zeroes = true, + wchar_t comma = '.' ) const + { + Conv conv; + + conv.base = base; + conv.scient = scient; + conv.scient_from = scient_from; + conv.round = round; + conv.trim_zeroes = trim_zeroes; + conv.comma = static_cast(comma); + + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + uint ToString(std::string & result, const Conv & conv) const + { + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + uint ToString(std::wstring & result, const Conv & conv) const + { + return ToStringBase(result, conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::string ToString(const Conv & conv) const + { + std::string result; + ToStringBase(result, conv); + + return result; + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::string ToString() const + { + Conv conv; + + return ToString(conv); + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::wstring ToWString(const Conv & conv) const + { + std::wstring result; + ToStringBase(result, conv); + + return result; + } + + + /*! + a method for converting into a string + struct Conv is defined in ttmathtypes.h, look there for more information about parameters + */ + std::wstring ToWString() const + { + Conv conv; + + return ToWString(conv); + } + + +private: + + + /*! + an auxiliary method for converting into the string + */ + template + uint ToStringBase(string_type & result, const Conv & conv) const + { + static char error_overflow_msg[] = "overflow"; + static char error_nan_msg[] = "NaN"; + result.erase(); + + if( IsNan() ) + { + Misc::AssignString(result, error_nan_msg); + return 0; + } + + if( conv.base<2 || conv.base>16 ) + { + Misc::AssignString(result, error_overflow_msg); + return 1; + } + + if( IsZero() ) + { + result = '0'; + + return 0; + } + + /* + since 'base' is greater or equal 2 that 'new_exp' of type 'Int' should + hold the new value of exponent but we're using 'Int' because + if the value for example would be 'max()' then we couldn't show it + + max() -> 11111111 * 2 ^ 11111111111 (bin)(the mantissa and exponent have all bits set) + if we were using 'Int' we couldn't show it in this format: + 1,1111111 * 2 ^ 11111111111 (bin) + because we have to add something to the mantissa and because + mantissa is full we can't do it and it'll be a carry + (look at ToString_SetCommaAndExponent(...)) + + when the base would be greater than two (for example 10) + we could use 'Int' here + */ + Int new_exp; + + if( ToString_CreateNewMantissaAndExponent(result, conv, new_exp) ) + { + Misc::AssignString(result, error_overflow_msg); + return 1; + } + + + if( ToString_SetCommaAndExponent(result, conv, new_exp) ) + { + Misc::AssignString(result, error_overflow_msg); + return 1; + } + + if( IsSign() ) + result.insert(result.begin(), '-'); + + + // converted successfully + return 0; + } + + + + /*! + in the method 'ToString_CreateNewMantissaAndExponent()' we're using + type 'Big' and we should have the ability to use some + necessary methods from that class (methods which are private here) + */ + friend class Big; + + + /*! + an auxiliary method for converting into the string + + input: + base - the base in range <2,16> + + output: + return values: + 0 - ok + 1 - if there was a carry + new_man - the new mantissa for 'base' + new_exp - the new exponent for 'base' + + mathematic part: + + the value is stored as: + value = mantissa * 2^exponent + we want to show 'value' as: + value = new_man * base^new_exp + + then 'new_man' we'll print using the standard method from UInt<> type for printing + and 'new_exp' is the offset of the comma operator in a system of a base 'base' + + value = mantissa * 2^exponent + value = mantissa * 2^exponent * (base^new_exp / base^new_exp) + value = mantissa * (2^exponent / base^new_exp) * base^new_exp + + look at the part (2^exponent / base^new_exp), there'll be good if we take + a 'new_exp' equal that value when the (2^exponent / base^new_exp) will be equal one + + on account of the 'base' is not as power of 2 (can be from 2 to 16), + this formula will not be true for integer 'new_exp' then in our case we take + 'base^new_exp' _greater_ than '2^exponent' + + if 'base^new_exp' were smaller than '2^exponent' the new mantissa could be + greater than the max value of the container UInt + + value = mantissa * (2^exponent / base^new_exp) * base^new_exp + let M = mantissa * (2^exponent / base^new_exp) then + value = M * base^new_exp + + in our calculation we treat M as floating value showing it as: + M = mm * 2^ee where ee will be <= 0 + + next we'll move all bits of mm into the right when ee is equal zero + abs(ee) must not be too big that only few bits from mm we can leave + + then we'll have: + M = mmm * 2^0 + 'mmm' is the new_man which we're looking for + + + new_exp we calculate in this way: + 2^exponent <= base^new_exp + new_exp >= log base (2^exponent) <- logarithm with the base 'base' from (2^exponent) + + but we need new_exp as integer then we test: + if new_exp is greater than zero and with fraction we add one to new_exp + new_exp = new_exp + 1 (if new_exp>0 and with fraction) + and at the end we take the integer part: + new_exp = int(new_exp) + */ + template + uint ToString_CreateNewMantissaAndExponent( string_type & new_man, const Conv & conv, + Int & new_exp) const + { + uint c = 0; + + if( conv.base<2 || conv.base>16 ) + return 1; + + // the speciality for base equal 2 + if( conv.base == 2 ) + return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp); + + // the speciality for base equal 4 + if( conv.base == 4 ) + return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 2); + + // the speciality for base equal 8 + if( conv.base == 8 ) + return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 3); + + // the speciality for base equal 16 + if( conv.base == 16 ) + return ToString_CreateNewMantissaAndExponent_BasePow2(new_man, new_exp, 4); + + + // this = mantissa * 2^exponent + + // temp = +1 * 2^exponent + // we're using a bigger type than 'big' (look below) + Big temp; + temp.info = 0; + temp.exponent = exponent; + temp.mantissa.SetOne(); + c += temp.Standardizing(); + + // new_exp_ = log base (2^exponent) + // if new_exp_ is positive and with fraction then we add one + Big new_exp_; + c += new_exp_.ToString_Log(temp, conv.base); // this logarithm isn't very complicated + + // adding some epsilon value (to get rid of some floating point errors) + temp.Set05(); + temp.exponent.SubOne(); // temp = 0.5/2 = 0.25 + c += new_exp_.Add(temp); + + if( !new_exp_.IsSign() && !new_exp_.IsInteger() ) + { + // new_exp_ > 0 and with fraction + temp.SetOne(); + c += new_exp_.Add( temp ); + } + + // new_exp_ = int(new_exp_) + new_exp_.SkipFraction(); + + + // because 'base^new_exp' is >= '2^exponent' then + // because base is >= 2 then we've got: + // 'new_exp_' must be smaller or equal 'new_exp' + // and we can pass it into the Int type + // (in fact we're using a greater type then it'll be ok) + c += new_exp_.ToInt(new_exp); + + // base_ = base + Big base_(conv.base); + + // base_ = base_ ^ new_exp_ + c += base_.Pow( new_exp_ ); + // if we hadn't used a bigger type than 'Big' then the result + // of this formula 'Pow(...)' would have been with an overflow + + // temp = mantissa * 2^exponent / base_^new_exp_ + // the sign don't interest us here + temp.mantissa = mantissa; + temp.exponent = exponent; + c += temp.Div(base_, false); // dividing without rounding + + // moving all bits of the mantissa into the right + // (how many times to move depend on the exponent) + c += temp.ToString_MoveMantissaIntoRight(); + + // because we took 'new_exp' as small as it was + // possible ([log base (2^exponent)] + 1) that after the division + // (temp.Div( base_ )) the value of exponent should be equal zero or + // minimum smaller than zero then we've got the mantissa which has + // maximum valid bits + temp.mantissa.ToString(new_man, conv.base); + + // base rounding + if( conv.base_round ) + c += ToString_BaseRound(new_man, conv, new_exp); + + return (c==0)? 0 : 1; + } + + + /*! + this method calculates the logarithm + it is used by ToString_CreateNewMantissaAndExponent() method + + it's not too complicated + because x=+1*2^exponent (mantissa is one) then during the calculation + the Ln(x) will not be making the long formula from LnSurrounding1() + and only we have to calculate 'Ln(base)' but it'll be calculated + only once, the next time we will get it from the 'history' + + x is greater than 0 + base is in <2,16> range + */ + uint ToString_Log(const Big & x, uint base) + { + TTMATH_REFERENCE_ASSERT( x ) + TTMATH_ASSERT( base>=2 && base<=16 ) + + Big temp; + temp.SetOne(); + + if( x == temp ) + { + // log(1) is 0 + SetZero(); + + return 0; + } + + // there can be only a carry + // because the 'x' is in '1+2*exponent' form then + // the long formula from LnSurrounding1() will not be calculated + // (LnSurrounding1() will return one immediately) + uint c = Ln(x); + + if( base==10 && man<=TTMATH_BUILTIN_VARIABLES_SIZE ) + { + // for the base equal 10 we're using SelLn10() instead of calculating it + // (only if we have the constant sufficient big) + temp.SetLn10(); + } + else + { + c += ToString_LogBase(base, temp); + } + + c += Div( temp ); + + return (c==0)? 0 : 1; + } + + +#ifndef TTMATH_MULTITHREADS + + /*! + this method calculates the logarithm of 'base' + it's used in single thread environment + */ + uint ToString_LogBase(uint base, Big & result) + { + TTMATH_ASSERT( base>=2 && base<=16 ) + + // this guardians are initialized before the program runs (static POD types) + static int guardians[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static Big log_history[15]; + uint index = base - 2; + uint c = 0; + + if( guardians[index] == 0 ) + { + Big base_(base); + c += log_history[index].Ln(base_); + guardians[index] = 1; + } + + result = log_history[index]; + + return (c==0)? 0 : 1; + } + +#else + + /*! + this method calculates the logarithm of 'base' + it's used in multi-thread environment + */ + uint ToString_LogBase(uint base, Big & result) + { + TTMATH_ASSERT( base>=2 && base<=16 ) + + // this guardians are initialized before the program runs (static POD types) + volatile static sig_atomic_t guardians[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + static Big * plog_history; + uint index = base - 2; + uint c = 0; + + // double-checked locking + if( guardians[index] == 0 ) + { + ThreadLock thread_lock; + + // locking + if( thread_lock.Lock() ) + { + static Big log_history[15]; + + if( guardians[index] == 0 ) + { + plog_history = log_history; + + Big base_(base); + c += log_history[index].Ln(base_); + guardians[index] = 1; + } + } + else + { + // there was a problem with locking, we store the result directly in 'result' object + Big base_(base); + c += result.Ln(base_); + + return (c==0)? 0 : 1; + } + + // automatically unlocking + } + + result = plog_history[index]; + + return (c==0)? 0 : 1; + } + +#endif + + /*! + an auxiliary method for converting into the string (private) + + this method moving all bits from mantissa into the right side + the exponent tell us how many times moving (the exponent is <=0) + */ + uint ToString_MoveMantissaIntoRight() + { + if( exponent.IsZero() ) + return 0; + + // exponent can't be greater than zero + // because we would cat the highest bits of the mantissa + if( !exponent.IsSign() ) + return 1; + + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + // if 'exponent' is <= than '-sint(man*TTMATH_BITS_PER_UINT)' + // it means that we must cut the whole mantissa + // (there'll not be any of the valid bits) + return 1; + + // e will be from (-man*TTMATH_BITS_PER_UINT, 0> + sint e = -( exponent.ToInt() ); + mantissa.Rcr(e,0); + + return 0; + } + + + /*! + a special method similar to the 'ToString_CreateNewMantissaAndExponent' + when the 'base' is equal 2 + + we use it because if base is equal 2 we don't have to make those + complicated calculations and the output is directly from the source + (there will not be any small distortions) + */ + template + uint ToString_CreateNewMantissaAndExponent_Base2( string_type & new_man, + Int & new_exp ) const + { + for( sint i=man-1 ; i>=0 ; --i ) + { + uint value = mantissa.table[i]; + + for( uint bit=0 ; bit + uint ToString_CreateNewMantissaAndExponent_BasePow2( string_type & new_man, + Int & new_exp, + uint bits) const + { + sint move; // how many times move the mantissa + UInt man_temp(mantissa); // man+1 for moving + new_exp = exponent; + new_exp.DivInt((sint)bits, move); + + if( move != 0 ) + { + // we're moving the man_temp to left-hand side + if( move < 0 ) + { + move = sint(bits) + move; + new_exp.SubOne(); // when move is < than 0 then new_exp is < 0 too + } + + man_temp.Rcl(move); + } + + + if( bits == 3 ) + { + // base 8 + // now 'move' is greater than or equal 0 + uint len = man*TTMATH_BITS_PER_UINT + move; + return ToString_CreateNewMantissaAndExponent_Base8(new_man, man_temp, len, bits); + } + else + { + // base 4 or 16 + return ToString_CreateNewMantissaAndExponent_Base4or16(new_man, man_temp, bits); + } + } + + + /*! + a special method used to calculate the new mantissa + when the 'base' is equal 8 + + bits is always 3 + + we can use this algorithm when the base is 4 or 16 too + but we have a faster method ToString_CreateNewMantissaAndExponent_Base4or16() + */ + template + uint ToString_CreateNewMantissaAndExponent_Base8( string_type & new_man, + UInt & man_temp, + uint len, + uint bits) const + { + uint shift = TTMATH_BITS_PER_UINT - bits; + uint mask = TTMATH_UINT_MAX_VALUE >> shift; + uint i; + + for( i=0 ; i(Misc::DigitToChar(digit))); + + man_temp.Rcr(bits); + } + + TTMATH_ASSERT( man_temp.IsZero() ) + + return 0; + } + + + /*! + a special method used to calculate the new mantissa + when the 'base' is equal 4 or 16 + + when the base is equal 4 or 16 the bits is 2 or 4 + and because TTMATH_BITS_PER_UINT (32 or 64) is divisible by 2 (or 4) + then we can get digits from the end of our mantissa + */ + template + uint ToString_CreateNewMantissaAndExponent_Base4or16( string_type & new_man, + UInt & man_temp, + uint bits) const + { + TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 2 == 0 ) + TTMATH_ASSERT( TTMATH_BITS_PER_UINT % 4 == 0 ) + + uint shift = TTMATH_BITS_PER_UINT - bits; + uint mask = TTMATH_UINT_MAX_VALUE << shift; + uint digit; + + // table[man] - last word - is different from zero if we moved man_temp + digit = man_temp.table[man]; + + if( digit != 0 ) + new_man += static_cast(Misc::DigitToChar(digit)); + + + for( int i=man-1 ; i>=0 ; --i ) + { + uint shift_local = shift; + uint mask_local = mask; + + while( mask_local != 0 ) + { + digit = man_temp.table[i] & mask_local; + + if( shift_local != 0 ) + digit = digit >> shift_local; + + new_man += static_cast(Misc::DigitToChar(digit)); + mask_local = mask_local >> bits; + shift_local = shift_local - bits; + } + } + + return 0; + } + + + /*! + an auxiliary method for converting into the string + */ + template + bool ToString_RoundMantissaWouldBeInteger(string_type & new_man, const Conv & conv, Int & new_exp) const + { + // if new_exp is greater or equal to zero then we have an integer value, + // if new_exp is equal -1 then we have only one digit after the comma + // and after rounding it would be an integer value + if( !new_exp.IsSign() || new_exp == -1 ) + return true; + + if( new_man.size() >= TTMATH_UINT_HIGHEST_BIT || new_man.size() < 2 ) + return true; // oops, the mantissa is too large for calculating (or too small) - we are not doing the base rounding + + uint i = 0; + char_type digit; + + if( new_exp >= -sint(new_man.size()) ) + { + uint new_exp_abs = -new_exp.ToInt(); + i = new_man.size() - new_exp_abs; // start from the first digit after the comma operator + } + + if( Misc::CharToDigit(new_man[new_man.size()-1]) >= conv.base/2 ) + { + if( new_exp < -sint(new_man.size()) ) + { + // there are some zeroes after the comma operator + // (between the comma and the first digit from the mantissa) + // and the result value will never be an integer + return false; + } + + digit = static_cast( Misc::DigitToChar(conv.base-1) ); + } + else + { + digit = '0'; + } + + for( ; i < new_man.size()-1 ; ++i) + if( new_man[i] != digit ) + return false; // it will not be an integer + + return true; // it will be integer after rounding + } + + + /*! + an auxiliary method for converting into the string + + this method is used for base!=2, base!=4, base!=8 and base!=16 + we do the rounding when the value has fraction (is not an integer) + */ + template + uint ToString_BaseRound(string_type & new_man, const Conv & conv, Int & new_exp) const + { + // we must have minimum two characters + if( new_man.size() < 2 ) + return 0; + + // assert that there will not be an integer after rounding + if( ToString_RoundMantissaWouldBeInteger(new_man, conv, new_exp) ) + return 0; + + typename string_type::size_type i = new_man.length() - 1; + + // we're erasing the last character + uint digit = Misc::CharToDigit( new_man[i] ); + new_man.erase(i, 1); + uint c = new_exp.AddOne(); + + // if the last character is greater or equal 'base/2' + // we are adding one into the new mantissa + if( digit >= conv.base / 2 ) + ToString_RoundMantissa_AddOneIntoMantissa(new_man, conv); + + return c; + } + + + /*! + an auxiliary method for converting into the string + + this method addes one into the new mantissa + */ + template + void ToString_RoundMantissa_AddOneIntoMantissa(string_type & new_man, const Conv & conv) const + { + if( new_man.empty() ) + return; + + sint i = sint( new_man.length() ) - 1; + bool was_carry = true; + + for( ; i>=0 && was_carry ; --i ) + { + // we can have the comma as well because + // we're using this method later in ToString_CorrectDigitsAfterComma_Round() + // (we're only ignoring it) + if( new_man[i] == static_cast(conv.comma) ) + continue; + + // we're adding one + uint digit = Misc::CharToDigit( new_man[i] ) + 1; + + if( digit == conv.base ) + digit = 0; + else + was_carry = false; + + new_man[i] = static_cast( Misc::DigitToChar(digit) ); + } + + if( i<0 && was_carry ) + new_man.insert( new_man.begin() , '1' ); + } + + + + /*! + an auxiliary method for converting into the string + + this method sets the comma operator and/or puts the exponent + into the string + */ + template + uint ToString_SetCommaAndExponent(string_type & new_man, const Conv & conv, Int & new_exp) const + { + uint carry = 0; + + if( new_man.empty() ) + return carry; + + Int scientific_exp( new_exp ); + + // 'new_exp' depends on the 'new_man' which is stored like this e.g: + // 32342343234 (the comma is at the end) + // we'd like to show it in this way: + // 3.2342343234 (the 'scientific_exp' is connected with this example) + + sint offset = sint( new_man.length() ) - 1; + carry += scientific_exp.Add( offset ); + // there shouldn't have been a carry because we're using + // a greater type -- 'Int' instead of 'Int' + + bool print_scientific = conv.scient; + + if( !print_scientific ) + { + if( scientific_exp > conv.scient_from || scientific_exp < -sint(conv.scient_from) ) + print_scientific = true; + } + + if( !print_scientific ) + ToString_SetCommaAndExponent_Normal(new_man, conv, new_exp); + else + // we're passing the 'scientific_exp' instead of 'new_exp' here + ToString_SetCommaAndExponent_Scientific(new_man, conv, scientific_exp); + + return (carry==0)? 0 : 1; + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Normal(string_type & new_man, const Conv & conv, Int & new_exp ) const + { + if( !new_exp.IsSign() ) // it means: if( new_exp >= 0 ) + ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp); + else + ToString_SetCommaAndExponent_Normal_SetCommaInside(new_man, conv, new_exp); + + + ToString_Group_man(new_man, conv); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Normal_AddingZero(string_type & new_man, + Int & new_exp) const + { + // we're adding zero characters at the end + // 'i' will be smaller than 'when_scientific' (or equal) + uint i = new_exp.ToInt(); + + if( new_man.length() + i > new_man.capacity() ) + // about 6 characters more (we'll need it for the comma or something) + new_man.reserve( new_man.length() + i + 6 ); + + for( ; i>0 ; --i) + new_man += '0'; + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Normal_SetCommaInside( + string_type & new_man, + const Conv & conv, + Int & new_exp ) const + { + // new_exp is < 0 + + sint new_man_len = sint(new_man.length()); // 'new_man_len' with a sign + sint e = -( new_exp.ToInt() ); // 'e' will be positive + + if( new_exp > -new_man_len ) + { + // we're setting the comma within the mantissa + + sint index = new_man_len - e; + new_man.insert( new_man.begin() + index, static_cast(conv.comma)); + } + else + { + // we're adding zero characters before the mantissa + + uint how_many = e - new_man_len; + string_type man_temp(how_many+1, '0'); + + man_temp.insert( man_temp.begin()+1, static_cast(conv.comma)); + new_man.insert(0, man_temp); + } + + ToString_CorrectDigitsAfterComma(new_man, conv); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_SetCommaAndExponent_Scientific( string_type & new_man, + const Conv & conv, + Int & scientific_exp ) const + { + if( new_man.empty() ) + return; + + if( new_man.size() > 1 ) + { + new_man.insert( new_man.begin()+1, static_cast(conv.comma) ); + ToString_CorrectDigitsAfterComma(new_man, conv); + } + + ToString_Group_man(new_man, conv); + + if( conv.base == 10 ) + { + new_man += 'e'; + + if( !scientific_exp.IsSign() ) + new_man += '+'; + } + else + { + // the 10 here is meant as the base 'base' + // (no matter which 'base' we're using there'll always be 10 here) + Misc::AddString(new_man, "*10^"); + } + + string_type temp_exp; + scientific_exp.ToString( temp_exp, conv.base ); + + new_man += temp_exp; + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_Group_man(string_type & new_man, const Conv & conv) const + { + typedef typename string_type::size_type StrSize; + + if( conv.group == 0 ) + return; + + // first we're looking for the comma operator + StrSize index = new_man.find(static_cast(conv.comma), 0); + + if( index == string_type::npos ) + index = new_man.size(); + + ToString_Group_man_before_comma(new_man, conv, index); + ToString_Group_man_after_comma(new_man, conv, index+1); + } + + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_Group_man_before_comma( string_type & new_man, const Conv & conv, + typename string_type::size_type & index) const + { + typedef typename string_type::size_type StrSize; + uint group = 0; + + StrSize i = index; + + // adding group characters before the comma operator + // i>0 because on the first position we don't put any additional grouping characters + for( ; i>0 ; --i, ++group) + { + if( group >= 3 ) + { + group = 0; + new_man.insert(i, 1, static_cast(conv.group)); + ++index; + } + } + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_Group_man_after_comma(string_type & new_man, const Conv & conv, + typename string_type::size_type index) const + { + uint group = 0; + + for( ; index= 3 ) + { + group = 0; + new_man.insert(index, 1, static_cast(conv.group)); + ++index; + } + } + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_CorrectDigitsAfterComma( string_type & new_man, + const Conv & conv ) const + { + if( conv.round >= 0 ) + ToString_CorrectDigitsAfterComma_Round(new_man, conv); + + if( conv.trim_zeroes ) + ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(new_man, conv); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters( + string_type & new_man, + const Conv & conv) const + { + // minimum two characters + if( new_man.length() < 2 ) + return; + + // we're looking for the index of the last character which is not zero + uint i = uint( new_man.length() ) - 1; + for( ; i>0 && new_man[i]=='0' ; --i ); + + // if there is another character than zero at the end + // we're finishing + if( i == new_man.length() - 1 ) + return; + + // we must have a comma + // (the comma can be removed by ToString_CorrectDigitsAfterComma_Round + // which is called before) + if( new_man.find_last_of(static_cast(conv.comma), i) == string_type::npos ) + return; + + // if directly before the first zero is the comma operator + // we're cutting it as well + if( i>0 && new_man[i]==static_cast(conv.comma) ) + --i; + + new_man.erase(i+1, new_man.length()-i-1); + } + + + /*! + an auxiliary method for converting into the string + */ + template + void ToString_CorrectDigitsAfterComma_Round( + string_type & new_man, + const Conv & conv ) const + { + typedef typename string_type::size_type StrSize; + + // first we're looking for the comma operator + StrSize index = new_man.find(static_cast(conv.comma), 0); + + if( index == string_type::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 + StrSize 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( static_cast(conv.round) >= after_comma ) + return; + + uint last_digit = Misc::CharToDigit( new_man[ index + conv.round + 1 ], conv.base ); + + // we're cutting the rest of the string + new_man.erase(index + conv.round + 1, after_comma - conv.round); + + if( conv.round == 0 ) + { + // we're cutting the comma operator as well + // (it's not needed now because we've cut the whole rest after the comma) + new_man.erase(index, 1); + } + + if( last_digit >= conv.base / 2 ) + // we must round here + ToString_RoundMantissa_AddOneIntoMantissa(new_man, conv); + } + + + +public: + + /*! + a method for converting a string into its value + + it returns 1 if the value is too big -- we cannot pass it into the range + of our class Big (or if the base is incorrect) + + that means only digits before the comma operator can make this value too big, + all digits after the comma we can ignore + + 'source' - pointer to the string for parsing + + if 'after_source' is set that when this method finishes + it sets the pointer to the new first character after parsed value + + 'value_read' - if the pointer is provided that means the value_read will be true + only when a value has been actually read, there can be situation where only such + a string '-' or '+' will be parsed -- 'after_source' will be different from 'source' but + 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 char * source, uint base = 10, const char ** after_source = 0, bool * value_read = 0) + { + Conv conv; + conv.base = base; + + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const wchar_t * source, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + Conv conv; + conv.base = base; + + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const char * source, const Conv & conv, const char ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const wchar_t * source, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(source, conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::string & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), base, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::wstring & string, uint base = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), base, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::string & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), conv, after_source, value_read); + } + + + /*! + a method for converting a string into its value + */ + uint FromString(const std::wstring & string, const Conv & conv, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromString(string.c_str(), conv, after_source, value_read); + } + +private: + + + /*! + an auxiliary method for converting from a string + */ + template + uint FromStringBase(const char_type * source, const Conv & conv, const char_type ** after_source = 0, bool * value_read = 0) + { + bool is_sign; + bool value_read_temp = false; + + if( conv.base<2 || conv.base>16 ) + { + SetNan(); + + if( after_source ) + *after_source = source; + + if( value_read ) + *value_read = value_read_temp; + + return 1; + } + + SetZero(); + FromString_TestSign( source, is_sign ); + + uint c = FromString_ReadPartBeforeComma( source, conv, value_read_temp ); + + if( FromString_TestCommaOperator(source, conv) ) + c += FromString_ReadPartAfterComma( source, conv, value_read_temp ); + + if( value_read_temp && conv.base == 10 ) + c += FromString_ReadScientificIfExists( source ); + + if( is_sign && !IsZero() ) + ChangeSign(); + + if( after_source ) + *after_source = source; + + if( value_read ) + *value_read = value_read_temp; + + return CheckCarry(c); + } + + + /*! + we're testing whether the value is with the sign + + (this method is used from 'FromString_ReadPartScientific' too) + */ + template + void FromString_TestSign( const char_type * & source, bool & is_sign ) + { + Misc::SkipWhiteCharacters(source); + + is_sign = false; + + if( *source == '-' ) + { + is_sign = true; + ++source; + } + else + if( *source == '+' ) + { + ++source; + } + } + + + /*! + we're testing whether there's a comma operator + */ + template + bool FromString_TestCommaOperator(const char_type * & source, const Conv & conv) + { + if( (*source == static_cast(conv.comma)) || + (*source == static_cast(conv.comma2) && conv.comma2 != 0 ) ) + { + ++source; + + return true; + } + + return false; + } + + + /*! + this method reads the first part of a string + (before the comma operator) + */ + template + uint FromString_ReadPartBeforeComma( const char_type * & source, const Conv & conv, bool & value_read ) + { + sint character; + Big temp; + Big base_( conv.base ); + + Misc::SkipWhiteCharacters( source ); + + for( ; true ; ++source ) + { + if( conv.group!=0 && *source==static_cast(conv.group) ) + continue; + + character = Misc::CharToDigit(*source, conv.base); + + if( character == -1 ) + break; + + value_read = true; + temp = character; + + if( Mul(base_) ) + return 1; + + if( Add(temp) ) + return 1; + } + + return 0; + } + + + /*! + this method reads the second part of a string + (after the comma operator) + */ + template + uint FromString_ReadPartAfterComma( const char_type * & source, const Conv & conv, bool & value_read ) + { + sint character; + uint c = 0, index = 1; + Big sum, part, power, old_value, base_( conv.base ); + + // we don't remove any white characters here + + // this is only to avoid getting a warning about an uninitialized object 'old_value' which GCC reports + // (in fact we will initialize it later when the condition 'testing' is fulfilled) + old_value.SetZero(); + + power.SetOne(); + sum.SetZero(); + + for( ; true ; ++source, ++index ) + { + if( conv.group!=0 && *source==static_cast(conv.group) ) + continue; + + character = Misc::CharToDigit(*source, conv.base); + + if( character == -1 ) + break; + + value_read = true; + + part = character; + + if( power.Mul( base_ ) ) + // there's no sens to add the next parts, but we can't report this + // as an error (this is only inaccuracy) + break; + + if( part.Div( power ) ) + break; + + // every 5 iteration we make a test whether the value will be changed or not + // (character must be different from zero to this test) + bool testing = (character != 0 && (index % 5) == 0); + + if( testing ) + old_value = sum; + + // there actually shouldn't be a carry here + c += sum.Add( part ); + + if( testing && old_value == sum ) + // after adding 'part' the value has not been changed + // there's no sense to add any next parts + break; + } + + // we could break the parsing somewhere in the middle of the string, + // but the result (value) still can be good + // we should set a correct value of 'source' now + for( ; Misc::CharToDigit(*source, conv.base) != -1 ; ++source ); + + c += Add(sum); + + return (c==0)? 0 : 1; + } + + + /*! + this method checks whether there is a scientific part: [e|E][-|+]value + + it is called when the base is 10 and some digits were read before + */ + template + uint FromString_ReadScientificIfExists(const char_type * & source) + { + uint c = 0; + + bool scientific_read = false; + const char_type * before_scientific = source; + + if( FromString_TestScientific(source) ) + c += FromString_ReadPartScientific( source, scientific_read ); + + if( !scientific_read ) + source = before_scientific; + + return (c==0)? 0 : 1; + } + + + + /*! + we're testing whether is there the character 'e' + + this character is only allowed when we're using the base equals 10 + */ + template + bool FromString_TestScientific(const char_type * & source) + { + Misc::SkipWhiteCharacters(source); + + if( *source=='e' || *source=='E' ) + { + ++source; + + return true; + } + + return false; + } + + + /*! + 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 + */ + template + uint FromString_ReadPartScientific( const char_type * & source, bool & scientific_read ) + { + uint c = 0; + Big new_exponent, temp; + bool was_sign = false; + + FromString_TestSign( source, was_sign ); + c += FromString_ReadPartScientific_ReadExponent( source, new_exponent, scientific_read ); + + if( scientific_read ) + { + if( was_sign ) + new_exponent.ChangeSign(); + + temp = 10; + c += temp.Pow( new_exponent ); + c += Mul(temp); + } + + return (c==0)? 0 : 1; + } + + + /*! + this method reads the value of the extra exponent when scientific format is used + (only when base == 10) + */ + template + uint FromString_ReadPartScientific_ReadExponent( const char_type * & source, Big & new_exponent, bool & scientific_read ) + { + sint character; + Big base, temp; + + Misc::SkipWhiteCharacters(source); + + new_exponent.SetZero(); + base = 10; + + for( ; (character=Misc::CharToDigit(*source, 10)) != -1 ; ++source ) + { + scientific_read = true; + + temp = character; + + if( new_exponent.Mul(base) ) + return 1; + + if( new_exponent.Add(temp) ) + return 1; + } + + return 0; + } + + +public: + + + /*! + a constructor for converting a string into this class + */ + Big(const char * string) + { + FromString( string ); + } + + + /*! + a constructor for converting a string into this class + */ + Big(const wchar_t * string) + { + FromString( string ); + } + + + /*! + a constructor for converting a string into this class + */ + Big(const std::string & string) + { + FromString( string.c_str() ); + } + + + /*! + a constructor for converting a string into this class + */ + Big(const std::wstring & string) + { + FromString( string.c_str() ); + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const char * string) + { + FromString( string ); + + return *this; + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const wchar_t * string) + { + FromString( string ); + + return *this; + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const std::string & string) + { + FromString( string.c_str() ); + + return *this; + } + + + /*! + an operator= for converting a string into its value + */ + Big & operator=(const std::wstring & string) + { + FromString( string.c_str() ); + + return *this; + } + + + + /*! + * + * methods for comparing + * + */ + + + /*! + this method performs the formula 'abs(this) < abs(ss2)' + and returns the result + + (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag + */ + bool SmallerWithoutSignThan(const Big & ss2) const + { + if( IsZero() ) + { + if( ss2.IsZero() ) + // we've got two zeroes + return false; + else + // this==0 and ss2!=0 + return true; + } + + if( ss2.IsZero() ) + // this!=0 and ss2==0 + return false; + + // we're using the fact that all bits in mantissa are pushed + // into the left side -- Standardizing() + if( exponent == ss2.exponent ) + return mantissa < ss2.mantissa; + + return exponent < ss2.exponent; + } + + + /*! + this method performs the formula 'abs(this) > abs(ss2)' + and returns the result + + (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag + */ + bool GreaterWithoutSignThan(const Big & ss2) const + { + if( IsZero() ) + { + if( ss2.IsZero() ) + // we've got two zeroes + return false; + else + // this==0 and ss2!=0 + return false; + } + + if( ss2.IsZero() ) + // this!=0 and ss2==0 + return true; + + // we're using the fact that all bits in mantissa are pushed + // into the left side -- Standardizing() + if( exponent == ss2.exponent ) + return mantissa > ss2.mantissa; + + return exponent > ss2.exponent; + } + + + /*! + this method performs the formula 'abs(this) == abs(ss2)' + and returns the result + + (in other words it treats 'this' and 'ss2' as values without a sign) + we don't check the NaN flag + */ + bool EqualWithoutSign(const Big & ss2) const + { + if( IsZero() ) + { + if( ss2.IsZero() ) + // we've got two zeroes + return true; + else + // this==0 and ss2!=0 + return false; + } + + if( ss2.IsZero() ) + // this!=0 and ss2==0 + return false; + + if( exponent==ss2.exponent && mantissa==ss2.mantissa ) + return true; + + return false; + } + + + bool operator<(const Big & ss2) const + { + if( IsSign() && !ss2.IsSign() ) + // this<0 and ss2>=0 + return true; + + if( !IsSign() && ss2.IsSign() ) + // this>=0 and ss2<0 + return false; + + // both signs are the same + + if( IsSign() ) + return ss2.SmallerWithoutSignThan( *this ); + + return SmallerWithoutSignThan( ss2 ); + } + + + bool operator==(const Big & ss2) const + { + if( IsSign() != ss2.IsSign() ) + return false; + + return EqualWithoutSign( ss2 ); + } + + + bool operator>(const Big & ss2) const + { + if( IsSign() && !ss2.IsSign() ) + // this<0 and ss2>=0 + return false; + + if( !IsSign() && ss2.IsSign() ) + // this>=0 and ss2<0 + return true; + + // both signs are the same + + if( IsSign() ) + return ss2.GreaterWithoutSignThan( *this ); + + return GreaterWithoutSignThan( ss2 ); + } + + + bool operator>=(const Big & ss2) const + { + return !operator<( ss2 ); + } + + + bool operator<=(const Big & ss2) const + { + return !operator>( ss2 ); + } + + + bool operator!=(const Big & ss2) const + { + return !operator==(ss2); + } + + + + + + /*! + * + * standard mathematical operators + * + */ + + + /*! + an operator for changing the sign + + this method is not changing 'this' but the changed value is returned + */ + Big operator-() const + { + Big temp(*this); + + temp.ChangeSign(); + + return temp; + } + + + Big operator-(const Big & ss2) const + { + Big temp(*this); + + temp.Sub(ss2); + + return temp; + } + + Big & operator-=(const Big & ss2) + { + Sub(ss2); + + return *this; + } + + + Big operator+(const Big & ss2) const + { + Big temp(*this); + + temp.Add(ss2); + + return temp; + } + + + Big & operator+=(const Big & ss2) + { + Add(ss2); + + return *this; + } + + + Big operator*(const Big & ss2) const + { + Big temp(*this); + + temp.Mul(ss2); + + return temp; + } + + + Big & operator*=(const Big & ss2) + { + Mul(ss2); + + return *this; + } + + + Big operator/(const Big & ss2) const + { + Big temp(*this); + + temp.Div(ss2); + + return temp; + } + + + Big & operator/=(const Big & ss2) + { + Div(ss2); + + return *this; + } + + + /*! + this method makes an integer value by skipping any fractions + + for example: + 10.7 will be 10 + 12.1 -- 12 + -20.2 -- 20 + -20.9 -- 20 + -0.7 -- 0 + 0.8 -- 0 + */ + void SkipFraction() + { + if( IsNan() || IsZero() ) + return; + + if( !exponent.IsSign() ) + // exponent >=0 -- the value don't have any fractions + return; + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + { + // the value is from (-1,1), we return zero + SetZero(); + return; + } + + // exponent is in range (-man*TTMATH_BITS_PER_UINT, 0) + sint e = exponent.ToInt(); + + mantissa.ClearFirstBits( -e ); + + // we don't have to standardize 'Standardizing()' the value because + // there's at least one bit in the mantissa + // (the highest bit which we didn't touch) + } + + + /*! + this method remains only a fraction from the value + + for example: + 30.56 will be 0.56 + -12.67 -- -0.67 + */ + void RemainFraction() + { + if( IsNan() || IsZero() ) + return; + + if( !exponent.IsSign() ) + { + // exponent >= 0 -- the value doesn't have any fractions + // we return zero + SetZero(); + return; + } + + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + { + // the value is from (-1,1) + // we don't make anything with the value + return; + } + + // e will be from (-man*TTMATH_BITS_PER_UINT, 0) + sint e = exponent.ToInt(); + + sint how_many_bits_leave = sint(man*TTMATH_BITS_PER_UINT) + e; // there'll be a subtraction -- e is negative + mantissa.Rcl( how_many_bits_leave, 0); + + // there'll not be a carry because the exponent is too small + exponent.Sub( how_many_bits_leave ); + + // we must call Standardizing() here + Standardizing(); + } + + + + /*! + 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 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 + (it returns a carry if it was) + + for example: + 2.3 = 2 + 2.8 = 3 + + -2.3 = -2 + -2.8 = 3 + */ + uint Round() + { + Big half; + uint c; + + if( IsNan() ) + return 1; + + if( IsZero() ) + return 0; + + half.Set05(); + + if( IsSign() ) + { + // 'this' is < 0 + c = Sub( half ); + } + else + { + // 'this' is > 0 + c = Add( half ); + } + + SkipFraction(); + + return CheckCarry(c); + } + + + + /*! + * + * input/output operators for standard streams + * + */ + +private: + + /*! + an auxiliary method for outputing to standard streams + */ + template + static ostream_type & OutputToStream(ostream_type & s, const Big & l) + { + string_type ss; + + l.ToString(ss); + s << ss; + + return s; + } + + +public: + + + /*! + output to standard streams + */ + friend std::ostream & operator<<(std::ostream & s, const Big & l) + { + return OutputToStream(s, l); + } + + + /*! + output to standard streams + */ + friend std::wostream & operator<<(std::wostream & s, const Big & l) + { + return OutputToStream(s, l); + } + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + static istream_type & InputFromStream(istream_type & s, Big & l) + { + string_type ss; + + // char or wchar_t for operator>> + char_type z, old_z; + bool was_comma = false; + bool was_e = false; + + + // operator>> omits white characters if they're set for ommiting + s >> z; + + if( z=='-' || z=='+' ) + { + ss += z; + s >> z; // we're reading a next character (white characters can be ommited) + } + + old_z = 0; + + // we're reading only digits (base=10) and only one comma operator + for( ; s.good() ; z=static_cast(s.get()) ) + { + if( z=='.' || z==',' ) + { + if( was_comma || was_e ) + // second comma operator or comma operator after 'e' character + break; + + was_comma = true; + } + else + if( z == 'e' || z == 'E' ) + { + if( was_e ) + // second 'e' character + break; + + was_e = true; + } + else + if( z == '+' || z == '-' ) + { + if( old_z != 'e' && old_z != 'E' ) + // '+' or '-' is allowed only after 'e' character + break; + } + else + if( Misc::CharToDigit(z, 10) < 0 ) + break; + + + ss += z; + old_z = z; + } + + // we're leaving the last read character + // (it's not belonging to the value) + s.unget(); + + l.FromString( ss ); + + return s; + } + + + +public: + + /*! + input from standard streams + */ + friend std::istream & operator>>(std::istream & s, Big & l) + { + return InputFromStream(s, l); + } + + + /*! + input from standard streams + */ + friend std::wistream & operator>>(std::wistream & s, Big & l) + { + return InputFromStream(s, l); + } + +}; + + +} // namespace + +#endif diff --git a/ttmath/ttmathint.h b/ttmath/ttmathint.h new file mode 100644 index 0000000..bf2c55a --- /dev/null +++ b/ttmath/ttmathint.h @@ -0,0 +1,1547 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#ifndef headerfilettmathint +#define headerfilettmathint + +/*! + \file ttmathint.h + \brief template class Int +*/ + +#include "ttmathuint.h" + +namespace ttmath +{ + + +/*! + \brief Int implements a big integer value with a sign + + value_size - how many bytes specify our value + on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits + on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits + value_size = 1,2,3,4,5,6.... +*/ +template +class Int : public UInt +{ +public: + + /*! + this method sets the max value which this class can hold + (all bits will be one besides the last one) + */ + void SetMax() + { + UInt::SetMax(); + UInt::table[value_size-1] = ~ TTMATH_UINT_HIGHEST_BIT; + } + + + /*! + this method sets the min value which this class can hold + (all bits will be zero besides the last one which is one) + */ + void SetMin() + { + UInt::SetZero(); + UInt::table[value_size-1] = TTMATH_UINT_HIGHEST_BIT; + } + + + /*! + this method sets -1 as the value + (-1 is equal the max value in an unsigned type) + */ + void SetSignOne() + { + UInt::SetMax(); + } + + + /*! + we change the sign of the value + + if it isn't possible to change the sign this method returns 1 + else return 0 and changing the sign + */ + uint ChangeSign() + { + Int temp; + + temp.SetMin(); + + /* + if the value is equal that one which has been returned from SetMin + that means we can't change sign because the value is too big (bigger about one) + + e.g. when value_size = 1 and value is -2147483648 we can't change it to the + 2147483648 because the max value which can be held is 2147483647 + + we don't change the value and we're using this fact somewhere in some methods + (if we look on our value without the sign we get the correct value + eg. -2147483648 in Int<1> will be 2147483648 on the UInt<1> type) + */ + if( operator==(temp) ) + return 1; + + temp.SetZero(); + temp.UInt::Sub(*this); + + operator=(temp); + + return 0; + } + + + + /*! + this method sets the sign + + e.g. 1 -> -1 + -2 -> -2 + + from a positive value we make a negative value, + if the value is negative we do nothing + */ + void SetSign() + { + if( IsSign() ) + return; + + ChangeSign(); + } + + + + /*! + this method returns true if there's the sign + + (the highest bit will be converted to the bool) + */ + bool IsSign() const + { + return UInt::IsTheHighestBitSet(); + } + + + + /*! + it sets an absolute value + + it can return carry (1) (look on ChangeSign() for details) + */ + uint Abs() + { + if( !IsSign() ) + return 0; + + return ChangeSign(); + } + + + + + /*! + * + * basic mathematic functions + * + */ + +private: + + uint CorrectCarryAfterAdding(bool p1_is_sign, bool p2_is_sign) + { + if( !p1_is_sign && !p2_is_sign ) + { + if( UInt::IsTheHighestBitSet() ) + return 1; + } + + if( p1_is_sign && p2_is_sign ) + { + if( ! UInt::IsTheHighestBitSet() ) + return 1; + } + + return 0; + } + + +public: + + /*! + this method adds two value with a sign and returns a carry + + we're using methods from the base class because values are stored with U2 + we must only make the carry correction + + this = p1(=this) + p2 + + when p1>=0 i p2>=0 carry is set when the highest bit of value is set + when p1<0 i p2<0 carry is set when the highest bit of value is clear + when p1>=0 i p2<0 carry will never be set + when p1<0 i p2>=0 carry will never be set + */ + uint Add(const Int & ss2) + { + bool p1_is_sign = IsSign(); + bool p2_is_sign = ss2.IsSign(); + + UInt::Add(ss2); + + return CorrectCarryAfterAdding(p1_is_sign, p2_is_sign); + } + + + /*! + this method adds one *unsigned* word (at a specific position) + and returns a carry (if it was) + + look at a description in UInt<>::AddInt(...) + */ + uint AddInt(uint value, uint index = 0) + { + bool p1_is_sign = IsSign(); + + UInt::AddInt(value, index); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + + + /*! + this method adds two *unsigned* words to the existing value + and these words begin on the 'index' position + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + look at a description in UInt<>::AddTwoInts(...) + */ + uint AddTwoInts(uint x2, uint x1, uint index) + { + bool p1_is_sign = IsSign(); + + UInt::AddTwoInts(x2, x1, index); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + +private: + + uint CorrectCarryAfterSubtracting(bool p1_is_sign, bool p2_is_sign) + { + if( !p1_is_sign && p2_is_sign ) + { + if( UInt::IsTheHighestBitSet() ) + return 1; + } + + if( p1_is_sign && !p2_is_sign ) + { + if( ! UInt::IsTheHighestBitSet() ) + return 1; + } + + return 0; + } + +public: + + /*! + this method subtracts two values with a sign + + we don't use the previous Add because the method ChangeSign can + sometimes return carry + + this = p1(=this) - p2 + + when p1>=0 i p2>=0 carry will never be set + when p1<0 i p2<0 carry will never be set + when p1>=0 i p2<0 carry is set when the highest bit of value is set + when p1<0 i p2>=0 carry is set when the highest bit of value is clear + */ + uint Sub(const Int & ss2) + { + bool p1_is_sign = IsSign(); + bool p2_is_sign = ss2.IsSign(); + + UInt::Sub(ss2); + + return CorrectCarryAfterSubtracting(p1_is_sign, p2_is_sign); + } + + + /*! + this method subtracts one *unsigned* word (at a specific position) + and returns a carry (if it was) + */ + uint SubInt(uint value, uint index = 0) + { + bool p1_is_sign = IsSign(); + + UInt::SubInt(value, index); + + return CorrectCarryAfterSubtracting(p1_is_sign, false); + } + + + /*! + this method adds one to the value and returns carry + */ + uint AddOne() + { + bool p1_is_sign = IsSign(); + + UInt::AddOne(); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + + + /*! + this method subtracts one from the value and returns carry + */ + uint SubOne() + { + bool p1_is_sign = IsSign(); + + UInt::SubOne(); + + return CorrectCarryAfterSubtracting(p1_is_sign, false); + } + + + + /*! + multiplication this = this * ss2 + + it returns carry if the result is too big + (we're using the method from the base class but we have to make + one correction in account of signs) + */ + uint Mul(Int ss2) + { + bool ss1_is_sign, ss2_is_sign; + + ss1_is_sign = IsSign(); + ss2_is_sign = ss2.IsSign(); + + /* + we don't have to check the carry from Abs (values will be correct + because next we're using the method Mul from the base class UInt + which is without a sign) + */ + Abs(); + ss2.Abs(); + + if( UInt::Mul(ss2) ) + return 1; + + + /* + we have to examine the sign of the result now + but if the result is with the sign then: + 1. if the signs were the same that means the result is too big + (the result must be without a sign) + 2. if the signs were different that means if the result + is different from that one which has been returned from SetMin() + that is carry (result too big) but if the result is equal SetMin() + there'll be ok (and the next SetSign will has no effect because + the value is actually negative -- look at description of that case + in ChangeSign()) + */ + if( IsSign() ) + { + /* + there can be one case where signs are different and + the result will be equal the value from SetMin() + (this situation is ok) + */ + if( ss1_is_sign != ss2_is_sign ) + { + Int temp; + temp.SetMin(); + + if( operator!=(temp) ) + /* + the result is too big + */ + return 1; + } + else + { + /* + the result is too big + */ + return 1; + } + } + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + + return 0; + } + + + /*! + division this = this / ss2 + returned values: + 0 - ok + 1 - division by zero + + for example: (result means 'this') + 20 / 3 --> result: 6 remainder: 2 + -20 / 3 --> result: -6 remainder: -2 + 20 / -3 --> result: -6 remainder: 2 + -20 / -3 --> result: 6 remainder: -2 + + in other words: this(old) = ss2 * this(new)(result) + remainder + */ + uint Div(Int ss2, Int * remainder = 0) + { + bool ss1_is_sign, ss2_is_sign; + + ss1_is_sign = IsSign(); + ss2_is_sign = ss2.IsSign(); + + /* + we don't have to test the carry from Abs as well as in Mul + */ + Abs(); + ss2.Abs(); + + uint c = UInt::Div(ss2, remainder); + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + if( ss1_is_sign && remainder ) + remainder->SetSign(); + + return c; + } + + uint Div(const Int & ss2, Int & remainder) + { + return Div(ss2, &remainder); + } + + + /*! + division this = this / ss2 (ss2 is int) + returned values: + 0 - ok + 1 - division by zero + + for example: (result means 'this') + 20 / 3 --> result: 6 remainder: 2 + -20 / 3 --> result: -6 remainder: -2 + 20 / -3 --> result: -6 remainder: 2 + -20 / -3 --> result: 6 remainder: -2 + + in other words: this(old) = ss2 * this(new)(result) + remainder + */ + uint DivInt(sint ss2, sint * remainder = 0) + { + bool ss1_is_sign, ss2_is_sign; + + ss1_is_sign = IsSign(); + + /* + we don't have to test the carry from Abs as well as in Mul + */ + Abs(); + + if( ss2 < 0 ) + { + ss2 = -ss2; + ss2_is_sign = true; + } + else + { + ss2_is_sign = false; + } + + uint rem; + uint c = UInt::DivInt((uint)ss2, &rem); + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + if( remainder ) + { + if( ss1_is_sign ) + *remainder = -sint(rem); + else + *remainder = sint(rem); + } + + return c; + } + + + uint DivInt(sint ss2, sint & remainder) + { + return DivInt(ss2, &remainder); + } + + +private: + + + /*! + power this = this ^ pow + this can be negative + pow is >= 0 + */ + uint Pow2(const Int & pow) + { + bool was_sign = IsSign(); + uint c = 0; + + if( was_sign ) + c += Abs(); + + uint c_temp = UInt::Pow(pow); + if( c_temp > 0 ) + return c_temp; // c_temp can be: 0, 1 or 2 + + if( was_sign && (pow.table[0] & 1) == 1 ) + // negative value to the power of odd number is negative + c += ChangeSign(); + + return (c==0)? 0 : 1; + } + + +public: + + + /*! + power this = this ^ pow + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + uint Pow(Int pow) + { + if( !pow.IsSign() ) + return Pow2(pow); + + if( UInt::IsZero() ) + // if 'pow' is negative then + // 'this' must be different from zero + return 2; + + if( pow.ChangeSign() ) + return 1; + + Int t(*this); + uint c_temp = t.Pow2(pow); + if( c_temp > 0 ) + return c_temp; + + UInt::SetOne(); + if( Div(t) ) + return 1; + + return 0; + } + + + + /*! + * + * convertion methods + * + */ +private: + + + /*! + an auxiliary method for converting both from UInt and Int + */ + template + uint FromUIntOrInt(const UInt & p, bool UInt_type) + { + uint min_size = (value_size < argument_size)? value_size : argument_size; + uint i; + + for(i=0 ; i::table[i] = p.table[i]; + + + if( value_size > argument_size ) + { + uint fill; + + if( UInt_type ) + fill = 0; + else + fill = (p.table[argument_size-1] & TTMATH_UINT_HIGHEST_BIT)? + TTMATH_UINT_MAX_VALUE : 0; + + // 'this' is longer than 'p' + for( ; i::table[i] = fill; + } + else + { + uint test = (UInt::table[value_size-1] & TTMATH_UINT_HIGHEST_BIT)? + TTMATH_UINT_MAX_VALUE : 0; + + if( UInt_type && test!=0 ) + return 1; + + for( ; i type into this class + + this operation has mainly sense if the value from p + can be held in this type + + it returns a carry if the value 'p' is too big + */ + template + uint FromInt(const Int & p) + { + return FromUIntOrInt(p, false); + } + + + /*! + this method converts the sint type into this class + */ + uint FromInt(sint value) + { + uint fill = ( value<0 ) ? TTMATH_UINT_MAX_VALUE : 0; + + for(uint i=1 ; i::table[i] = fill; + + UInt::table[0] = uint(value); + + // there'll never be a carry here + return 0; + } + + + /*! + this method converts UInt into this class + */ + template + uint FromUInt(const UInt & p) + { + return FromUIntOrInt(p, true); + } + + + /*! + this method converts the uint type into this class + */ + uint FromUInt(uint value) + { + for(uint i=1 ; i::table[i] = 0; + + UInt::table[0] = value; + + // there can be a carry here when the size of this value is equal one word + // and the 'value' has the highest bit set + if( value_size==1 && (value & TTMATH_UINT_HIGHEST_BIT)!=0 ) + return 1; + + return 0; + } + + + + /*! + the default assignment operator + */ + Int & operator=(const Int & p) + { + FromInt(p); + + return *this; + } + + + /*! + this operator converts an Int type to this class + + it doesn't return a carry + */ + template + Int & operator=(const Int & p) + { + FromInt(p); + + return *this; + } + + + /*! + this method converts the sint type to this class + */ + Int & operator=(sint i) + { + FromInt(i); + + return *this; + } + + + /*! + a constructor for converting the uint to this class + */ + Int(sint i) + { + FromInt(i); + } + + + /*! + a copy constructor + */ + Int(const Int & u) + { + FromInt(u); + } + + + /*! + a constructor for copying from another types + */ + template + Int(const Int & u) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + FromInt(u); + } + + + + /*! + this operator converts an UInt type to this class + + it doesn't return a carry + */ + template + Int & operator=(const UInt & p) + { + FromUInt(p); + + return *this; + } + + + /*! + this method converts the Uint type to this class + */ + Int & operator=(uint i) + { + FromUInt(i); + + return *this; + } + + + /*! + a constructor for converting the uint to this class + */ + Int(uint i) + { + FromUInt(i); + } + + + /*! + a constructor for copying from another types + */ + template + Int(const UInt & u) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + FromUInt(u); + } + + + + +#ifdef TTMATH_PLATFORM64 + + /*! + this method converts the signed int type to this class + + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int & operator=(signed int i) + { + FromInt(sint(i)); + + return *this; + } + + + /*! + a constructor for converting the signed int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int(signed int i) + { + FromInt(sint(i)); + } + + + /*! + this method converts the unsigned int type to this class + + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int & operator=(unsigned int i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the unsigned int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + Int(unsigned int i) + { + FromUInt(uint(i)); + } + +#endif + + + /*! + a constructor for converting string to this class (with the base=10) + */ + Int(const char * s) + { + FromString(s); + } + + + /*! + a constructor for converting string to this class (with the base=10) + */ + Int(const wchar_t * s) + { + FromString(s); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + Int(const std::string & s) + { + FromString( s.c_str() ); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + Int(const std::wstring & s) + { + FromString( s.c_str() ); + } + + + /*! + a default constructor + + we don't clear table etc. + */ + Int() + { + } + + + /*! + the destructor + */ + ~Int() + { + } + + + /*! + this method returns the lowest value from table with a sign + + we must be sure when we using this method whether the value + will hold in an sint type or not (the rest value from table must be zero or -1) + */ + sint ToInt() const + { + return sint( UInt::table[0] ); + } + + +private: + + /*! + an auxiliary method for converting to a string + */ + template + void ToStringBase(string_type & result, uint b = 10) const + { + if( IsSign() ) + { + Int temp(*this); + temp.Abs(); + + temp.UInt::ToString(result, b); + result.insert(result.begin(), '-'); + } + else + { + UInt::ToString(result, b); + } + } + +public: + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::string & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::wstring & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + std::string ToString(uint b = 10) const + { + std::string result; + ToStringBase(result, b); + + return result; + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + std::wstring ToWString(uint b = 10) const + { + std::wstring result; + ToStringBase(result, b); + + return result; + } + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + uint FromStringBase(const char_type * s, uint b = 10, const char_type ** after_source = 0, bool * value_read = 0) + { + bool is_sign = false; + + Misc::SkipWhiteCharacters(s); + + if( *s == '-' ) + { + is_sign = true; + Misc::SkipWhiteCharacters(++s); + } + else + if( *s == '+' ) + { + Misc::SkipWhiteCharacters(++s); + } + + if( UInt::FromString(s,b,after_source,value_read) ) + return 1; + + if( is_sign ) + { + Int mmin; + + mmin.SetMin(); + + /* + the reference to mmin will be automatically converted to the reference + to UInt type + (this value can be equal mmin -- look at a description in ChangeSign()) + */ + if( UInt::operator>( mmin ) ) + return 1; + + /* + if the value is equal mmin the method ChangeSign() does nothing (only returns 1 but we ignore it) + */ + ChangeSign(); + } + else + { + Int mmax; + + mmax.SetMax(); + + if( UInt::operator>( mmax ) ) + return 1; + } + + return 0; + } + + +public: + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + + string is ended with a non-digit value, for example: + "-12" will be translated to -12 + as well as: + "- 12foo" will be translated to -12 too + + existing first white characters will be ommited + (between '-' and a first digit can be white characters too) + + after_source (if exists) is pointing at the end of the parsed string + + value_read (if exists) tells whether something has actually been read (at least one digit) + */ + uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + */ + uint FromString(const wchar_t * s, uint b = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + */ + uint FromString(const std::string & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + */ + uint FromString(const std::wstring & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const char * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const wchar_t * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const std::string & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + Int & operator=(const std::wstring & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + * + * methods for comparing + * + * + */ + + bool operator==(const Int & l) const + { + return UInt::operator==(l); + } + + bool operator!=(const Int & l) const + { + return UInt::operator!=(l); + } + + bool operator<(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 < a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] < l.table[i]; + } + + // they're equal + return false; + } + + + bool operator>(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 > a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] > l.table[i]; + } + + // they're equal + return false; + } + + + bool operator<=(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 < a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] < l.table[i]; + } + + // they're equal + return true; + } + + + bool operator>=(const Int & l) const + { + sint i=value_size-1; + + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); + + if( a1 != a2 ) + return a1 > a2; + + + for(--i ; i>=0 ; --i) + { + if( UInt::table[i] != l.table[i] ) + // comparison as unsigned int + return UInt::table[i] > l.table[i]; + } + + // they're equal + return true; + } + + + + /*! + * + * standard mathematical operators + * + */ + + + /*! + an operator for changing the sign + + it's not changing 'this' but the changed value will be returned + */ + Int operator-() const + { + Int temp(*this); + + temp.ChangeSign(); + + return temp; + } + + + Int operator-(const Int & p2) const + { + Int temp(*this); + + temp.Sub(p2); + + return temp; + } + + + Int & operator-=(const Int & p2) + { + Sub(p2); + + return *this; + } + + + Int operator+(const Int & p2) const + { + Int temp(*this); + + temp.Add(p2); + + return temp; + } + + + Int & operator+=(const Int & p2) + { + Add(p2); + + return *this; + } + + + Int operator*(const Int & p2) const + { + Int temp(*this); + + temp.Mul(p2); + + return temp; + } + + + Int & operator*=(const Int & p2) + { + Mul(p2); + + return *this; + } + + + Int operator/(const Int & p2) const + { + Int temp(*this); + + temp.Div(p2); + + return temp; + } + + + Int & operator/=(const Int & p2) + { + Div(p2); + + return *this; + } + + + Int operator%(const Int & p2) const + { + Int temp(*this); + Int remainder; + + temp.Div(p2, remainder); + + return remainder; + } + + + Int & operator%=(const Int & p2) + { + Int temp(*this); + Int remainder; + + temp.Div(p2, remainder); + + operator=(remainder); + + return *this; + } + + + /*! + Prefix operator e.g. ++variable + */ + UInt & operator++() + { + AddOne(); + + return *this; + } + + + /*! + Postfix operator e.g. variable++ + */ + UInt operator++(int) + { + UInt temp( *this ); + + AddOne(); + + return temp; + } + + + UInt & operator--() + { + SubOne(); + + return *this; + } + + + UInt operator--(int) + { + UInt temp( *this ); + + SubOne(); + + return temp; + } + + + + /*! + * + * input/output operators for standard streams + * + */ + +private: + + /*! + an auxiliary method for outputing to standard streams + */ + template + static ostream_type & OutputToStream(ostream_type & s, const Int & l) + { + string_type ss; + + l.ToString(ss); + s << ss; + + return s; + } + + + +public: + + + /*! + output to standard streams + */ + friend std::ostream & operator<<(std::ostream & s, const Int & l) + { + return OutputToStream(s, l); + } + + + /*! + output to standard streams + */ + friend std::wostream & operator<<(std::wostream & s, const Int & l) + { + return OutputToStream(s, l); + } + + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + static istream_type & InputFromStream(istream_type & s, Int & l) + { + string_type ss; + + // char or wchar_t for operator>> + char_type z; + + // operator>> omits white characters if they're set for ommiting + s >> z; + + if( z=='-' || z=='+' ) + { + ss += z; + s >> z; // we're reading a next character (white characters can be ommited) + } + + // we're reading only digits (base=10) + while( s.good() && Misc::CharToDigit(z, 10)>=0 ) + { + ss += z; + z = static_cast(s.get()); + } + + // we're leaving the last readed character + // (it's not belonging to the value) + s.unget(); + + l.FromString(ss); + + return s; + } + + +public: + + /*! + input from standard streams + */ + friend std::istream & operator>>(std::istream & s, Int & l) + { + return InputFromStream(s, l); + } + + + /*! + input from standard streams + */ + friend std::wistream & operator>>(std::wistream & s, Int & l) + { + return InputFromStream(s, l); + } + +}; + +} // namespace + +#endif diff --git a/ttmath/ttmathmisc.h b/ttmath/ttmathmisc.h new file mode 100644 index 0000000..38ab596 --- /dev/null +++ b/ttmath/ttmathmisc.h @@ -0,0 +1,243 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfilettmathmisc +#define headerfilettmathmisc + + +/*! + \file ttmathmisc.h + \brief some helpful functions +*/ + + +#include + + +namespace ttmath +{ + +/*! + some helpful functions +*/ +class Misc +{ +public: + + +/* + * + * AssignString(result, str) + * result = str + * + */ + +/*! + result = str +*/ +static void AssignString(std::string & result, const char * str) +{ + result = str; +} + + +/*! + result = str +*/ +static void AssignString(std::wstring & result, const char * str) +{ + result.clear(); + + for( ; *str ; ++str ) + result += *str; +} + + +/*! + result = str +*/ +static void AssignString(std::wstring & result, const std::string & str) +{ + return AssignString(result, str.c_str()); +} + + +/*! + result = str +*/ +static void AssignString(std::string & result, const wchar_t * str) +{ + result.clear(); + + for( ; *str ; ++str ) + result += static_cast(*str); +} + + +/*! + result = str +*/ +static void AssignString(std::string & result, const std::wstring & str) +{ + return AssignString(result, str.c_str()); +} + + +/* + * + * AddString(result, str) + * result += str + * + */ + + +/*! + result += str +*/ +static void AddString(std::string & result, const char * str) +{ + result += str; +} + + +/*! + result += str +*/ +static void AddString(std::wstring & result, const char * str) +{ + for( ; *str ; ++str ) + result += *str; +} + + + +/* + this method omits any white characters from the string + char_type is char or wchar_t +*/ +template +static void SkipWhiteCharacters(const char_type * & c) +{ + // 13 is at the end in a DOS text file (\r\n) + while( (*c==' ' ) || (*c=='\t') || (*c==13 ) || (*c=='\n') ) + ++c; +} + + + + +/*! + this static method converts one character into its value + + for example: + 1 -> 1 + 8 -> 8 + A -> 10 + f -> 15 + + this method don't check whether c is correct or not +*/ +static uint CharToDigit(uint c) +{ + if(c>='0' && c<='9') + return c-'0'; + + if(c>='a' && c<='z') + return c-'a'+10; + +return c-'A'+10; +} + + +/*! + this method changes a character 'c' into its value + (if there can't be a correct value it returns -1) + + for example: + c=2, base=10 -> function returns 2 + c=A, base=10 -> function returns -1 + c=A, base=16 -> function returns 10 +*/ +static sint CharToDigit(uint c, uint base) +{ + if( c>='0' && c<='9' ) + c=c-'0'; + else + if( c>='a' && c<='z' ) + c=c-'a'+10; + else + if( c>='A' && c<='Z' ) + c=c-'A'+10; + else + return -1; + + + if( c >= base ) + return -1; + + +return sint(c); +} + + + +/*! + this method converts a digit into a char + digit should be from <0,F> + (we don't have to get a base) + + for example: + 1 -> 1 + 8 -> 8 + 10 -> A + 15 -> F +*/ +static uint DigitToChar(uint digit) +{ + if( digit < 10 ) + return digit + '0'; + +return digit - 10 + 'A'; +} + + +}; // struct Misc + +} + + +#endif diff --git a/ttmath/ttmathobjects.h b/ttmath/ttmathobjects.h new file mode 100644 index 0000000..5fe343d --- /dev/null +++ b/ttmath/ttmathobjects.h @@ -0,0 +1,766 @@ +/* + * This file is a part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef headerfilettmathobject +#define headerfilettmathobject + +/*! + \file ttmathobjects.h + \brief Mathematic functions. +*/ + +#include +#include +#include +#include + +#include "ttmathtypes.h" +#include "ttmathmisc.h" + + +namespace ttmath +{ + +/*! + objects of this class are used with the mathematical parser + they hold variables or functions defined by a user + + each object has its own table in which we're keeping variables or functions +*/ +class Objects +{ +public: + + + /*! + one item (variable or function) + 'items' will be on the table + */ + struct Item + { + // name of a variable of a function + // internally we store variables and funcions as std::string (not std::wstring even when wide characters are used) + std::string value; + + // number of parameters required by the function + // (if there's a variable this 'param' is ignored) + int param; + + Item() {} + Item(const std::string & v, int p) : value(v), param(p) {} + }; + + // 'Table' is the type of our table + typedef std::map Table; + typedef Table::iterator Iterator; + typedef Table::const_iterator CIterator; + + + + /*! + this method returns true if a character 'c' is a character + which can be in a name + + if 'can_be_digit' is true that means when the 'c' is a digit this + method returns true otherwise it returns false + */ + static bool CorrectCharacter(wchar_t c, bool can_be_digit) + { + if( (c>='a' && c<='z') || (c>='A' && c<='Z') ) + return true; + + if( can_be_digit && ((c>='0' && c<='9') || c=='_') ) + return true; + + return false; + } + + + /*! + this method returns true if the name can be as a name of an object + */ + template + static bool IsNameCorrect(const string_type & name) + { + if( name.empty() ) + return false; + + if( !CorrectCharacter(name[0], false) ) + return false; + + typename string_type::const_iterator i = name.begin(); + + for(++i ; i!=name.end() ; ++i) + if( !CorrectCharacter(*i, true) ) + return false; + + return true; + } + + + /*! + this method returns true if such an object is defined (name exists) + */ + bool IsDefined(const std::string & name) + { + Iterator i = table.find(name); + + if( i != table.end() ) + // we have this object in our table + return true; + + return false; + } + + + /*! + this method returns true if such an object is defined (name exists) + */ + bool IsDefined(const std::wstring & name) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return false; + + Misc::AssignString(str_tmp1, name); + + return IsDefined(str_tmp1); + } + + + /*! + this method adds one object (variable of function) into the table + */ + ErrorCode Add(const std::string & name, const std::string & value, int param = 0) + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Iterator i = table.find(name); + + if( i != table.end() ) + // we have this object in our table + return err_object_exists; + + table.insert( std::make_pair(name, Item(value, param)) ); + + return err_ok; + } + + + /*! + this method adds one object (variable of function) into the table + */ + ErrorCode Add(const std::wstring & name, const std::wstring & value, int param = 0) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + Misc::AssignString(str_tmp2, value); + + return Add(str_tmp1, str_tmp2, param); + } + + + /*! + this method returns 'true' if the table is empty + */ + bool Empty() const + { + return table.empty(); + } + + + /*! + this method clears the table + */ + void Clear() + { + return table.clear(); + } + + + /*! + this method returns 'const_iterator' on the first item on the table + */ + CIterator Begin() const + { + return table.begin(); + } + + + /*! + this method returns 'const_iterator' pointing at the space after last item + (returns table.end()) + */ + CIterator End() const + { + return table.end(); + } + + + /*! + this method changes the value and the number of parameters for a specific object + */ + ErrorCode EditValue(const std::string & name, const std::string & value, int param = 0) + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Iterator i = table.find(name); + + if( i == table.end() ) + return err_unknown_object; + + i->second.value = value; + i->second.param = param; + + return err_ok; + } + + + /*! + this method changes the value and the number of parameters for a specific object + */ + ErrorCode EditValue(const std::wstring & name, const std::wstring & value, int param = 0) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + Misc::AssignString(str_tmp2, value); + + return EditValue(str_tmp1, str_tmp2, param); + } + + + /*! + this method changes the name of a specific object + */ + ErrorCode EditName(const std::string & old_name, const std::string & new_name) + { + if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) ) + return err_incorrect_name; + + Iterator old_i = table.find(old_name); + if( old_i == table.end() ) + return err_unknown_object; + + if( old_name == new_name ) + // the new name is the same as the old one + // we treat it as a normal situation + return err_ok; + + ErrorCode err = Add(new_name, old_i->second.value, old_i->second.param); + + if( err == err_ok ) + { + old_i = table.find(old_name); + TTMATH_ASSERT( old_i != table.end() ) + + table.erase(old_i); + } + + return err; + } + + + /*! + this method changes the name of a specific object + */ + ErrorCode EditName(const std::wstring & old_name, const std::wstring & new_name) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(old_name) || !IsNameCorrect(new_name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, old_name); + Misc::AssignString(str_tmp2, new_name); + + return EditName(str_tmp1, str_tmp2); + } + + + /*! + this method deletes an object + */ + ErrorCode Delete(const std::string & name) + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Iterator i = table.find(name); + + if( i == table.end() ) + return err_unknown_object; + + table.erase( i ); + + return err_ok; + } + + + /*! + this method deletes an object + */ + ErrorCode Delete(const std::wstring & name) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + + return Delete(str_tmp1); + } + + + /*! + this method gets the value of a specific object + */ + ErrorCode GetValue(const std::string & name, std::string & value) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + value.clear(); + return err_unknown_object; + } + + value = i->second.value; + + return err_ok; + } + + + /*! + this method gets the value of a specific object + */ + ErrorCode GetValue(const std::wstring & name, std::wstring & value) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + ErrorCode err = GetValue(str_tmp1, str_tmp2); + Misc::AssignString(value, str_tmp2); + + return err; + } + + + /*! + this method gets the value of a specific object + (this version is used for not copying the whole string) + */ + ErrorCode GetValue(const std::string & name, const char ** value) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + *value = 0; + return err_unknown_object; + } + + *value = i->second.value.c_str(); + + return err_ok; + } + + + /*! + this method gets the value of a specific object + (this version is used for not copying the whole string) + */ + ErrorCode GetValue(const std::wstring & name, const char ** value) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + + return GetValue(str_tmp1, value); + } + + + /*! + this method gets the value and the number of parameters + of a specific object + */ + ErrorCode GetValueAndParam(const std::string & name, std::string & value, int * param) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + value.empty(); + *param = 0; + return err_unknown_object; + } + + value = i->second.value; + *param = i->second.param; + + return err_ok; + } + + + /*! + this method gets the value and the number of parameters + of a specific object + */ + ErrorCode GetValueAndParam(const std::wstring & name, std::wstring & value, int * param) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + ErrorCode err = GetValueAndParam(str_tmp1, str_tmp2, param); + Misc::AssignString(value, str_tmp2); + + return err; + } + + + /*! + this method sets the value and the number of parameters + of a specific object + (this version is used for not copying the whole string) + */ + ErrorCode GetValueAndParam(const std::string & name, const char ** value, int * param) const + { + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + CIterator i = table.find(name); + + if( i == table.end() ) + { + *value = 0; + *param = 0; + return err_unknown_object; + } + + *value = i->second.value.c_str(); + *param = i->second.param; + + return err_ok; + } + + + /*! + this method sets the value and the number of parameters + of a specific object + (this version is used for not copying the whole string + but in fact we make one copying during AssignString()) + */ + ErrorCode GetValueAndParam(const std::wstring & name, const char ** value, int * param) + { + // we should check whether the name (in wide characters) are correct + // before calling AssignString() function + if( !IsNameCorrect(name) ) + return err_incorrect_name; + + Misc::AssignString(str_tmp1, name); + + return GetValueAndParam(str_tmp1, value, param); + } + + + /*! + this method returns a pointer into the table + */ + Table * GetTable() + { + return &table; + } + + +private: + + Table table; + std::string str_tmp1, str_tmp2; + +}; // end of class Objects + + + + + + + +/*! + objects of the class History are used to keep values in functions + which take a lot of time during calculating, for instance in the + function Factorial(x) + + it means that when we're calculating e.g. Factorial(1000) and the + Factorial finds that we have calculated it before, the value (result) + is taken from the history +*/ +template +class History +{ + /*! + one item in the History's object holds a key, a value for the key + and a corresponding error code + */ + struct Item + { + ValueType key, value; + ErrorCode err; + }; + + + /*! + we use std::list for simply deleting the first item + but because we're searching through the whole container + (in the method Get) the container should not be too big + (linear time of searching) + */ + typedef std::list buffer_type; + buffer_type buffer; + typename buffer_type::size_type buffer_max_size; + +public: + + /*! + default constructor + default max size of the History's container is 15 items + */ + History() + { + buffer_max_size = 15; + } + + + /*! + a constructor which takes another value of the max size + of the History's container + */ + History(typename buffer_type::size_type new_size) + { + buffer_max_size = new_size; + } + + + /*! + this method adds one item into the History + if the size of the container is greater than buffer_max_size + the first item will be removed + */ + void Add(const ValueType & key, const ValueType & value, ErrorCode err) + { + Item item; + item.key = key; + item.value = value; + item.err = err; + + buffer.insert( buffer.end(), item ); + + if( buffer.size() > buffer_max_size ) + buffer.erase(buffer.begin()); + } + + + /*! + this method checks whether we have an item which has the key equal 'key' + + if there's such item the method sets the 'value' and the 'err' + and returns true otherwise it returns false and 'value' and 'err' + remain unchanged + */ + bool Get(const ValueType & key, ValueType & value, ErrorCode & err) + { + typename buffer_type::iterator i = buffer.begin(); + + for( ; i != buffer.end() ; ++i ) + { + if( i->key == key ) + { + value = i->value; + err = i->err; + return true; + } + } + + return false; + } + + + /*! + this methods deletes an item + + we assume that there is only one item with the 'key' + (this methods removes the first one) + */ + bool Remove(const ValueType & key) + { + typename buffer_type::iterator i = buffer.begin(); + + for( ; i != buffer.end() ; ++i ) + { + if( i->key == key ) + { + buffer.erase(i); + return true; + } + } + + return false; + } + + +}; // end of class History + + + +/*! + this is an auxiliary class used when calculating Gamma() or Factorial() + + in multithreaded environment you can provide an object of this class to + the Gamma() or Factorial() function, e.g; + typedef Big<1, 3> MyBig; + MyBig x = 123456; + CGamma cgamma; + std::cout << Gamma(x, cgamma); + each thread should have its own CGamma<> object + + in a single-thread environment a CGamma<> object is a static variable + in a second version of Gamma() and you don't have to explicitly use it, e.g. + typedef Big<1, 3> MyBig; + MyBig x = 123456; + std::cout << Gamma(x); +*/ +template +struct CGamma +{ + /*! + this table holds factorials + 1 + 1 + 2 + 6 + 24 + 120 + 720 + ....... + */ + std::vector fact; + + + /*! + this table holds Bernoulli numbers + 1 + -0.5 + 0.166666666666666666666666667 + 0 + -0.0333333333333333333333333333 + 0 + 0.0238095238095238095238095238 + 0 + -0.0333333333333333333333333333 + 0 + 0.075757575757575757575757576 + ..... + */ + std::vector bern; + + + /*! + here we store some calculated values + (this is for speeding up, if the next argument of Gamma() or Factorial() + is in the 'history' then the result we are not calculating but simply + return from the 'history' object) + */ + History history; + + + /*! + this method prepares some coefficients: factorials and Bernoulli numbers + stored in 'fact' and 'bern' objects + + how many values should be depends on the size of the mantissa - if + the mantissa is larger then we must calculate more values + for a mantissa which consists of 256 bits (8 words on a 32bit platform) + we have to calculate about 30 values (the size of fact and bern will be 30), + and for a 2048 bits mantissa we have to calculate 306 coefficients + + you don't have to call this method, these coefficients will be automatically calculated + when they are needed + + you must note that calculating these coefficients is a little time-consuming operation, + (especially when the mantissa is large) and first call to Gamma() or Factorial() + can take more time than next calls, and in the end this is the point when InitAll() + comes in handy: you can call this method somewhere at the beginning of your program + */ + void InitAll(); + // definition is in ttmath.h +}; + + + + +} // namespace + +#endif diff --git a/ttmath/ttmathparser.h b/ttmath/ttmathparser.h new file mode 100644 index 0000000..3f9c796 --- /dev/null +++ b/ttmath/ttmathparser.h @@ -0,0 +1,2754 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2010, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#ifndef headerfilettmathparser +#define headerfilettmathparser + +/*! + \file ttmathparser.h + \brief A mathematical parser +*/ + +#include +#include +#include +#include + +#include "ttmath.h" +#include "ttmathobjects.h" +#include "ttmathmisc.h" + + + +namespace ttmath +{ + +/*! + \brief Mathematical parser + + let x will be an input string meaning an expression for converting: + + x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]... + where: + an operator can be: + ^ (pow) (the heighest priority) + + * (mul) (or multiplication without an operator -- short mul) + / (div) (* and / have the same priority) + + + (add) + - (sub) (+ and - have the same priority) + + < (lower than) + > (greater than) + <= (lower or equal than) + >= (greater or equal than) + == (equal) + != (not equal) (all above logical operators have the same priority) + + && (logical and) + + || (logical or) (the lowest priority) + + short mul: + if the second Value (Var below) is either a variable or function there might not be + an operator between them, e.g. + "[+|-]Value Var" is treated as "[+|-]Value * Var" and the multiplication + has the same priority as a normal multiplication: + 4x = 4 * x + 2^3m = (2^3)* m + 6h^3 = 6 * (h^3) + 2sin(pi) = 2 * sin(pi) + etc. + + Value can be: + constant e.g. 100, can be preceded by operators for changing the base (radix): [#|&] + # - hex + & - bin + sample: #10 = 16 + &10 = 2 + variable e.g. pi + another expression between brackets e.g (x) + function e.g. sin(x) + + for example a correct input string can be: + "1" + "2.1234" + "2,1234" (they are the same, by default we can either use a comma or a dot) + "1 + 2" + "(1 + 2) * 3" + "pi" + "sin(pi)" + "(1+2)*(2+3)" + "log(2;1234)" there's a semicolon here (not a comma), we use it in functions + for separating parameters + "1 < 2" (the result will be: 1) + "4 < 3" (the result will be: 0) + "2+x" (of course if the variable 'x' is defined) + "4x+10" + "#20+10" = 32 + 10 = 42 + "10 ^ -&101" = 10 ^ -5 = 0.00001 + "8 * -&10" = 8 * -2 = -16 + etc. + + we can also use a semicolon for separating any 'x' input strings + for example: + "1+2;4+5" + the result will be on the stack as follows: + "3" + "9" +*/ +template +class Parser +{ +private: + +/*! + there are 5 mathematical operators as follows (with their standard priorities): + add (+) + sub (-) + mul (*) + div (/) + pow (^) + and 'shortmul' used when there is no any operators between + a first parameter and a variable or function + (the 'shortmul' has the same priority as the normal multiplication ) +*/ + class MatOperator + { + public: + + enum Type + { + none,add,sub,mul,div,pow,lt,gt,let,get,eq,neq,lor,land,shortmul + }; + + enum Assoc + { + right, // right-associative + non_right // associative or left-associative + }; + + Type GetType() const { return type; } + int GetPriority() const { return priority; } + Assoc GetAssoc() const { return assoc; } + + void SetType(Type t) + { + type = t; + assoc = non_right; + + switch( type ) + { + case lor: + priority = 4; + break; + + case land: + priority = 5; + break; + + case eq: + case neq: + case lt: + case gt: + case let: + case get: + priority = 7; + break; + + case add: + case sub: + priority = 10; + break; + + case mul: + case shortmul: + case div: + priority = 12; + break; + + case pow: + priority = 14; + assoc = right; + break; + + default: + Error( err_internal_error ); + break; + } + } + + MatOperator(): type(none), priority(0), assoc(non_right) + { + } + + private: + + Type type; + int priority; + Assoc assoc; + }; // end of MatOperator class + + + +public: + + + + /*! + Objects of type 'Item' we are keeping on our stack + */ + struct Item + { + enum Type + { + none, numerical_value, mat_operator, first_bracket, + last_bracket, variable, semicolon + }; + + // The kind of type which we're keeping + Type type; + + // if type == numerical_value + ValueType value; + + // if type == mat_operator + MatOperator moperator; + + /* + if type == first_bracket + + if 'function' is set to true it means that the first recognized bracket + was the bracket from function in other words we must call a function when + we'll find the 'last' bracket + */ + bool function; + + // if function is true + std::string function_name; + + /* + the sign of value + + it can be for type==numerical_value or type==first_bracket + when it's true it means e.g. that value is equal -value + */ + bool sign; + + Item(): type(none), function(false), sign(false) + { + } + + }; // end of Item struct + + +/*! + stack on which we're keeping the Items + + at the end of parsing we'll have the result on its + the result don't have to be one value, it can be a list + of values separated by the 'semicolon item' +*/ +std::vector stack; + + +private: + + +/*! + size of the stack when we're starting parsing of the string + + if it's to small while parsing the stack will be automatically resized +*/ +const int default_stack_size; + + + +/*! + index of an object in our stack + it's pointing on the place behind the last element + for example at the beginning of parsing its value is zero +*/ +unsigned int stack_index; + + +/*! + code of the last error +*/ +ErrorCode error; + + +/*! + pointer to the currently reading char + it's either char* or wchar_t* + + when an error has occured it may be used to count the index of the wrong character +*/ +const char * pstring; + + +/*! + the base (radix) of the mathematic system (for example it may be '10') +*/ +int base; + + +/*! + the unit of angles used in: sin,cos,tan,cot,asin,acos,atan,acot + 0 - deg + 1 - rad (default) + 2 - grad +*/ +int deg_rad_grad; + + + +/*! + a pointer to an object which tell us whether we should stop calculating or not +*/ +const volatile StopCalculating * pstop_calculating; + + + +/*! + a pointer to the user-defined variables' table +*/ +const Objects * puser_variables; + +/*! + a pointer to the user-defined functions' table +*/ +const Objects * puser_functions; + + +typedef std::map FunctionLocalVariables; + +/*! + a pointer to the local variables of a function +*/ +const FunctionLocalVariables * pfunction_local_variables; + + +/*! + a temporary set using during parsing user defined variables +*/ +std::set visited_variables; + + +/*! + a temporary set using during parsing user defined functions +*/ +std::set visited_functions; + + + + +/*! + pfunction is the type of pointer to a mathematic function + + these mathematic functions are private members of this class, + they are the wrappers for standard mathematics function + + 'pstack' is the pointer to the first argument on our stack + 'amount_of_arg' tell us how many argument there are in our stack + 'result' is the reference for result of function +*/ +typedef void (Parser::*pfunction)(int pstack, int amount_of_arg, ValueType & result); + + +/*! + pfunction is the type of pointer to a method which returns value of variable +*/ +typedef void (ValueType::*pfunction_var)(); + + +/*! + table of mathematic functions + + this map consists of: + std::string - function's name + pfunction - pointer to specific function +*/ +typedef std::map FunctionsTable; +FunctionsTable functions_table; + + +/*! + table of mathematic operators + + this map consists of: + std::string - operators's name + MatOperator::Type - type of the operator +*/ +typedef std::map OperatorsTable; +OperatorsTable operators_table; + + +/*! + table of mathematic variables + + this map consists of: + std::string - variable's name + pfunction_var - pointer to specific function which returns value of variable +*/ +typedef std::map VariablesTable; +VariablesTable variables_table; + + +/*! + some coefficients used when calculating the gamma (or factorial) function +*/ +CGamma cgamma; + + +/*! + temporary object for a whole string when Parse(std::wstring) is used +*/ +std::string wide_to_ansi; + + +/*! + group character (used when parsing) + default zero (not used) +*/ +int group; + + +/*! + characters used as a comma + default: '.' and ',' + comma2 can be zero (it means it is not used) +*/ +int comma, comma2; + + +/*! + an additional character used as a separator between function parameters + (semicolon is used always) +*/ +int param_sep; + + +/*! + true if something was calculated (at least one mathematical operator was used or a function or a variable) +*/ +bool calculated; + + + +/*! + we're using this method for reporting an error +*/ +static void Error(ErrorCode code) +{ + throw code; +} + + +/*! + this method skips the white character from the string + + it's moving the 'pstring' to the first no-white character +*/ +void SkipWhiteCharacters() +{ + while( (*pstring==' ' ) || (*pstring=='\t') ) + ++pstring; +} + + +/*! + an auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_CheckStopCondition(bool variable, const std::string & name) +{ + if( variable ) + { + if( visited_variables.find(name) != visited_variables.end() ) + Error( err_variable_loop ); + } + else + { + if( visited_functions.find(name) != visited_functions.end() ) + Error( err_functions_loop ); + } +} + + +/*! + an auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_AddName(bool variable, const std::string & name) +{ + if( variable ) + visited_variables.insert( name ); + else + visited_functions.insert( name ); +} + + +/*! + an auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_DeleteName(bool variable, const std::string & name) +{ + if( variable ) + visited_variables.erase( name ); + else + visited_functions.erase( name ); +} + + +/*! + this method returns the value of a variable or function + by creating a new instance of the mathematical parser + and making the standard parsing algorithm on the given string + + this method is used only during parsing user defined variables or functions + + (there can be a recurrence here therefore we're using 'visited_variables' + and 'visited_functions' sets to make a stop condition) +*/ +ValueType RecurrenceParsingVariablesOrFunction(bool variable, const std::string & name, const char * new_string, + FunctionLocalVariables * local_variables = 0) +{ + RecurrenceParsingVariablesOrFunction_CheckStopCondition(variable, name); + RecurrenceParsingVariablesOrFunction_AddName(variable, name); + + Parser NewParser(*this); + ErrorCode err; + + NewParser.pfunction_local_variables = local_variables; + + try + { + err = NewParser.Parse(new_string); + } + catch(...) + { + RecurrenceParsingVariablesOrFunction_DeleteName(variable, name); + + throw; + } + + RecurrenceParsingVariablesOrFunction_DeleteName(variable, name); + + if( err != err_ok ) + Error( err ); + + if( NewParser.stack.size() != 1 ) + Error( err_must_be_only_one_value ); + + if( NewParser.stack[0].type != Item::numerical_value ) + // I think there shouldn't be this error here + Error( err_incorrect_value ); + +return NewParser.stack[0].value; +} + + +public: + + +/*! + this method returns the user-defined value of a variable +*/ +bool GetValueOfUserDefinedVariable(const std::string & variable_name,ValueType & result) +{ + if( !puser_variables ) + return false; + + const char * string_value; + + if( puser_variables->GetValue(variable_name, &string_value) != err_ok ) + return false; + + result = RecurrenceParsingVariablesOrFunction(true, variable_name, string_value); + calculated = true; + +return true; +} + + +/*! + this method returns the value of a local variable of a function +*/ +bool GetValueOfFunctionLocalVariable(const std::string & variable_name, ValueType & result) +{ + if( !pfunction_local_variables ) + return false; + + typename FunctionLocalVariables::const_iterator i = pfunction_local_variables->find(variable_name); + + if( i == pfunction_local_variables->end() ) + return false; + + result = i->second; + +return true; +} + + +/*! + this method returns the value of a variable from variables' table + + we make an object of type ValueType then call a method which + sets the correct value in it and finally we'll return the object +*/ +ValueType GetValueOfVariable(const std::string & variable_name) +{ +ValueType result; + + if( GetValueOfFunctionLocalVariable(variable_name, result) ) + return result; + + if( GetValueOfUserDefinedVariable(variable_name, result) ) + return result; + + + typename std::map::iterator i = + variables_table.find(variable_name); + + if( i == variables_table.end() ) + Error( err_unknown_variable ); + + (result.*(i->second))(); + calculated = true; + +return result; +} + + +private: + +/*! + wrappers for mathematic functions + + 'sindex' is pointing on the first argument on our stack + (the second argument has 'sindex+2' + because 'sindex+1' is guaranted for the 'semicolon' operator) + the third artument has of course 'sindex+4' etc. + + 'result' will be the result of the function + + (we're using exceptions here for example when function gets an improper argument) +*/ + + +/*! + used by: sin,cos,tan,cot +*/ +ValueType ConvertAngleToRad(const ValueType & input) +{ + if( deg_rad_grad == 1 ) // rad + return input; + + ValueType result; + ErrorCode err; + + if( deg_rad_grad == 0 ) // deg + result = ttmath::DegToRad(input, &err); + else // grad + result = ttmath::GradToRad(input, &err); + + if( err != err_ok ) + Error( err ); + +return result; +} + + +/*! + used by: asin,acos,atan,acot +*/ +ValueType ConvertRadToAngle(const ValueType & input) +{ + if( deg_rad_grad == 1 ) // rad + return input; + + ValueType result; + ErrorCode err; + + if( deg_rad_grad == 0 ) // deg + result = ttmath::RadToDeg(input, &err); + else // grad + result = ttmath::RadToGrad(input, &err); + + if( err != err_ok ) + Error( err ); + +return result; +} + + +void Gamma(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + + result = ttmath::Gamma(stack[sindex].value, cgamma, &err, pstop_calculating); + + if(err != err_ok) + Error( err ); +} + + +/*! + factorial + result = 1 * 2 * 3 * 4 * .... * x +*/ +void Factorial(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + + result = ttmath::Factorial(stack[sindex].value, cgamma, &err, pstop_calculating); + + if(err != err_ok) + Error( err ); +} + + +void Abs(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::Abs(stack[sindex].value); +} + +void Sin(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Sin( ConvertAngleToRad(stack[sindex].value), &err ); + + if(err != err_ok) + Error( err ); +} + +void Cos(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Cos( ConvertAngleToRad(stack[sindex].value), &err ); + + if(err != err_ok) + Error( err ); +} + +void Tan(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Tan(ConvertAngleToRad(stack[sindex].value), &err); + + if(err != err_ok) + Error( err ); +} + +void Cot(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Cot(ConvertAngleToRad(stack[sindex].value), &err); + + if(err != err_ok) + Error( err ); +} + +void Int(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::SkipFraction(stack[sindex].value); +} + + +void Round(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = stack[sindex].value; + + if( result.Round() ) + Error( err_overflow ); +} + + +void Ln(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Ln(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); +} + +void Log(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 2 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Log(stack[sindex].value, stack[sindex+2].value, &err); + + if(err != err_ok) + Error( err ); +} + +void Exp(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::Exp(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); +} + + +void Max(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args == 0 ) + { + result.SetMax(); + + return; + } + + result = stack[sindex].value; + + for(int i=1 ; i stack[sindex + i*2].value ) + result = stack[sindex + i*2].value; + } +} + + +void ASin(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + ValueType temp = ttmath::ASin(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); + + result = ConvertRadToAngle(temp); +} + + +void ACos(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + ValueType temp = ttmath::ACos(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); + + result = ConvertRadToAngle(temp); +} + + +void ATan(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ConvertRadToAngle(ttmath::ATan(stack[sindex].value)); +} + + +void ACot(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ConvertRadToAngle(ttmath::ACot(stack[sindex].value)); +} + + +void Sgn(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::Sgn(stack[sindex].value); +} + + +void Mod(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 2 ) + Error( err_improper_amount_of_arguments ); + + if( stack[sindex+2].value.IsZero() ) + Error( err_improper_argument ); + + result = stack[sindex].value; + uint c = result.Mod(stack[sindex+2].value); + + if( c ) + Error( err_overflow ); +} + + +void If(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 3 ) + Error( err_improper_amount_of_arguments ); + + + if( !stack[sindex].value.IsZero() ) + result = stack[sindex+2].value; + else + result = stack[sindex+4].value; +} + + +void Or(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args < 2 ) + Error( err_improper_amount_of_arguments ); + + for(int i=0 ; iGetValueAndParam(function_name, &string_value, ¶m) != err_ok ) + return false; + + if( param != amount_of_args ) + Error( err_improper_amount_of_arguments ); + + + FunctionLocalVariables local_variables; + + if( amount_of_args > 0 ) + { + char buffer[30]; + + // x = x1 + buffer[0] = 'x'; + buffer[1] = 0; + local_variables.insert( std::make_pair(buffer, stack[sindex].value) ); + + for(int i=0 ; i*(i->second))(sindex, amount_of_args, stack[sindex-1].value); + calculated = true; +} + + + + + +/*! + inserting a function to the functions' table + + function_name - name of the function + pf - pointer to the function (to the wrapper) +*/ +void InsertFunctionToTable(const char * function_name, pfunction pf) +{ + std::string str; + Misc::AssignString(str, function_name); + + functions_table.insert( std::make_pair(str, pf) ); +} + + + +/*! + inserting a function to the variables' table + (this function returns value of variable) + + variable_name - name of the function + pf - pointer to the function +*/ +void InsertVariableToTable(const char * variable_name, pfunction_var pf) +{ + std::string str; + Misc::AssignString(str, variable_name); + + variables_table.insert( std::make_pair(str, pf) ); +} + + +/*! + this method creates the table of functions +*/ +void CreateFunctionsTable() +{ + InsertFunctionToTable("gamma", &Parser::Gamma); + InsertFunctionToTable("factorial", &Parser::Factorial); + InsertFunctionToTable("abs", &Parser::Abs); + InsertFunctionToTable("sin", &Parser::Sin); + InsertFunctionToTable("cos", &Parser::Cos); + InsertFunctionToTable("tan", &Parser::Tan); + InsertFunctionToTable("tg", &Parser::Tan); + InsertFunctionToTable("cot", &Parser::Cot); + InsertFunctionToTable("ctg", &Parser::Cot); + InsertFunctionToTable("int", &Parser::Int); + InsertFunctionToTable("round", &Parser::Round); + InsertFunctionToTable("ln", &Parser::Ln); + InsertFunctionToTable("log", &Parser::Log); + InsertFunctionToTable("exp", &Parser::Exp); + InsertFunctionToTable("max", &Parser::Max); + InsertFunctionToTable("min", &Parser::Min); + InsertFunctionToTable("asin", &Parser::ASin); + InsertFunctionToTable("acos", &Parser::ACos); + InsertFunctionToTable("atan", &Parser::ATan); + InsertFunctionToTable("atg", &Parser::ATan); + InsertFunctionToTable("acot", &Parser::ACot); + InsertFunctionToTable("actg", &Parser::ACot); + InsertFunctionToTable("sgn", &Parser::Sgn); + InsertFunctionToTable("mod", &Parser::Mod); + InsertFunctionToTable("if", &Parser::If); + InsertFunctionToTable("or", &Parser::Or); + InsertFunctionToTable("and", &Parser::And); + InsertFunctionToTable("not", &Parser::Not); + InsertFunctionToTable("degtorad", &Parser::DegToRad); + InsertFunctionToTable("radtodeg", &Parser::RadToDeg); + InsertFunctionToTable("degtodeg", &Parser::DegToDeg); + InsertFunctionToTable("gradtorad", &Parser::GradToRad); + InsertFunctionToTable("radtograd", &Parser::RadToGrad); + InsertFunctionToTable("degtograd", &Parser::DegToGrad); + InsertFunctionToTable("gradtodeg", &Parser::GradToDeg); + InsertFunctionToTable("ceil", &Parser::Ceil); + InsertFunctionToTable("floor", &Parser::Floor); + InsertFunctionToTable("sqrt", &Parser::Sqrt); + InsertFunctionToTable("sinh", &Parser::Sinh); + InsertFunctionToTable("cosh", &Parser::Cosh); + InsertFunctionToTable("tanh", &Parser::Tanh); + InsertFunctionToTable("tgh", &Parser::Tanh); + InsertFunctionToTable("coth", &Parser::Coth); + InsertFunctionToTable("ctgh", &Parser::Coth); + InsertFunctionToTable("root", &Parser::Root); + InsertFunctionToTable("asinh", &Parser::ASinh); + InsertFunctionToTable("acosh", &Parser::ACosh); + InsertFunctionToTable("atanh", &Parser::ATanh); + InsertFunctionToTable("atgh", &Parser::ATanh); + InsertFunctionToTable("acoth", &Parser::ACoth); + InsertFunctionToTable("actgh", &Parser::ACoth); + InsertFunctionToTable("bitand", &Parser::BitAnd); + InsertFunctionToTable("bitor", &Parser::BitOr); + InsertFunctionToTable("bitxor", &Parser::BitXor); + InsertFunctionToTable("band", &Parser::BitAnd); + InsertFunctionToTable("bor", &Parser::BitOr); + InsertFunctionToTable("bxor", &Parser::BitXor); + InsertFunctionToTable("sum", &Parser::Sum); + InsertFunctionToTable("avg", &Parser::Avg); + InsertFunctionToTable("frac", &Parser::Frac); +} + + +/*! + this method creates the table of variables +*/ +void CreateVariablesTable() +{ + InsertVariableToTable("pi", &ValueType::SetPi); + InsertVariableToTable("e", &ValueType::SetE); +} + + +/*! + converting from a big letter to a small one +*/ +int ToLowerCase(int c) +{ + if( c>='A' && c<='Z' ) + return c - 'A' + 'a'; + +return c; +} + + +/*! + this method read the name of a variable or a function + + 'result' will be the name of a variable or a function + function return 'false' if this name is the name of a variable + or function return 'true' if this name is the name of a function + + what should be returned is tested just by a '(' character that means if there's + a '(' character after a name that function returns 'true' +*/ +bool ReadName(std::string & result) +{ +int character; + + + result.erase(); + character = *pstring; + + /* + the first letter must be from range 'a' - 'z' or 'A' - 'Z' + */ + if( ! (( character>='a' && character<='z' ) || ( character>='A' && character<='Z' )) ) + Error( err_unknown_character ); + + + do + { + result += static_cast( character ); + character = * ++pstring; + } + while( (character>='a' && character<='z') || + (character>='A' && character<='Z') || + (character>='0' && character<='9') || + character=='_' ); + + + SkipWhiteCharacters(); + + + /* + if there's a character '(' that means this name is a name of a function + */ + if( *pstring == '(' ) + { + ++pstring; + return true; + } + + +return false; +} + + +/*! + we're checking whether the first character is '-' or '+' + if it is we'll return 'true' and if it is equally '-' we'll set the 'sign' member of 'result' +*/ +bool TestSign(Item & result) +{ + SkipWhiteCharacters(); + result.sign = false; + + if( *pstring == '-' || *pstring == '+' ) + { + if( *pstring == '-' ) + result.sign = true; + + ++pstring; + + return true; + } + +return false; +} + + +/*! + we're reading the name of a variable or a function + if is there a function we'll return 'true' +*/ +bool ReadVariableOrFunction(Item & result) +{ +std::string name; +bool is_it_name_of_function = ReadName(name); + + if( is_it_name_of_function ) + { + /* + we've read the name of a function + */ + result.function_name = name; + result.type = Item::first_bracket; + result.function = true; + } + else + { + /* + we've read the name of a variable and we're getting its value now + */ + result.value = GetValueOfVariable( name ); + } + +return is_it_name_of_function; +} + + + + +/*! + we're reading a numerical value directly from the string +*/ +void ReadValue(Item & result, int reading_base) +{ +const char * new_stack_pointer; +bool value_read; +Conv conv; + + conv.base = reading_base; + conv.comma = comma; + conv.comma2 = comma2; + conv.group = group; + + uint carry = result.value.FromString(pstring, conv, &new_stack_pointer, &value_read); + pstring = new_stack_pointer; + + if( carry ) + Error( err_overflow ); + + if( !value_read ) + Error( err_unknown_character ); +} + + +/*! + this method returns true if 'character' is a proper first digit for the value (or a comma -- can be first too) +*/ +bool ValueStarts(int character, int base) +{ + if( character == comma ) + return true; + + if( comma2!=0 && character==comma2 ) + return true; + + if( Misc::CharToDigit(character, base) != -1 ) + return true; + +return false; +} + + +/*! + we're reading the item + + return values: + 0 - all ok, the item is successfully read + 1 - the end of the string (the item is not read) + 2 - the final bracket ')' +*/ +int ReadValueVariableOrFunction(Item & result) +{ +bool it_was_sign = false; +int character; + + + if( TestSign(result) ) + // 'result.sign' was set as well + it_was_sign = true; + + SkipWhiteCharacters(); + character = ToLowerCase( *pstring ); + + + if( character == 0 ) + { + if( it_was_sign ) + // at the end of the string a character like '-' or '+' has left + Error( err_unexpected_end ); + + // there's the end of the string here + return 1; + } + else + if( character == '(' ) + { + // we've got a normal bracket (not a function) + result.type = Item::first_bracket; + result.function = false; + ++pstring; + + return 0; + } + else + if( character == ')' ) + { + // we've got a final bracket + // (in this place we can find a final bracket only when there are empty brackets + // without any values inside or with a sign '-' or '+' inside) + + if( it_was_sign ) + Error( err_unexpected_final_bracket ); + + result.type = Item::last_bracket; + + // we don't increment 'pstring', this final bracket will be read next by the + // 'ReadOperatorAndCheckFinalBracket(...)' method + + return 2; + } + else + if( character == '#' ) + { + ++pstring; + SkipWhiteCharacters(); + + // after '#' character we do not allow '-' or '+' (can be white characters) + if( ValueStarts(*pstring, 16) ) + ReadValue( result, 16 ); + else + Error( err_unknown_character ); + } + else + if( character == '&' ) + { + ++pstring; + SkipWhiteCharacters(); + + // after '&' character we do not allow '-' or '+' (can be white characters) + if( ValueStarts(*pstring, 2) ) + ReadValue( result, 2 ); + else + Error( err_unknown_character ); + } + else + if( ValueStarts(character, base) ) + { + ReadValue( result, base ); + } + else + if( character>='a' && character<='z' ) + { + if( ReadVariableOrFunction(result) ) + // we've read the name of a function + return 0; + } + else + Error( err_unknown_character ); + + + + /* + we've got a value in the 'result' + this value is from a variable or directly from the string + */ + result.type = Item::numerical_value; + + if( result.sign ) + { + result.value.ChangeSign(); + result.sign = false; + } + + +return 0; +} + + +void InsertOperatorToTable(const char * name, typename MatOperator::Type type) +{ + operators_table.insert( std::make_pair(std::string(name), type) ); +} + + +/*! + this method creates the table of operators +*/ +void CreateMathematicalOperatorsTable() +{ + InsertOperatorToTable("||", MatOperator::lor); + InsertOperatorToTable("&&", MatOperator::land); + InsertOperatorToTable("!=", MatOperator::neq); + InsertOperatorToTable("==", MatOperator::eq); + InsertOperatorToTable(">=", MatOperator::get); + InsertOperatorToTable("<=", MatOperator::let); + InsertOperatorToTable(">", MatOperator::gt); + InsertOperatorToTable("<", MatOperator::lt); + InsertOperatorToTable("-", MatOperator::sub); + InsertOperatorToTable("+", MatOperator::add); + InsertOperatorToTable("/", MatOperator::div); + InsertOperatorToTable("*", MatOperator::mul); + InsertOperatorToTable("^", MatOperator::pow); +} + + +/*! + returns true if 'str2' is the substring of str1 + + e.g. + true when str1="test" and str2="te" +*/ +bool IsSubstring(const std::string & str1, const std::string & str2) +{ + if( str2.length() > str1.length() ) + return false; + + for(typename std::string::size_type i=0 ; ifirst, oper) ) + { + oper.erase( --oper.end() ); // we've got mininum one element + + if( iter_old != operators_table.end() && iter_old->first == oper ) + { + result.type = Item::mat_operator; + result.moperator.SetType( iter_old->second ); + break; + } + + Error( err_unknown_operator ); + } + + iter_old = iter_new; + } +} + + +/*! + this method makes a calculation for the percentage operator + e.g. + 1000-50% = 1000-(1000*0,5) = 500 +*/ +void OperatorPercentage() +{ + if( stack_index < 3 || + stack[stack_index-1].type != Item::numerical_value || + stack[stack_index-2].type != Item::mat_operator || + stack[stack_index-3].type != Item::numerical_value ) + Error(err_percent_from); + + ++pstring; + SkipWhiteCharacters(); + + uint c = 0; + c += stack[stack_index-1].value.Div(100); + c += stack[stack_index-1].value.Mul(stack[stack_index-3].value); + + if( c ) + Error(err_overflow); +} + + +/*! + this method reads a mathematic operators + or the final bracket or the semicolon operator + + return values: + 0 - ok + 1 - the string is finished +*/ +int ReadOperator(Item & result) +{ + SkipWhiteCharacters(); + + if( *pstring == '%' ) + OperatorPercentage(); + + + if( *pstring == 0 ) + return 1; + else + if( *pstring == ')' ) + { + result.type = Item::last_bracket; + ++pstring; + } + else + if( *pstring == ';' || (param_sep!=0 && *pstring==param_sep) ) + { + result.type = Item::semicolon; + ++pstring; + } + else + if( (*pstring>='a' && *pstring<='z') || (*pstring>='A' && *pstring<='Z') ) + { + // short mul (without any operators) + + result.type = Item::mat_operator; + result.moperator.SetType( MatOperator::shortmul ); + } + else + ReadMathematicalOperator(result); + +return 0; +} + + + +/*! + this method is making the standard mathematic operation like '-' '+' '*' '/' and '^' + + the operation is made between 'value1' and 'value2' + the result of this operation is stored in the 'value1' +*/ +void MakeStandardMathematicOperation(ValueType & value1, typename MatOperator::Type mat_operator, + const ValueType & value2) +{ +uint res; + + calculated = true; + + switch( mat_operator ) + { + case MatOperator::land: + (!value1.IsZero() && !value2.IsZero()) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::lor: + (!value1.IsZero() || !value2.IsZero()) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::eq: + (value1 == value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::neq: + (value1 != value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::lt: + (value1 < value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::gt: + (value1 > value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::let: + (value1 <= value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::get: + (value1 >= value2) ? value1.SetOne() : value1.SetZero(); + break; + + case MatOperator::sub: + if( value1.Sub(value2) ) Error( err_overflow ); + break; + + case MatOperator::add: + if( value1.Add(value2) ) Error( err_overflow ); + break; + + case MatOperator::mul: + case MatOperator::shortmul: + if( value1.Mul(value2) ) Error( err_overflow ); + break; + + case MatOperator::div: + if( value2.IsZero() ) Error( err_division_by_zero ); + if( value1.Div(value2) ) Error( err_overflow ); + break; + + case MatOperator::pow: + res = value1.Pow( value2 ); + + if( res == 1 ) Error( err_overflow ); + else + if( res == 2 ) Error( err_improper_argument ); + + break; + + default: + /* + on the stack left an unknown operator but we had to recognize its before + that means there's an error in our algorithm + */ + Error( err_internal_error ); + } +} + + + + +/*! + this method is trying to roll the stack up with the operator's priority + + for example if there are: + "1 - 2 +" + we can subtract "1-2" and the result store on the place where is '1' and copy the last + operator '+', that means there'll be '-1+' on our stack + + but if there are: + "1 - 2 *" + we can't roll the stack up because the operator '*' has greater priority than '-' +*/ +void TryRollingUpStackWithOperatorPriority() +{ + while( stack_index>=4 && + stack[stack_index-4].type == Item::numerical_value && + stack[stack_index-3].type == Item::mat_operator && + stack[stack_index-2].type == Item::numerical_value && + stack[stack_index-1].type == Item::mat_operator && + ( + ( + // the first operator has greater priority + stack[stack_index-3].moperator.GetPriority() > stack[stack_index-1].moperator.GetPriority() + ) || + ( + // or both operators have the same priority and the first operator is not right associative + stack[stack_index-3].moperator.GetPriority() == stack[stack_index-1].moperator.GetPriority() && + stack[stack_index-3].moperator.GetAssoc() == MatOperator::non_right + ) + ) + ) + { + MakeStandardMathematicOperation(stack[stack_index-4].value, + stack[stack_index-3].moperator.GetType(), + stack[stack_index-2].value); + + + /* + copying the last operator and setting the stack pointer to the correct value + */ + stack[stack_index-3] = stack[stack_index-1]; + stack_index -= 2; + } +} + + +/*! + this method is trying to roll the stack up without testing any operators + + for example if there are: + "1 - 2" + there'll be "-1" on our stack +*/ +void TryRollingUpStack() +{ + while( stack_index >= 3 && + stack[stack_index-3].type == Item::numerical_value && + stack[stack_index-2].type == Item::mat_operator && + stack[stack_index-1].type == Item::numerical_value ) + { + MakeStandardMathematicOperation( stack[stack_index-3].value, + stack[stack_index-2].moperator.GetType(), + stack[stack_index-1].value ); + + stack_index -= 2; + } +} + + +/*! + this method is reading a value or a variable or a function + (the normal first bracket as well) and push it into the stack +*/ +int ReadValueVariableOrFunctionAndPushItIntoStack(Item & temp) +{ +int code = ReadValueVariableOrFunction( temp ); + + if( code == 0 ) + { + if( stack_index < stack.size() ) + stack[stack_index] = temp; + else + stack.push_back( temp ); + + ++stack_index; + } + + if( code == 2 ) + // there was a final bracket, we didn't push it into the stack + // (it'll be read by the 'ReadOperatorAndCheckFinalBracket' method next) + code = 0; + + +return code; +} + + + +/*! + this method calculate how many parameters there are on the stack + and the index of the first parameter + + if there aren't any parameters on the stack this method returns + 'size' equals zero and 'index' pointing after the first bracket + (on non-existend element) +*/ +void HowManyParameters(int & size, int & index) +{ + size = 0; + index = stack_index; + + if( index == 0 ) + // we haven't put a first bracket on the stack + Error( err_unexpected_final_bracket ); + + + if( stack[index-1].type == Item::first_bracket ) + // empty brackets + return; + + for( --index ; index>=1 ; index-=2 ) + { + if( stack[index].type != Item::numerical_value ) + { + /* + this element must be 'numerical_value', if not that means + there's an error in our algorithm + */ + Error( err_internal_error ); + } + + ++size; + + if( stack[index-1].type != Item::semicolon ) + break; + } + + if( index<1 || stack[index-1].type != Item::first_bracket ) + { + /* + we haven't put a first bracket on the stack + */ + Error( err_unexpected_final_bracket ); + } +} + + +/*! + this method is being called when the final bracket ')' is being found + + this method's rolling the stack up, counting how many parameters there are + on the stack and if there was a function it's calling the function +*/ +void RollingUpFinalBracket() +{ +int amount_of_parameters; +int index; + + + if( stack_index<1 || + (stack[stack_index-1].type != Item::numerical_value && + stack[stack_index-1].type != Item::first_bracket) + ) + Error( err_unexpected_final_bracket ); + + + TryRollingUpStack(); + HowManyParameters(amount_of_parameters, index); + + // 'index' will be greater than zero + // 'amount_of_parameters' can be zero + + + if( amount_of_parameters==0 && !stack[index-1].function ) + Error( err_unexpected_final_bracket ); + + + bool was_sign = stack[index-1].sign; + + + if( stack[index-1].function ) + { + // the result of a function will be on 'stack[index-1]' + // and then at the end we'll set the correct type (numerical value) of this element + CallFunction(stack[index-1].function_name, amount_of_parameters, index); + } + else + { + /* + there was a normal bracket (not a funcion) + */ + if( amount_of_parameters != 1 ) + Error( err_unexpected_semicolon_operator ); + + + /* + in the place where is the bracket we put the result + */ + stack[index-1] = stack[index]; + } + + + /* + if there was a '-' character before the first bracket + we change the sign of the expression + */ + stack[index-1].sign = false; + + if( was_sign ) + stack[index-1].value.ChangeSign(); + + stack[index-1].type = Item::numerical_value; + + + /* + the pointer of the stack will be pointing on the next (non-existing now) element + */ + stack_index = index; +} + + +/*! + this method is putting the operator on the stack +*/ + +void PushOperatorIntoStack(Item & temp) +{ + if( stack_index < stack.size() ) + stack[stack_index] = temp; + else + stack.push_back( temp ); + + ++stack_index; +} + + + +/*! + this method is reading a operator and if it's a final bracket + it's calling RollingUpFinalBracket() and reading a operator again +*/ +int ReadOperatorAndCheckFinalBracket(Item & temp) +{ + do + { + if( ReadOperator(temp) == 1 ) + { + /* + the string is finished + */ + return 1; + } + + if( temp.type == Item::last_bracket ) + RollingUpFinalBracket(); + + } + while( temp.type == Item::last_bracket ); + +return 0; +} + + +/*! + we check wheter there are only numerical value's or 'semicolon' operators on the stack +*/ +void CheckIntegrityOfStack() +{ + for(unsigned int i=0 ; iWasStopSignal() ) + Error( err_interrupt ); + + result_code = ReadValueVariableOrFunctionAndPushItIntoStack( item ); + + if( result_code == 0 ) + { + if( item.type == Item::first_bracket ) + continue; + + result_code = ReadOperatorAndCheckFinalBracket( item ); + } + + + if( result_code==1 || item.type==Item::semicolon ) + { + /* + the string is finished or the 'semicolon' operator has appeared + */ + + if( stack_index == 0 ) + Error( err_nothing_has_read ); + + TryRollingUpStack(); + + if( result_code == 1 ) + { + CheckIntegrityOfStack(); + + return; + } + } + + + PushOperatorIntoStack( item ); + TryRollingUpStackWithOperatorPriority(); + } +} + +/*! + this method is called at the end of the parsing process + + on our stack we can have another value than 'numerical_values' for example + when someone use the operator ';' in the global scope or there was an error during + parsing and the parser hasn't finished its job + + if there was an error the stack is cleaned up now + otherwise we resize stack and leave on it only 'numerical_value' items +*/ +void NormalizeStack() +{ + if( error!=err_ok || stack_index==0 ) + { + stack.clear(); + return; + } + + + /* + 'stack_index' tell us how many elements there are on the stack, + we must resize the stack now because 'stack_index' is using only for parsing + and stack has more (or equal) elements than value of 'stack_index' + */ + stack.resize( stack_index ); + + for(uint i=stack_index-1 ; i!=uint(-1) ; --i) + { + if( stack[i].type != Item::numerical_value ) + stack.erase( stack.begin() + i ); + } +} + + +public: + + +/*! + the default constructor +*/ +Parser(): default_stack_size(100) +{ + pstop_calculating = 0; + puser_variables = 0; + puser_functions = 0; + pfunction_local_variables = 0; + base = 10; + deg_rad_grad = 1; + error = err_ok; + group = 0; + comma = '.'; + comma2 = ','; + param_sep = 0; + + CreateFunctionsTable(); + CreateVariablesTable(); + CreateMathematicalOperatorsTable(); +} + + +/*! + the assignment operator +*/ +Parser & operator=(const Parser & p) +{ + pstop_calculating = p.pstop_calculating; + puser_variables = p.puser_variables; + puser_functions = p.puser_functions; + pfunction_local_variables = 0; + base = p.base; + deg_rad_grad = p.deg_rad_grad; + error = p.error; + group = p.group; + comma = p.comma; + comma2 = p.comma2; + param_sep = p.param_sep; + + /* + we don't have to call 'CreateFunctionsTable()' etc. + we can only copy these tables + */ + functions_table = p.functions_table; + variables_table = p.variables_table; + operators_table = p.operators_table; + + visited_variables = p.visited_variables; + visited_functions = p.visited_functions; + +return *this; +} + + +/*! + the copying constructor +*/ +Parser(const Parser & p): default_stack_size(p.default_stack_size) +{ + operator=(p); +} + + +/*! + the new base of mathematic system + default is 10 +*/ +void SetBase(int b) +{ + if( b>=2 && b<=16 ) + base = b; +} + + +/*! + the unit of angles used in: sin,cos,tan,cot,asin,acos,atan,acot + 0 - deg + 1 - rad (default) + 2 - grad +*/ +void SetDegRadGrad(int angle) +{ + if( angle >= 0 || angle <= 2 ) + deg_rad_grad = angle; +} + +/*! + this method sets a pointer to the object which tell us whether we should stop + calculations +*/ +void SetStopObject(const volatile StopCalculating * ps) +{ + pstop_calculating = ps; +} + + +/*! + this method sets the new table of user-defined variables + if you don't want any other variables just put zero value into the 'puser_variables' variable + + (you can have only one table at the same time) +*/ +void SetVariables(const Objects * pv) +{ + puser_variables = pv; +} + + +/*! + this method sets the new table of user-defined functions + if you don't want any other functions just put zero value into the 'puser_functions' variable + + (you can have only one table at the same time) +*/ +void SetFunctions(const Objects * pf) +{ + puser_functions = pf; +} + + +/*! + setting the group character + default zero (not used) +*/ +void SetGroup(int g) +{ + group = g; +} + + +/*! + setting the main comma operator and the additional comma operator + the additional operator can be zero (which means it is not used) + default are: '.' and ',' +*/ +void SetComma(int c, int c2 = 0) +{ + comma = c; + comma2 = c2; +} + + +/*! + setting an additional character which is used as a parameters separator + the main parameters separator is a semicolon (is used always) + + this character is used also as a global separator +*/ +void SetParamSep(int s) +{ + param_sep = s; +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const char * str) +{ + stack_index = 0; + pstring = str; + error = err_ok; + calculated = false; + + stack.resize( default_stack_size ); + + try + { + Parse(); + } + catch(ErrorCode c) + { + error = c; + calculated = false; + } + + NormalizeStack(); + +return error; +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const std::string & str) +{ + return Parse(str.c_str()); +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const wchar_t * str) +{ + Misc::AssignString(wide_to_ansi, str); + +return Parse(wide_to_ansi.c_str()); +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const std::wstring & str) +{ + return Parse(str.c_str()); +} + + +/*! + this method returns true is something was calculated + (at least one mathematical operator was used or a function or variable) + e.g. true if the string to Parse() looked like this: + "1+1" + "2*3" + "sin(5)" + + if the string was e.g. "678" the result is false +*/ +bool Calculated() +{ + return calculated; +} + + +}; + + + +} // namespace + + +#endif diff --git a/ttmath/ttmaththreads.h b/ttmath/ttmaththreads.h new file mode 100644 index 0000000..586227f --- /dev/null +++ b/ttmath/ttmaththreads.h @@ -0,0 +1,250 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#ifndef headerfilettmaththreads +#define headerfilettmaththreads + +#include "ttmathtypes.h" + +#ifdef TTMATH_WIN32_THREADS +#include +#include +#endif + +#ifdef TTMATH_POSIX_THREADS +#include +#endif + + + +/*! + \file ttmaththreads.h + \brief Some objects used in multithreads environment +*/ + + +/* + this is a simple skeleton of a program in multithreads environment: + + #define TTMATH_MULTITHREADS + #include + + TTMATH_MULTITHREADS_HELPER + + int main() + { + [...] + } + + make sure that macro TTMATH_MULTITHREADS is defined and (somewhere in *.cpp file) + use TTMATH_MULTITHREADS_HELPER macro (outside of any classes/functions/namespaces scope) +*/ + + +namespace ttmath +{ + + +#ifdef TTMATH_WIN32_THREADS + + /* + we use win32 threads + */ + + + /*! + in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro + somewhere in *.cpp file + + (at the moment in win32 this macro does nothing) + */ + #define TTMATH_MULTITHREADS_HELPER + + + /*! + objects of this class are used to synchronize + */ + class ThreadLock + { + HANDLE mutex_handle; + + + void CreateName(char * buffer) const + { + #ifdef _MSC_VER + #pragma warning (disable : 4996) + // warning C4996: 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead. + #endif + + sprintf(buffer, "TTMATH_LOCK_%ul", (unsigned long)GetCurrentProcessId()); + + #ifdef _MSC_VER + #pragma warning (default : 4996) + #endif + } + + + public: + + bool Lock() + { + char buffer[50]; + + CreateName(buffer); + mutex_handle = CreateMutexA(0, false, buffer); + + if( mutex_handle == 0 ) + return false; + + WaitForSingleObject(mutex_handle, INFINITE); + + return true; + } + + + ThreadLock() + { + mutex_handle = 0; + } + + + ~ThreadLock() + { + if( mutex_handle != 0 ) + { + ReleaseMutex(mutex_handle); + CloseHandle(mutex_handle); + } + } + }; + +#endif // #ifdef TTMATH_WIN32_THREADS + + + + + +#ifdef TTMATH_POSIX_THREADS + + /* + we use posix threads + */ + + + /*! + in multithreads environment you should use TTMATH_MULTITHREADS_HELPER macro + somewhere in *.cpp file + (this macro defines a pthread_mutex_t object used by TTMath library) + */ + #define TTMATH_MULTITHREADS_HELPER \ + namespace ttmath \ + { \ + pthread_mutex_t ttmath_mutex = PTHREAD_MUTEX_INITIALIZER; \ + } + + + /*! + ttmath_mutex will be defined by TTMATH_MULTITHREADS_HELPER macro + */ + extern pthread_mutex_t ttmath_mutex; + + + /*! + objects of this class are used to synchronize + */ + class ThreadLock + { + public: + + bool Lock() + { + if( pthread_mutex_lock(&ttmath_mutex) != 0 ) + return false; + + return true; + } + + + ~ThreadLock() + { + pthread_mutex_unlock(&ttmath_mutex); + } + }; + +#endif // #ifdef TTMATH_POSIX_THREADS + + + + +#if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) + + /*! + we don't use win32 and pthreads + */ + + /*! + */ + #define TTMATH_MULTITHREADS_HELPER + + + /*! + objects of this class are used to synchronize + actually we don't synchronize, the method Lock() returns always 'false' + */ + class ThreadLock + { + public: + + bool Lock() + { + return false; + } + }; + + +#endif // #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) + + + + + +} // namespace + +#endif + diff --git a/ttmath/ttmathtypes.h b/ttmath/ttmathtypes.h new file mode 100644 index 0000000..f3236ea --- /dev/null +++ b/ttmath/ttmathtypes.h @@ -0,0 +1,646 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2010, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef headerfilettmathtypes +#define headerfilettmathtypes + +/*! + \file ttmathtypes.h + \brief constants used in the library + + As our library is written in header files (templates) we cannot use + constants like 'const int' etc. because we should have some source files + *.cpp to define this variables. Only what we can have are constants + defined by #define preprocessor macros. + + All macros are preceded by TTMATH_ prefix +*/ + + +#include +#include +#include + +/*! + the version of the library + + TTMATH_PRERELEASE_VER is either zero or one + if zero that means this is the release version of the library +*/ +#define TTMATH_MAJOR_VER 0 +#define TTMATH_MINOR_VER 9 +#define TTMATH_REVISION_VER 1 +#define TTMATH_PRERELEASE_VER 0 + + +/*! + TTMATH_DEBUG + this macro enables further testing during writing your code + you don't have to define it in a release mode + + if this macro is set then macros TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT + are set as well and these macros can throw an exception if a condition in it + is not fulfilled (look at the definition of TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT) + + TTMATH_RELEASE + if you are confident that your code is perfect you can define TTMATH_RELEASE + macro for example by using -D option in gcc + gcc -DTTMATH_RELEASE -o myprogram myprogram.cpp + or by defining this macro in your code before using any header files of this library + + if TTMATH_RELEASE is not set then TTMATH_DEBUG is set automatically +*/ +#ifndef TTMATH_RELEASE + #define TTMATH_DEBUG +#endif + + + +namespace ttmath +{ + +#if !defined _M_X64 && !defined __x86_64__ + + /*! + we're using a 32bit platform + */ + #define TTMATH_PLATFORM32 + +#else + + /*! + we're using a 64bit platform + */ + #define TTMATH_PLATFORM64 + +#endif + + + +/*! + another compilers than MS VC or GCC by default use no asm version (TTMATH_NOASM) +*/ +#if !defined _MSC_VER && !defined __GNUC__ + #define TTMATH_NOASM +#endif + + + +#ifdef TTMATH_PLATFORM32 + + /*! + on 32bit platforms one word (uint, sint) will be equal 32bits + */ + typedef unsigned int uint; + typedef signed int sint; + + /*! + this type is twice bigger than uint + (64bit on a 32bit platforms) + + although C++ Standard - ANSI ISO IEC 14882:2003 doesn't define such a type (long long) + but it is defined in C99 and in upcoming C++0x /3.9.1 (2)/ and many compilers support it + + this type is used in UInt::MulTwoWords and UInt::DivTwoWords when macro TTMATH_NOASM is defined + but only on a 32bit platform + */ + #ifdef TTMATH_NOASM + typedef unsigned long long int ulint; + #endif + + /*! + how many bits there are in the uint type + */ + #define TTMATH_BITS_PER_UINT 32u + + /*! + the mask for the highest bit in the unsigned 32bit word (2^31) + */ + #define TTMATH_UINT_HIGHEST_BIT 2147483648u + + /*! + the max value of the unsigned 32bit word (2^32 - 1) + (all bits equal one) + */ + #define TTMATH_UINT_MAX_VALUE 4294967295u + + /*! + the number of words (32bit words on 32bit platform) + which are kept in built-in variables for a Big<> type + (these variables are defined in ttmathbig.h) + */ + #define TTMATH_BUILTIN_VARIABLES_SIZE 256u + + /*! + this macro returns the number of machine words + capable to hold min_bits bits + e.g. TTMATH_BITS(128) returns 4 + */ + #define TTMATH_BITS(min_bits) ((min_bits-1)/32 + 1) + +#else + + /*! + on 64bit platforms one word (uint, sint) will be equal 64bits + */ + #ifdef _MSC_VER + /* in VC 'long' type has 32 bits, __int64 is VC extension */ + typedef unsigned __int64 uint; + typedef signed __int64 sint; + #else + typedef unsigned long uint; + typedef signed long sint; + #endif + + /*! + on 64bit platform we do not define ulint + sizeof(long long) is 8 (64bit) but we need 128bit + + on 64 bit platform (when there is defined TTMATH_NOASM macro) + methods UInt::MulTwoWords and UInt::DivTwoWords are using other algorithms than those on 32 bit + */ + //typedef unsigned long long int ulint; + + /*! + how many bits there are in the uint type + */ + #define TTMATH_BITS_PER_UINT 64ul + + /*! + the mask for the highest bit in the unsigned 64bit word (2^63) + */ + #define TTMATH_UINT_HIGHEST_BIT 9223372036854775808ul + + /*! + the max value of the unsigned 64bit word (2^64 - 1) + (all bits equal one) + */ + #define TTMATH_UINT_MAX_VALUE 18446744073709551615ul + + /*! + the number of words (64bit words on 64bit platforms) + which are kept in built-in variables for a Big<> type + (these variables are defined in ttmathbig.h) + */ + #define TTMATH_BUILTIN_VARIABLES_SIZE 128ul + + /*! + this macro returns the number of machine words + capable to hold min_bits bits + e.g. TTMATH_BITS(128) returns 2 + */ + #define TTMATH_BITS(min_bits) ((min_bits-1)/64 + 1) + +#endif +} + + +#if defined(TTMATH_MULTITHREADS) && !defined(TTMATH_MULTITHREADS_NOSYNC) + #if !defined(TTMATH_POSIX_THREADS) && !defined(TTMATH_WIN32_THREADS) + + #if defined(_WIN32) + #define TTMATH_WIN32_THREADS + #elif defined(unix) || defined(__unix__) || defined(__unix) + #define TTMATH_POSIX_THREADS + #endif + + #endif +#endif + + + +/*! + this variable defines how many iterations are performed + during some kind of calculating when we're making any long formulas + (for example Taylor series) + + it's used in ExpSurrounding0(...), LnSurrounding1(...), Sin0pi05(...), etc. + + note! there'll not be so many iterations, iterations are stopped when + there is no sense to continue calculating (for example when the result + still remains unchanged after adding next series and we know that the next + series are smaller than previous ones) +*/ +#define TTMATH_ARITHMETIC_MAX_LOOP 10000 + + + +/*! + this is a limit when calculating Karatsuba multiplication + if the size of a vector is smaller than TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE + the Karatsuba algorithm will use standard schoolbook multiplication +*/ +#ifdef TTMATH_DEBUG_LOG + // if TTMATH_DEBUG_LOG is defined then we should use the same size regardless of the compiler + #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 +#else + #ifdef __GNUC__ + #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 3 + #else + #define TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE 5 + #endif +#endif + + +/*! + this is a special value used when calculating the Gamma(x) function + if x is greater than this value then the Gamma(x) will be calculated using + some kind of series + + don't use smaller values than about 100 +*/ +#define TTMATH_GAMMA_BOUNDARY 2000 + + + + + +namespace ttmath +{ + + /*! + lib type codes: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + enum LibTypeCode + { + asm_vc_32 = 0, + asm_gcc_32, + asm_vc_64, + asm_gcc_64, + no_asm_32, + no_asm_64 + }; + + + /*! + error codes + */ + enum ErrorCode + { + err_ok = 0, + err_nothing_has_read, + err_unknown_character, + err_unexpected_final_bracket, + err_stack_not_clear, + err_unknown_variable, + err_division_by_zero, + err_interrupt, + err_overflow, + err_unknown_function, + err_unknown_operator, + err_unexpected_semicolon_operator, + err_improper_amount_of_arguments, + err_improper_argument, + err_unexpected_end, + err_internal_error, + err_incorrect_name, + err_incorrect_value, + err_variable_exists, + err_variable_loop, + err_functions_loop, + err_must_be_only_one_value, + err_object_exists, + err_unknown_object, + err_still_calculating, + err_in_short_form_used_function, + err_percent_from + }; + + + /*! + this struct is used when converting to/from a string + /temporarily only in Big::ToString() and Big::FromString()/ + */ + struct Conv + { + /*! + base (radix) on which the value will be shown (or read) + default: 10 + */ + uint base; + + + /*! + used only in Big::ToString() + if true the value will be always shown in the scientific mode, e.g: 123e+30 + default: false + */ + bool scient; + + + /*! + used only in Big::ToString() + if scient is false then the value will be print in the scientific mode + only if the exponent is greater than scien_from + default: 15 + */ + sint scient_from; + + + /*! + if 'base_round' is true and 'base' is different from 2, 4, 8, or 16 + and the result value is not an integer then we make an additional rounding + (after converting the last digit from the result is skipped) + default: true + + e.g. + Conv c; + c.base_round = false; + Big<1, 1> a = "0.1"; // decimal input + std::cout << a.ToString(c) << std::endl; // the result is: 0.099999999 + */ + bool base_round; + + + /*! + used only in Big::ToString() + tells how many digits after comma are possible + default: -1 which means all digits are printed + + set it to zero if you want integer value only + + for example when the value is: + 12.345678 and 'round' is 4 + then the result will be + 12.3457 (the last digit was rounded) + */ + sint round; + + + /*! + if true that not mattered digits in the mantissa will be cut off + (zero characters at the end -- after the comma operator) + e.g. 1234,78000 will be: 1234,78 + default: true + */ + bool trim_zeroes; + + + /*! + the main comma operator (used when reading and writing) + default is a dot '.' + */ + uint comma; + + + /*! + additional comma operator (used only when reading) + if you don't want it just set it to zero + default is a comma ',' + + this allowes you to convert from a value: + 123.45 as well as from 123,45 + */ + uint comma2; + + + /*! + it sets the character which is used for grouping + if group=' ' then: 1234,56789 will be printed as: 1 234,567 89 + + if you don't want grouping just set it to zero (which is default) + */ + uint group; + + + /*! + */ + uint group_exp; // not implemented yet + + + + + Conv() + { + // default values + base = 10; + scient = false; + scient_from = 15; + base_round = true; + round = -1; + trim_zeroes = true; + comma = '.'; + comma2 = ','; + group = 0; + group_exp = 0; + } + }; + + + + /*! + this simple class can be used in multithreading model + (you can write your own class derived from this one) + + for example: in some functions like Factorial() + /at the moment only Factorial/ you can give a pointer to + the 'stop object', if the method WasStopSignal() of this + object returns true that means we should break the calculating + and return + */ + class StopCalculating + { + public: + virtual bool WasStopSignal() const volatile { return false; } + virtual ~StopCalculating(){} + }; + + + /*! + a small class which is useful when compiling with gcc + + object of this type holds the name and the line of a file + in which the macro TTMATH_ASSERT or TTMATH_REFERENCE_ASSERT was used + */ + class ExceptionInfo + { + const char * file; + int line; + + public: + ExceptionInfo() : file(0), line(0) {} + ExceptionInfo(const char * f, int l) : file(f), line(l) {} + + std::string Where() const + { + if( !file ) + return "unknown"; + + std::ostringstream result; + result << file << ":" << line; + + return result.str(); + } + }; + + + /*! + A small class used for reporting 'reference' errors + + In the library is used macro TTMATH_REFERENCE_ASSERT which + can throw an exception of this type + + If you compile with gcc you can get a small benefit + from using method Where() (it returns std::string) with + the name and the line of a file where the macro TTMATH_REFERENCE_ASSERT + was used) + + What is the 'reference' error? + Some kind of methods use a reference as their argument to another object, + and the another object not always can be the same which is calling, e.g. + Big<1,2> foo(10); + foo.Mul(foo); // this is incorrect + above method Mul is making something more with 'this' object and + 'this' cannot be passed as the argument because the result will be undefined + + macro TTMATH_REFERENCE_ASSERT helps us to solve the above problem + + note! some methods can use 'this' object as the argument + for example this code is correct: + UInt<2> foo(10); + foo.Add(foo); + but there are only few methods which can do that + */ + class ReferenceError : public std::logic_error, public ExceptionInfo + { + public: + + ReferenceError() : std::logic_error("reference error") + { + } + + ReferenceError(const char * f, int l) : + std::logic_error("reference error"), ExceptionInfo(f,l) + { + } + + std::string Where() const + { + return ExceptionInfo::Where(); + } + }; + + + /*! + a small class used for reporting errors + + in the library is used macro TTMATH_ASSERT which + (if the condition in it is false) throw an exception + of this type + + if you compile with gcc you can get a small benefit + from using method Where() (it returns std::string) with + the name and the line of a file where the macro TTMATH_ASSERT + was used) + */ + class RuntimeError : public std::runtime_error, public ExceptionInfo + { + public: + + RuntimeError() : std::runtime_error("internal error") + { + } + + RuntimeError(const char * f, int l) : + std::runtime_error("internal error"), ExceptionInfo(f,l) + { + } + + std::string Where() const + { + return ExceptionInfo::Where(); + } + }; + + + + /*! + look at the description of macros TTMATH_RELEASE and TTMATH_DEBUG + */ + #ifdef TTMATH_DEBUG + + #if defined(__FILE__) && defined(__LINE__) + + #define TTMATH_REFERENCE_ASSERT(expression) \ + if( &(expression) == this ) throw ttmath::ReferenceError(__FILE__, __LINE__); + + #define TTMATH_ASSERT(expression) \ + if( !(expression) ) throw ttmath::RuntimeError(__FILE__, __LINE__); + + #else + + #define TTMATH_REFERENCE_ASSERT(expression) \ + if( &(expression) == this ) throw ReferenceError(); + + #define TTMATH_ASSERT(expression) \ + if( !(expression) ) throw RuntimeError(); + #endif + + #else + #define TTMATH_REFERENCE_ASSERT(expression) + #define TTMATH_ASSERT(expression) + #endif + + + + #ifdef TTMATH_DEBUG_LOG + #define TTMATH_LOG(msg) PrintLog(msg, std::cout); + #define TTMATH_LOGC(msg, carry) PrintLog(msg, carry, std::cout); + #define TTMATH_VECTOR_LOG(msg, vector, len) PrintVectorLog(msg, std::cout, vector, len); + #define TTMATH_VECTOR_LOGC(msg, carry, vector, len) PrintVectorLog(msg, carry, std::cout, vector, len); + #else + #define TTMATH_LOG(msg) + #define TTMATH_LOGC(msg, carry) + #define TTMATH_VECTOR_LOG(msg, vector, len) + #define TTMATH_VECTOR_LOGC(msg, carry, vector, len) + #endif + + + + +} // namespace + + +#endif + diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h new file mode 100644 index 0000000..5f3e3e2 --- /dev/null +++ b/ttmath/ttmathuint.h @@ -0,0 +1,3520 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#ifndef headerfilettmathuint +#define headerfilettmathuint + + +/*! + \file ttmathuint.h + \brief template class UInt +*/ + +#include +#include + + +#include "ttmathtypes.h" +#include "ttmathmisc.h" + + + +/*! + \brief a namespace for the TTMath library +*/ +namespace ttmath +{ + +/*! + \brief UInt implements a big integer value without a sign + + value_size - how many bytes specify our value + on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits + on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits + value_size = 1,2,3,4,5,6.... +*/ +template +class UInt +{ +public: + + /*! + buffer for the integer value + table[0] - the lowest word of the value + */ + uint table[value_size]; + + + + /*! + some methods used for debugging purposes + */ + + + /*! + this method is only for debugging purposes or when we want to make + a table of a variable (constant) in ttmathbig.h + + it prints the table in a nice form of several columns + */ + template + void PrintTable(ostream_type & output) const + { + // how many columns there'll be + const int columns = 8; + + int c = 1; + for(int i=value_size-1 ; i>=0 ; --i) + { + output << "0x" << std::setfill('0'); + + #ifdef TTMATH_PLATFORM32 + output << std::setw(8); + #else + output << std::setw(16); + #endif + + output << std::hex << table[i]; + + if( i>0 ) + { + output << ", "; + + if( ++c > columns ) + { + output << std::endl; + c = 1; + } + } + } + + output << std::dec << std::endl; + } + + + /*! + this method is used when macro TTMATH_DEBUG_LOG is defined + */ + template + static void PrintVectorLog(const char_type * msg, ostream_type & output, const uint * vector, uint vector_len) + { + output << msg << std::endl; + + for(uint i=0 ; i + static void PrintVectorLog(const char_type * msg, uint carry, ostream_type & output, const uint * vector, uint vector_len) + { + PrintVectorLog(msg, output, vector, vector_len); + output << " carry: " << carry << std::endl; + } + + + /*! + this method is used when macro TTMATH_DEBUG_LOG is defined + */ + template + void PrintLog(const char_type * msg, ostream_type & output) const + { + PrintVectorLog(msg, output, table, value_size); + } + + + /*! + this method is used when macro TTMATH_DEBUG_LOG is defined + */ + template + void PrintLog(const char_type * msg, uint carry, ostream_type & output) const + { + PrintVectorLog(msg, output, table, value_size); + output << " carry: " << carry << std::endl; + } + + + /*! + this method returns the size of the table + */ + uint Size() const + { + return value_size; + } + + + /*! + this method sets zero + */ + void SetZero() + { + // in the future here can be 'memset' + + for(uint i=0 ; i=0 && temp_table_index=0 ; --i) + table[i] = 0; + + + TTMATH_LOG("UInt::SetFromTable") + } + +#endif + + +#ifdef TTMATH_PLATFORM64 + /*! + this method copies the value stored in an another table + (warning: first values in temp_table are the highest words -- it's different + from our table) + + ***this method is created only on a 64bit platform*** + + we copy as many words as it is possible + + if temp_table_len is bigger than value_size we'll try to round + the lowest word from table depending on the last not used bit in temp_table + (this rounding isn't a perfect rounding -- look at the description below) + + and if temp_table_len is smaller than value_size we'll clear the rest words + in the table + + warning: we're using 'temp_table' as a pointer at 32bit words + */ + void SetFromTable(const unsigned int * temp_table, uint temp_table_len) + { + uint temp_table_index = 0; + sint i; // 'i' with a sign + + for(i=value_size-1 ; i>=0 && temp_table_index= 0 ; --i) + table[i] = 0; + + TTMATH_LOG("UInt::SetFromTable") + } + +#endif + + + + + + /*! + * + * basic mathematic functions + * + */ + + + + + /*! + this method adds one to the existing value + */ + uint AddOne() + { + return AddInt(1); + } + + + /*! + this method subtracts one from the existing value + */ + uint SubOne() + { + return SubInt(1); + } + + +private: + + + /*! + an auxiliary method for moving bits into the left hand side + + this method moves only words + */ + void RclMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) + { + rest_bits = bits % TTMATH_BITS_PER_UINT; + uint all_words = bits / TTMATH_BITS_PER_UINT; + uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; + + + if( all_words >= value_size ) + { + if( all_words == value_size && rest_bits == 0 ) + last_c = table[0] & 1; + // else: last_c is default set to 0 + + // clearing + for(uint i = 0 ; i 0 ) + { + // 0 < all_words < value_size + + sint first, second; + last_c = table[value_size - all_words] & 1; // all_words is greater than 0 + + // copying the first part of the value + for(first = value_size-1, second=first-all_words ; second>=0 ; --first, --second) + table[first] = table[second]; + + // setting the rest to 'c' + for( ; first>=0 ; --first ) + table[first] = mask; + } + + TTMATH_LOG("UInt::RclMoveAllWords") + } + +public: + + /*! + moving all bits into the left side 'bits' times + return value <- this <- C + + bits is from a range of <0, man * TTMATH_BITS_PER_UINT> + or it can be even bigger then all bits will be set to 'c' + + the value c will be set into the lowest bits + and the method returns state of the last moved bit + */ + uint Rcl(uint bits, uint c=0) + { + uint last_c = 0; + uint rest_bits = bits; + + if( bits == 0 ) + return 0; + + if( bits >= TTMATH_BITS_PER_UINT ) + RclMoveAllWords(rest_bits, last_c, bits, c); + + if( rest_bits == 0 ) + { + TTMATH_LOG("UInt::Rcl") + return last_c; + } + + // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now + if( rest_bits == 1 ) + { + last_c = Rcl2_one(c); + } + else if( rest_bits == 2 ) + { + // performance tests showed that for rest_bits==2 it's better to use Rcl2_one twice instead of Rcl2(2,c) + Rcl2_one(c); + last_c = Rcl2_one(c); + } + else + { + last_c = Rcl2(rest_bits, c); + } + + TTMATH_LOGC("UInt::Rcl", last_c) + + return last_c; + } + +private: + + /*! + an auxiliary method for moving bits into the right hand side + + this method moves only words + */ + void RcrMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) + { + rest_bits = bits % TTMATH_BITS_PER_UINT; + uint all_words = bits / TTMATH_BITS_PER_UINT; + uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; + + + if( all_words >= value_size ) + { + if( all_words == value_size && rest_bits == 0 ) + last_c = (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; + // else: last_c is default set to 0 + + // clearing + for(uint i = 0 ; i 0 ) + { + // 0 < all_words < value_size + + uint first, second; + last_c = (table[all_words - 1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; // all_words is > 0 + + // copying the first part of the value + for(first=0, second=all_words ; second this -> return value + + bits is from a range of <0, man * TTMATH_BITS_PER_UINT> + or it can be even bigger then all bits will be set to 'c' + + the value c will be set into the highest bits + and the method returns state of the last moved bit + */ + uint Rcr(uint bits, uint c=0) + { + uint last_c = 0; + uint rest_bits = bits; + + if( bits == 0 ) + return 0; + + if( bits >= TTMATH_BITS_PER_UINT ) + RcrMoveAllWords(rest_bits, last_c, bits, c); + + if( rest_bits == 0 ) + { + TTMATH_LOG("UInt::Rcr") + return last_c; + } + + // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now + if( rest_bits == 1 ) + { + last_c = Rcr2_one(c); + } + else if( rest_bits == 2 ) + { + // performance tests showed that for rest_bits==2 it's better to use Rcr2_one twice instead of Rcr2(2,c) + Rcr2_one(c); + last_c = Rcr2_one(c); + } + else + { + last_c = Rcr2(rest_bits, c); + } + + TTMATH_LOGC("UInt::Rcr", last_c) + + return last_c; + } + + + /*! + this method moves all bits into the left side + (it returns value how many bits have been moved) + */ + uint CompensationToLeft() + { + uint moving = 0; + + // a - index a last word which is different from zero + sint a; + for(a=value_size-1 ; a>=0 && table[a]==0 ; --a); + + if( a < 0 ) + return moving; // all words in table have zero + + if( a != value_size-1 ) + { + moving += ( value_size-1 - a ) * TTMATH_BITS_PER_UINT; + + // moving all words + sint i; + for(i=value_size-1 ; a>=0 ; --i, --a) + table[i] = table[a]; + + // setting the rest word to zero + for(; i>=0 ; --i) + table[i] = 0; + } + + uint moving2 = FindLeadingBitInWord( table[value_size-1] ); + // moving2 is different from -1 because the value table[value_size-1] + // is not zero + + moving2 = TTMATH_BITS_PER_UINT - moving2 - 1; + Rcl(moving2); + + TTMATH_LOG("UInt::CompensationToLeft") + + return moving + moving2; + } + + + /*! + this method looks for the highest set bit + + result: + if 'this' is not zero: + return value - true + 'table_id' - the index of a word <0..value_size-1> + 'index' - the index of this set bit in the word <0..TTMATH_BITS_PER_UINT) + + if 'this' is zero: + return value - false + both 'table_id' and 'index' are zero + */ + bool FindLeadingBit(uint & table_id, uint & index) const + { + for(table_id=value_size-1 ; table_id!=0 && table[table_id]==0 ; --table_id); + + if( table_id==0 && table[table_id]==0 ) + { + // is zero + index = 0; + + return false; + } + + // table[table_id] is different from 0 + index = FindLeadingBitInWord( table[table_id] ); + + return true; + } + + + /*! + this method looks for the smallest set bit + + result: + if 'this' is not zero: + return value - true + 'table_id' - the index of a word <0..value_size-1> + 'index' - the index of this set bit in the word <0..TTMATH_BITS_PER_UINT) + + if 'this' is zero: + return value - false + both 'table_id' and 'index' are zero + */ + bool FindLowestBit(uint & table_id, uint & index) const + { + for(table_id=0 ; table_id= value_size ) + { + // is zero + index = 0; + table_id = 0; + + return false; + } + + // table[table_id] is different from 0 + index = FindLowestBitInWord( table[table_id] ); + + return true; + } + + + /*! + getting the 'bit_index' bit + + bit_index bigger or equal zero + */ + uint GetBit(uint bit_index) const + { + TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT ) + + uint index = bit_index / TTMATH_BITS_PER_UINT; + uint bit = bit_index % TTMATH_BITS_PER_UINT; + + uint temp = table[index]; + uint res = SetBitInWord(temp, bit); + + return res; + } + + + /*! + setting the 'bit_index' bit + and returning the last state of the bit + + bit_index bigger or equal zero + */ + uint SetBit(uint bit_index) + { + TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT ) + + uint index = bit_index / TTMATH_BITS_PER_UINT; + uint bit = bit_index % TTMATH_BITS_PER_UINT; + uint res = SetBitInWord(table[index], bit); + + TTMATH_LOG("UInt::SetBit") + + return res; + } + + + /*! + this method performs a bitwise operation AND + */ + void BitAnd(const UInt & ss2) + { + for(uint x=0 ; x & ss2) + { + for(uint x=0 ; x & ss2) + { + for(uint x=0 ; x + + for example: + BitNot2(8) = BitNot2( 1000(bin) ) = 111(bin) = 7 + */ + void BitNot2() + { + uint table_id, index; + + if( FindLeadingBit(table_id, index) ) + { + for(uint x=0 ; x>= shift; + + table[table_id] ^= mask; + } + else + table[0] = 1; + + + TTMATH_LOG("UInt::BitNot2") + } + + + + /*! + * + * Multiplication + * + * + */ + +public: + + /*! + multiplication: this = this * ss2 + + it can return a carry + */ + uint MulInt(uint ss2) + { + uint r1, r2, x1; + uint c = 0; + + UInt u(*this); + SetZero(); + + if( ss2 == 0 ) + { + TTMATH_LOGC("UInt::MulInt(uint)", 0) + return 0; + } + + for(x1=0 ; x1 + void MulInt(uint ss2, UInt & result) const + { + TTMATH_ASSERT( result_size > value_size ) + + uint r2,r1; + uint x1size=value_size; + uint x1start=0; + + result.SetZero(); + + if( ss2 == 0 ) + { + TTMATH_VECTOR_LOG("UInt::MulInt(uint, UInt<>)", result.table, result_size) + return; + } + + 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 ) + { + TTMATH_VECTOR_LOG("UInt::MulInt(uint, UInt<>)", result.table, result_size) + return; + } + + for(x1start=0 ; x1start)", result.table, result_size) + + return; + } + + + + /*! + the multiplication 'this' = 'this' * ss2 + + algorithm: 100 - means automatically choose the fastest algorithm + */ + uint Mul(const UInt & ss2, uint algorithm = 100) + { + switch( algorithm ) + { + case 1: + return Mul1(ss2); + + case 2: + return Mul2(ss2); + + case 3: + return Mul3(ss2); + + case 100: + default: + return MulFastest(ss2); + } + } + + + /*! + the multiplication 'result' = 'this' * ss2 + + since the 'result' is twice bigger than 'this' and 'ss2' + this method never returns a carry + + algorithm: 100 - means automatically choose the fastest algorithm + */ + void MulBig(const UInt & ss2, + UInt & result, + uint algorithm = 100) + { + switch( algorithm ) + { + case 1: + return Mul1Big(ss2, result); + + case 2: + return Mul2Big(ss2, result); + + case 3: + return Mul3Big(ss2, result); + + case 100: + default: + return MulFastestBig(ss2, result); + } + } + + + + /*! + the first version of the multiplication algorithm + */ + + /*! + multiplication: this = this * ss2 + + it returns carry if it has been + */ + uint Mul1(const UInt & ss2) + { + TTMATH_REFERENCE_ASSERT( ss2 ) + + UInt ss1( *this ); + SetZero(); + + for(uint i=0; i < value_size*TTMATH_BITS_PER_UINT ; ++i) + { + if( Add(*this) ) + { + TTMATH_LOGC("UInt::Mul1", 1) + return 1; + } + + if( ss1.Rcl(1) ) + if( Add(ss2) ) + { + TTMATH_LOGC("UInt::Mul1", 1) + return 1; + } + } + + TTMATH_LOGC("UInt::Mul1", 0) + + return 0; + } + + + /*! + multiplication: result = this * ss2 + + result is twice bigger than 'this' and 'ss2' + this method never returns carry + */ + void Mul1Big(const UInt & ss2_, UInt & result) + { + UInt ss2; + uint i; + + // copying *this into result and ss2_ into ss2 + for(i=0 ; i & ss2) + { + UInt result; + uint i, c = 0; + + Mul2Big(ss2, result); + + // copying result + for(i=0 ; i & ss2, UInt & result) + { + Mul2Big2(table, ss2.table, result); + + TTMATH_LOG("UInt::Mul2Big") + } + + +private: + + /*! + an auxiliary method for calculating the multiplication + + arguments we're taking as pointers (this is to improve the Mul3Big2()- avoiding + unnecessary copying objects), the result should be taken as a pointer too, + but at the moment there is no method AddTwoInts() which can operate on pointers + */ + template + void Mul2Big2(const uint * ss1, const uint * ss2, UInt & result) + { + uint x1size = ss_size, x2size = ss_size; + uint x1start = 0, x2start = 0; + + if( ss_size > 2 ) + { + // if the ss_size is smaller than or equal to 2 + // there is no sense to set x1size (and others) to another values + + for(x1size=ss_size ; x1size>0 && ss1[x1size-1]==0 ; --x1size); + for(x2size=ss_size ; x2size>0 && ss2[x2size-1]==0 ; --x2size); + + for(x1start=0 ; x1start(ss1, ss2, result, x1start, x1size, x2start, x2size); + } + + + + /*! + an auxiliary method for calculating the multiplication + */ + template + void Mul2Big3(const uint * ss1, const uint * ss2, UInt & result, uint x1start, uint x1size, uint x2start, uint x2size) + { + uint r2, r1; + + result.SetZero(); + + if( x1size==0 || x2size==0 ) + return; + + for(uint x1=x1start ; x1 & ss2) + { + UInt result; + uint i, c = 0; + + Mul3Big(ss2, result); + + // copying result + for(i=0 ; i & ss2, UInt & result) + { + Mul3Big2(table, ss2.table, result.table); + + TTMATH_LOG("UInt::Mul3Big") + } + + + +private: + + /*! + an auxiliary method for calculating the Karatsuba multiplication + + result_size is equal ss_size*2 + */ + template + void Mul3Big2(const uint * ss1, const uint * ss2, uint * result) + { + const uint * x1, * x0, * y1, * y0; + + + if( ss_size>1 && ss_size res; + Mul2Big2(ss1, ss2, res); + + for(uint i=0 ; i(x1, x0, y1, y0, result); + } + else + { + // ss_size is even + x0 = ss1; + y0 = ss2; + x1 = ss1 + ss_size / 2; + y1 = ss2 + ss_size / 2; + + // all four vectors (x0 x1 y0 y1) are equal in size + Mul3Big3(x1, x0, y1, y0, result); + } + } + + + +#ifdef _MSC_VER +#pragma warning (disable : 4717) +//warning C4717: recursive on all control paths, function will cause runtime stack overflow +//we have the stop point in Mul3Big2() method +#endif + + + /*! + an auxiliary method for calculating the Karatsuba multiplication + + x = x1*B^m + x0 + y = y1*B^m + y0 + + first_size - is the size of vectors: x0 and y0 + second_size - is the size of vectors: x1 and y1 (can be either equal first_size or smaller about one from first_size) + + x*y = (x1*B^m + x0)(y1*B^m + y0) = z2*B^(2m) + z1*B^m + z0 + where + z0 = x0*y0 + z2 = x1*y1 + z1 = (x1 + x0)*(y1 + y0) - z2 - z0 + */ + template + void Mul3Big3(const uint * x1, const uint * x0, const uint * y1, const uint * y0, uint * result) + { + uint i, c, xc, yc; + + UInt temp, temp2; + UInt z1; + + // z0 and z2 we store directly in the result (we don't use any temporary variables) + Mul3Big2(x0, y0, result); // z0 + Mul3Big2(x1, y1, result+first_size*2); // z2 + + // now we calculate z1 + // temp = (x0 + x1) + // temp2 = (y0 + y1) + // we're using temp and temp2 with UInt, although there can be a carry but + // we simple remember it in xc and yc (xc and yc can be either 0 or 1), + // and (x0 + x1)*(y0 + y1) we calculate in this way (schoolbook algorithm): + // + // xc | temp + // yc | temp2 + // -------------------- + // (temp * temp2) + // xc*temp2 | + // yc*temp | + // xc*yc | + // ---------- z1 -------- + // + // and the result is never larger in size than 3*first_size + + xc = AddVector(x0, x1, first_size, second_size, temp.table); + yc = AddVector(y0, y1, first_size, second_size, temp2.table); + + Mul3Big2(temp.table, temp2.table, z1.table); + + // clearing the rest of z1 + for(i=first_size*2 ; i second_size ) + { + uint z1_size = result_size - first_size; + TTMATH_ASSERT( z1_size <= first_size*3 ) + + for(i=z1_size ; i & ss2) + { + UInt result; + uint i, c = 0; + + MulFastestBig(ss2, result); + + // copying result + for(i=0 ; i & ss2, UInt & result) + { + if( value_size < TTMATH_USE_KARATSUBA_MULTIPLICATION_FROM_SIZE ) + return Mul2Big(ss2, result); + + uint x1size = value_size, x2size = value_size; + uint x1start = 0, x2start = 0; + + for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); + for(x2size=value_size ; x2size>0 && ss2.table[x2size-1]==0 ; --x2size); + + if( x1size==0 || x2size==0 ) + { + // either 'this' or 'ss2' is equal zero - the result is zero too + result.SetZero(); + return; + } + + for(x1start=0 ; x1start(table, ss2.table, result, x1start, x1size, x2start, x2size); + + + // Karatsuba multiplication + Mul3Big(ss2, result); + + TTMATH_LOG("UInt::MulFastestBig") + } + + + /*! + * + * Division + * + * + */ + +public: + + + /*! + division by one unsigned word + + returns 1 when divisor is zero + */ + uint DivInt(uint divisor, uint * remainder = 0) + { + if( divisor == 0 ) + { + if( remainder ) + *remainder = 0; // this is for convenience, without it the compiler can report that 'remainder' is uninitialized + + TTMATH_LOG("UInt::DivInt") + + return 1; + } + + if( divisor == 1 ) + { + if( remainder ) + *remainder = 0; + + TTMATH_LOG("UInt::DivInt") + + return 0; + } + + UInt dividend(*this); + SetZero(); + + sint i; // i must be with a sign + uint r = 0; + + // we're looking for the last word in ss1 + for(i=value_size-1 ; i>0 && dividend.table[i]==0 ; --i); + + for( ; i>=0 ; --i) + DivTwoWords(r, dividend.table[i], divisor, &table[i], &r); + + if( remainder ) + *remainder = r; + + TTMATH_LOG("UInt::DivInt") + + return 0; + } + + uint DivInt(uint divisor, uint & remainder) + { + return DivInt(divisor, &remainder); + } + + + + /*! + division this = this / ss2 + + return values: + 0 - ok + 1 - division by zero + 'this' will be the quotient + 'remainder' - remainder + */ + uint Div( const UInt & divisor, + UInt * remainder = 0, + uint algorithm = 3) + { + switch( algorithm ) + { + case 1: + return Div1(divisor, remainder); + + case 2: + return Div2(divisor, remainder); + + case 3: + default: + return Div3(divisor, remainder); + } + } + + uint Div(const UInt & divisor, UInt & remainder, uint algorithm = 3) + { + return Div(divisor, &remainder, algorithm); + } + + + +private: + + /*! + return values: + 0 - none has to be done + 1 - division by zero + 2 - division should be made + */ + uint Div_StandardTest( const UInt & v, + uint & m, uint & n, + UInt * remainder = 0) + { + switch( Div_CalculatingSize(v, m, n) ) + { + case 4: // 'this' is equal v + if( remainder ) + remainder->SetZero(); + + SetOne(); + TTMATH_LOG("UInt::Div_StandardTest") + return 0; + + case 3: // 'this' is smaller than v + if( remainder ) + *remainder = *this; + + SetZero(); + TTMATH_LOG("UInt::Div_StandardTest") + return 0; + + case 2: // 'this' is zero + if( remainder ) + remainder->SetZero(); + + SetZero(); + TTMATH_LOG("UInt::Div_StandardTest") + return 0; + + case 1: // v is zero + TTMATH_LOG("UInt::Div_StandardTest") + return 1; + } + + TTMATH_LOG("UInt::Div_StandardTest") + + return 2; + } + + + + /*! + return values: + 0 - ok + 'm' - is the index (from 0) of last non-zero word in table ('this') + 'n' - is the index (from 0) of last non-zero word in v.table + 1 - v is zero + 2 - 'this' is zero + 3 - 'this' is smaller than v + 4 - 'this' is equal v + + if the return value is different than zero the 'm' and 'n' are undefined + */ + uint Div_CalculatingSize(const UInt & v, uint & m, uint & n) + { + m = n = value_size-1; + + for( ; n!=0 && v.table[n]==0 ; --n); + + if( n==0 && v.table[n]==0 ) + return 1; + + for( ; m!=0 && table[m]==0 ; --m); + + if( m==0 && table[m]==0 ) + return 2; + + if( m < n ) + return 3; + else + if( m == n ) + { + uint i; + for(i = n ; i!=0 && table[i]==v.table[i] ; --i); + + if( table[i] < v.table[i] ) + return 3; + else + if (table[i] == v.table[i] ) + return 4; + } + + return 0; + } + + +public: + + /*! + the first division algorithm + radix 2 + */ + uint Div1(const UInt & divisor, UInt * remainder = 0) + { + uint m,n, test; + + test = Div_StandardTest(divisor, m, n, remainder); + if( test < 2 ) + return test; + + if( !remainder ) + { + UInt rem; + + return Div1_Calculate(divisor, rem); + } + + return Div1_Calculate(divisor, *remainder); + } + + +private: + + + uint Div1_Calculate(const UInt & divisor, UInt & rest) + { + TTMATH_REFERENCE_ASSERT( divisor ) + + sint loop; + sint c; + + rest.SetZero(); + loop = value_size * TTMATH_BITS_PER_UINT; + c = 0; + + + div_a: + c = Rcl(1, c); + c = rest.Add(rest,c); + c = rest.Sub(divisor,c); + + c = !c; + + if(!c) + goto div_d; + + + div_b: + --loop; + if(loop) + goto div_a; + + c = Rcl(1, c); + TTMATH_LOG("UInt::Div1_Calculate") + return 0; + + + div_c: + c = Rcl(1, c); + c = rest.Add(rest,c); + c = rest.Add(divisor); + + if(c) + goto div_b; + + + div_d: + --loop; + if(loop) + goto div_c; + + c = Rcl(1, c); + c = rest.Add(divisor); + + TTMATH_LOG("UInt::Div1_Calculate") + + return 0; + } + + +public: + + + /*! + the second division algorithm + + return values: + 0 - ok + 1 - division by zero + */ + uint Div2(const UInt & divisor, UInt * remainder = 0) + { + TTMATH_REFERENCE_ASSERT( divisor ) + + uint bits_diff; + uint status = Div2_Calculate(divisor, remainder, bits_diff); + if( status < 2 ) + return status; + + if( CmpBiggerEqual(divisor) ) + { + Div2(divisor, remainder); + SetBit(bits_diff); + } + else + { + if( remainder ) + *remainder = *this; + + SetZero(); + SetBit(bits_diff); + } + + TTMATH_LOG("UInt::Div2") + + return 0; + } + + + uint Div2(const UInt & divisor, UInt & remainder) + { + return Div2(divisor, &remainder); + } + + +private: + + /*! + return values: + 0 - we've calculated the division + 1 - division by zero + 2 - we have to still calculate + + */ + uint Div2_Calculate(const UInt & divisor, UInt * remainder, + uint & bits_diff) + { + uint table_id, index; + uint divisor_table_id, divisor_index; + + uint status = Div2_FindLeadingBitsAndCheck( divisor, remainder, + table_id, index, + divisor_table_id, divisor_index); + + if( status < 2 ) + { + TTMATH_LOG("UInt::Div2_Calculate") + return status; + } + + // here we know that 'this' is greater than divisor + // then 'index' is greater or equal 'divisor_index' + bits_diff = index - divisor_index; + + UInt divisor_copy(divisor); + divisor_copy.Rcl(bits_diff, 0); + + if( CmpSmaller(divisor_copy, table_id) ) + { + divisor_copy.Rcr(1); + --bits_diff; + } + + Sub(divisor_copy, 0); + + TTMATH_LOG("UInt::Div2_Calculate") + + return 2; + } + + + /*! + return values: + 0 - we've calculated the division + 1 - division by zero + 2 - we have to still calculate + */ + uint Div2_FindLeadingBitsAndCheck( const UInt & divisor, + UInt * remainder, + uint & table_id, uint & index, + uint & divisor_table_id, uint & divisor_index) + { + if( !divisor.FindLeadingBit(divisor_table_id, divisor_index) ) + { + // division by zero + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + return 1; + } + + if( !FindLeadingBit(table_id, index) ) + { + // zero is divided by something + + SetZero(); + + if( remainder ) + remainder->SetZero(); + + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + + return 0; + } + + divisor_index += divisor_table_id * TTMATH_BITS_PER_UINT; + index += table_id * TTMATH_BITS_PER_UINT; + + if( divisor_table_id == 0 ) + { + // dividor has only one 32-bit word + + uint r; + DivInt(divisor.table[0], &r); + + if( remainder ) + { + remainder->SetZero(); + remainder->table[0] = r; + } + + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + + return 0; + } + + + if( Div2_DivisorGreaterOrEqual( divisor, remainder, + table_id, index, + divisor_index) ) + { + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + return 0; + } + + + TTMATH_LOG("UInt::Div2_FindLeadingBitsAndCheck") + + return 2; + } + + + /*! + return values: + true if divisor is equal or greater than 'this' + */ + bool Div2_DivisorGreaterOrEqual( const UInt & divisor, + UInt * remainder, + uint table_id, uint index, + uint divisor_index ) + { + if( divisor_index > index ) + { + // divisor is greater than this + + if( remainder ) + *remainder = *this; + + SetZero(); + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return true; + } + + if( divisor_index == index ) + { + // table_id == divisor_table_id as well + + uint i; + for(i = table_id ; i!=0 && table[i]==divisor.table[i] ; --i); + + if( table[i] < divisor.table[i] ) + { + // divisor is greater than 'this' + + if( remainder ) + *remainder = *this; + + SetZero(); + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return true; + } + else + if( table[i] == divisor.table[i] ) + { + // divisor is equal 'this' + + if( remainder ) + remainder->SetZero(); + + SetOne(); + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return true; + } + } + + TTMATH_LOG("UInt::Div2_DivisorGreaterOrEqual") + + return false; + } + + +public: + + /*! + the third division algorithm + + this algorithm is described in the following book: + "The art of computer programming 2" (4.3.1 page 272) + Donald E. Knuth + */ + uint Div3(const UInt & v, UInt * remainder = 0) + { + TTMATH_REFERENCE_ASSERT( v ) + + uint m,n, test; + + test = Div_StandardTest(v, m, n, remainder); + if( test < 2 ) + return test; + + if( n == 0 ) + { + uint r; + DivInt( v.table[0], &r ); + + if( remainder ) + { + remainder->SetZero(); + remainder->table[0] = r; + } + + TTMATH_LOG("UInt::Div3") + + return 0; + } + + + // we can only use the third division algorithm when + // the divisor is greater or equal 2^32 (has more than one 32-bit word) + ++m; + ++n; + m = m - n; + Div3_Division(v, remainder, m, n); + + TTMATH_LOG("UInt::Div3") + + return 0; + } + + + +private: + + + void Div3_Division(UInt v, UInt * remainder, uint m, uint n) + { + TTMATH_ASSERT( n>=2 ) + + UInt uu, vv; + UInt q; + uint d, u_value_size, u0, u1, u2, v1, v0, j=m; + + u_value_size = Div3_Normalize(v, n, d); + + if( j+n == value_size ) + u2 = u_value_size; + else + u2 = table[j+n]; + + Div3_MakeBiggerV(v, vv); + + for(uint i = j+1 ; i & uu, uint j, uint n, uint u_max) + { + uint i; + + for(i=0 ; i so and 'i' is from <0..value_size> + // then table[i] is always correct (look at the declaration of 'uu') + uu.table[i] = u_max; + + for( ++i ; i & uu, uint j, uint n) + { + uint i; + + for(i=0 ; i & v, UInt & vv) + { + for(uint i=0 ; i & v, uint n, uint & d) + { + // v.table[n-1] is != 0 + + uint bit = (uint)FindLeadingBitInWord(v.table[n-1]); + uint move = (TTMATH_BITS_PER_UINT - bit - 1); + uint res = table[value_size-1]; + d = move; + + if( move > 0 ) + { + v.Rcl(move, 0); + Rcl(move, 0); + res = res >> (bit + 1); + } + else + { + res = 0; + } + + TTMATH_LOG("UInt::Div3_Normalize") + + return res; + } + + + void Div3_Unnormalize(UInt * remainder, uint n, uint d) + { + for(uint i=n ; i u_temp; + uint rp; + bool next_test; + + TTMATH_ASSERT( v1 != 0 ) + + u_temp.table[1] = u2; + u_temp.table[0] = u1; + u_temp.DivInt(v1, &rp); + + TTMATH_ASSERT( u_temp.table[1]==0 || u_temp.table[1]==1 ) + + do + { + bool decrease = false; + + if( u_temp.table[1] == 1 ) + decrease = true; + else + { + UInt<2> temp1, temp2; + + UInt<2>::MulTwoWords(u_temp.table[0], v0, temp1.table+1, temp1.table); + temp2.table[1] = rp; + temp2.table[0] = u0; + + if( temp1 > temp2 ) + decrease = true; + } + + next_test = false; + + if( decrease ) + { + u_temp.SubOne(); + + rp += v1; + + if( rp >= v1 ) // it means that there wasn't a carry (r & uu, + const UInt & vv, uint & qp) + { + // D4 (in the book) + + UInt vv_temp(vv); + vv_temp.MulInt(qp); + + if( uu.Sub(vv_temp) ) + { + // there was a carry + + // + // !!! this part of code was not tested + // + + --qp; + uu.Add(vv); + + // can be a carry from this additions but it should be ignored + // because it cancels with the borrow from uu.Sub(vv_temp) + } + + TTMATH_LOG("UInt::Div3_MultiplySubtract") + } + + + + + + +public: + + + /*! + power this = this ^ pow + binary algorithm (r-to-l) + + return values: + 0 - ok + 1 - carry + 2 - incorrect argument (0^0) + */ + uint Pow(UInt pow) + { + if(pow.IsZero() && IsZero()) + // we don't define zero^zero + return 2; + + UInt start(*this), start_temp; + UInt result; + result.SetOne(); + uint c = 0; + + while( !c ) + { + if( pow.table[0] & 1 ) + c += result.Mul(start); + + pow.Rcr2_one(0); + if( pow.IsZero() ) + break; + + start_temp = start; + // in the second Mul algorithm we can use start.Mul(start) directly (there is no TTMATH_ASSERT_REFERENCE there) + c += start.Mul(start_temp); + } + + *this = result; + + TTMATH_LOGC("UInt::Pow(UInt<>)", c) + + return (c==0)? 0 : 1; + } + + + /*! + square root + e.g. Sqrt(9) = 3 + ('digit-by-digit' algorithm) + */ + void Sqrt() + { + UInt bit, temp; + + if( IsZero() ) + return; + + UInt value(*this); + + SetZero(); + bit.SetZero(); + bit.table[value_size-1] = (TTMATH_UINT_HIGHEST_BIT >> 1); + + while( bit > value ) + bit.Rcr(2); + + while( !bit.IsZero() ) + { + temp = *this; + temp.Add(bit); + + if( value >= temp ) + { + value.Sub(temp); + Rcr(1); + Add(bit); + } + else + { + Rcr(1); + } + + bit.Rcr(2); + } + + TTMATH_LOG("UInt::Sqrt") + } + + + + /*! + this method sets n first bits to value zero + + For example: + let n=2 then if there's a value 111 (bin) there'll be '100' (bin) + */ + void ClearFirstBits(uint n) + { + if( n >= value_size*TTMATH_BITS_PER_UINT ) + { + SetZero(); + TTMATH_LOG("UInt::ClearFirstBits") + return; + } + + uint * p = table; + + // first we're clearing the whole words + while( n >= TTMATH_BITS_PER_UINT ) + { + *p++ = 0; + n -= TTMATH_BITS_PER_UINT; + } + + if( n == 0 ) + { + TTMATH_LOG("UInt::ClearFirstBits") + return; + } + + // and then we're clearing one word which has left + // mask -- all bits are set to one + uint mask = TTMATH_UINT_MAX_VALUE; + + mask = mask << n; + + (*p) &= mask; + + TTMATH_LOG("UInt::ClearFirstBits") + } + + + /*! + this method returns true if the highest bit of the value is set + */ + bool IsTheHighestBitSet() const + { + return (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) != 0; + } + + + /*! + this method returns true if the lowest bit of the value is set + */ + bool IsTheLowestBitSet() const + { + return (*table & 1) != 0; + } + + + /*! + this method returns true if the value is equal zero + */ + bool IsZero() const + { + for(uint i=0 ; i> (TTMATH_BITS_PER_UINT - rest); + + return (table[i] & mask) == 0; + } + + + + /*! + * + * conversion methods + * + */ + + + + /*! + this method converts an UInt type to this class + + this operation has mainly sense if the value from p is + equal or smaller than that one which is returned from UInt::SetMax() + + it returns a carry if the value 'p' is too big + */ + template + uint FromUInt(const UInt & p) + { + uint min_size = (value_size < argument_size)? value_size : argument_size; + uint i; + + for(i=0 ; i argument_size ) + { + // 'this' is longer than 'p' + + for( ; i)", 1) + return 1; + } + } + + TTMATH_LOGC("UInt::FromUInt(UInt<>)", 0) + + return 0; + } + + + /*! + this method converts the uint type to this class + */ + void FromUInt(uint value) + { + for(uint i=1 ; i type to this class + + it doesn't return a carry + */ + template + UInt & operator=(const UInt & p) + { + FromUInt(p); + + return *this; + } + + + /*! + the assignment operator + */ + UInt & operator=(const UInt & p) + { + for(uint i=0 ; i)") + + return *this; + } + + + /*! + this method converts the uint type to this class + */ + UInt & operator=(uint i) + { + FromUInt(i); + + return *this; + } + + + /*! + a constructor for converting the uint to this class + */ + UInt(uint i) + { + FromUInt(i); + } + + + /*! + this method converts the sint type to this class + + we provide operator(sint) and the constructor(sint) in order to allow + the programmer do that: + UInt<..> type = 10; + + above "10" constant has the int type (signed int), if we don't give such + operators and constructors the compiler will not compile the program, + because it has to make a conversion and doesn't know into which type + (the UInt class has operator=(const char*), operator=(uint) etc.) + */ + UInt & operator=(sint i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the sint to this class + + look at the description of UInt::operator=(sint) + */ + UInt(sint i) + { + FromUInt(uint(i)); + } + + + +#ifdef TTMATH_PLATFORM64 + + /*! + in 64bit platforms we must define additional operators and contructors + in order to allow a user initializing the objects in this way: + UInt<...> type = 20; + or + UInt<...> type; + type = 30; + + decimal constants such as 20, 30 etc. are integer literal of type int, + if the value is greater it can even be long int, + 0 is an octal integer of type int + (ISO 14882 p2.13.1 Integer literals) + */ + + /*! + this operator converts the unsigned int type to this class + + ***this operator is created only on a 64bit platform*** + it takes one argument of 32bit + */ + UInt & operator=(unsigned int i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the unsigned int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + */ + UInt(unsigned int i) + { + FromUInt(uint(i)); + } + + + /*! + an operator for converting the signed int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + + look at the description of UInt::operator=(sint) + */ + UInt & operator=(signed int i) + { + FromUInt(uint(i)); + + return *this; + } + + + /*! + a constructor for converting the signed int to this class + + ***this constructor is created only on a 64bit platform*** + it takes one argument of 32bit + + look at the description of UInt::operator=(sint) + */ + UInt(signed int i) + { + FromUInt(uint(i)); + } + + +#endif + + + + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const char * s) + { + FromString(s); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const wchar_t * s) + { + FromString(s); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const std::string & s) + { + FromString( s.c_str() ); + } + + + /*! + a constructor for converting a string to this class (with the base=10) + */ + UInt(const std::wstring & s) + { + FromString( s.c_str() ); + } + + + /*! + a default constructor + + we don't clear the table + */ + UInt() + { + // when macro TTMATH_DEBUG_LOG is defined + // we set special values to the table + // in order to be everywhere the same value of the UInt object + // without this it would be difficult to analyse the log file + #ifdef TTMATH_DEBUG_LOG + #ifdef TTMATH_PLATFORM32 + for(uint i=0 ; i & u) + { + for(uint i=0 ; i)") + } + + + + /*! + a template for producting constructors for copying from another types + */ + template + UInt(const UInt & u) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + FromUInt(u); + } + + + + + /*! + a destructor + */ + ~UInt() + { + } + + + /*! + this method returns the lowest value from table + + we must be sure when we using this method whether the value + will hold in an uint type or not (the rest value from the table must be zero) + */ + uint ToUInt() const + { + return table[0]; + } + + +private: + + /*! + an auxiliary method for converting to a string + */ + template + void ToStringBase(string_type & result, uint b = 10) const + { + UInt temp( *this ); + char character; + uint rem; + + result.clear(); + + if( b<2 || b>16 ) + return; + + do + { + temp.DivInt(b, &rem); + character = static_cast( Misc::DigitToChar(rem) ); + result.insert(result.begin(), character); + } + while( !temp.IsZero() ); + + return; + } + + +public: + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::string & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + void ToString(std::wstring & result, uint b = 10) const + { + return ToStringBase(result, b); + } + + std::string ToString(uint b = 10) const + { + std::string result; + ToStringBase(result, b); + + return result; + } + + std::wstring ToWString(uint b = 10) const + { + std::wstring result; + ToStringBase(result, b); + + return result; + } + + +private: + + /*! + an auxiliary method for converting from a string + */ + template + uint FromStringBase(const char_type * s, uint b = 10, const char_type ** after_source = 0, bool * value_read = 0) + { + UInt base( b ); + UInt temp; + sint z; + uint c = 0; + + SetZero(); + temp.SetZero(); + Misc::SkipWhiteCharacters(s); + + if( after_source ) + *after_source = s; + + if( value_read ) + *value_read = false; + + if( b<2 || b>16 ) + return 1; + + + for( ; (z=Misc::CharToDigit(*s, b)) != -1 ; ++s) + { + if( value_read ) + *value_read = true; + + if( c == 0 ) + { + temp.table[0] = z; + + c += Mul(base); + c += Add(temp); + } + } + + if( after_source ) + *after_source = s; + + TTMATH_LOGC("UInt::FromString", c) + + return (c==0)? 0 : 1; + } + + +public: + + + /*! + this method converts a string into its value + it returns carry=1 if the value will be too big or an incorrect base 'b' is given + + string is ended with a non-digit value, for example: + "12" will be translated to 12 + as well as: + "12foo" will be translated to 12 too + + existing first white characters will be ommited + + if the value from s is too large the rest digits will be skipped + + after_source (if exists) is pointing at the end of the parsed string + + value_read (if exists) tells whether something has actually been read (at least one digit) + */ + uint FromString(const char * s, uint b = 10, const char ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + */ + uint FromString(const wchar_t * s, uint b = 10, const wchar_t ** after_source = 0, bool * value_read = 0) + { + return FromStringBase(s, b, after_source, value_read); + } + + + /*! + this method converts a string into its value + + (it returns carry=1 if the value will be too big or an incorrect base 'b' is given) + */ + uint FromString(const std::string & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this method converts a string into its value + + (it returns carry=1 if the value will be too big or an incorrect base 'b' is given) + */ + uint FromString(const std::wstring & s, uint b = 10) + { + return FromString( s.c_str(), b ); + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const char * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const wchar_t * s) + { + FromString(s); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const std::string & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + this operator converts a string into its value (with base = 10) + */ + UInt & operator=(const std::wstring & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + * + * methods for comparing + * + */ + + + /*! + this method returns true if 'this' is smaller than 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + I introduced it for some kind of optimization made in the second division algorithm (Div2) + */ + bool CmpSmaller(const UInt & l, sint index = -1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] < l.table[i]; + } + + // they're equal + return false; + } + + + + /*! + this method returns true if 'this' is bigger than 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + + I introduced it for some kind of optimization made in the second division algorithm (Div2) + */ + bool CmpBigger(const UInt & l, sint index = -1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] > l.table[i]; + } + + // they're equal + return false; + } + + + /*! + this method returns true if 'this' is equal 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + */ + bool CmpEqual(const UInt & l, sint index = -1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + if( table[i] != l.table[i] ) + return false; + + return true; + } + + + + /*! + this method returns true if 'this' is smaller than or equal 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + */ + bool CmpSmallerEqual(const UInt & l, sint index=-1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] < l.table[i]; + } + + // they're equal + return true; + } + + + + /*! + this method returns true if 'this' is bigger than or equal 'l' + + 'index' is an index of the first word from will be the comparison performed + (note: we start the comparison from back - from the last word, when index is -1 /default/ + it is automatically set into the last word) + */ + bool CmpBiggerEqual(const UInt & l, sint index=-1) const + { + sint i; + + if( index==-1 || index>=sint(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] > l.table[i]; + } + + // they're equal + return true; + } + + + /* + operators for comparising + */ + + bool operator<(const UInt & l) const + { + return CmpSmaller(l); + } + + + bool operator>(const UInt & l) const + { + return CmpBigger(l); + } + + + bool operator==(const UInt & l) const + { + return CmpEqual(l); + } + + + bool operator!=(const UInt & l) const + { + return !operator==(l); + } + + + bool operator<=(const UInt & l) const + { + return CmpSmallerEqual(l); + } + + bool operator>=(const UInt & l) const + { + return CmpBiggerEqual(l); + } + + + /*! + * + * standard mathematical operators + * + */ + + UInt operator-(const UInt & p2) const + { + UInt temp(*this); + + temp.Sub(p2); + + return temp; + } + + UInt & operator-=(const UInt & p2) + { + Sub(p2); + + return *this; + } + + UInt operator+(const UInt & p2) const + { + UInt temp(*this); + + temp.Add(p2); + + return temp; + } + + UInt & operator+=(const UInt & p2) + { + Add(p2); + + return *this; + } + + + UInt operator*(const UInt & p2) const + { + UInt temp(*this); + + temp.Mul(p2); + + return temp; + } + + + UInt & operator*=(const UInt & p2) + { + Mul(p2); + + return *this; + } + + + UInt operator/(const UInt & p2) const + { + UInt temp(*this); + + temp.Div(p2); + + return temp; + } + + + UInt & operator/=(const UInt & p2) + { + Div(p2); + + return *this; + } + + + UInt operator%(const UInt & p2) const + { + UInt temp(*this); + UInt remainder; + + temp.Div( p2, remainder ); + + return remainder; + } + + + UInt & operator%=(const UInt & p2) + { + UInt temp(*this); + UInt remainder; + + temp.Div( p2, remainder ); + + operator=(remainder); + + return *this; + } + + + /*! + Prefix operator e.g ++variable + */ + UInt & operator++() + { + AddOne(); + + return *this; + } + + + /*! + Postfix operator e.g variable++ + */ + UInt operator++(int) + { + UInt temp( *this ); + + AddOne(); + + return temp; + } + + + UInt & operator--() + { + SubOne(); + + return *this; + } + + + UInt operator--(int) + { + UInt temp( *this ); + + SubOne(); + + return temp; + } + + + UInt operator>>(int move) + { + UInt temp( *this ); + + temp.Rcr(move); + + return temp; + } + + + UInt & operator>>=(int move) + { + Rcr(move); + + return *this; + } + + + UInt operator<<(int move) + { + UInt temp( *this ); + + temp.Rcl(move); + + return temp; + } + + + UInt & operator<<=(int move) + { + Rcl(move); + + return *this; + } + + + /*! + * + * input/output operators for standard streams + * + * (they are very simple, in the future they should be changed) + * + */ + + +private: + + + /*! + an auxiliary method for outputing to standard streams + */ + template + static ostream_type & OutputToStream(ostream_type & s, const UInt & l) + { + string_type ss; + + l.ToString(ss); + s << ss; + + return s; + } + + +public: + + + /*! + output to standard streams + */ + friend std::ostream & operator<<(std::ostream & s, const UInt & l) + { + return OutputToStream(s, l); + } + + + /*! + output to standard streams + */ + friend std::wostream & operator<<(std::wostream & s, const UInt & l) + { + return OutputToStream(s, l); + } + + +private: + + /*! + an auxiliary method for reading from standard streams + */ + template + static istream_type & InputFromStream(istream_type & s, UInt & l) + { + string_type ss; + + // char or wchar_t for operator>> + char_type z; + + // operator>> omits white characters if they're set for ommiting + s >> z; + + // we're reading only digits (base=10) + while( s.good() && Misc::CharToDigit(z, 10)>=0 ) + { + ss += z; + z = static_cast(s.get()); + } + + // we're leaving the last read character + // (it's not belonging to the value) + s.unget(); + + l.FromString(ss); + + return s; + } + +public: + + + /*! + input from standard streams + */ + friend std::istream & operator>>(std::istream & s, UInt & l) + { + return InputFromStream(s, l); + } + + + /*! + input from standard streams + */ + friend std::wistream & operator>>(std::wistream & s, UInt & l) + { + return InputFromStream(s, l); + } + + + /* + following methods are defined in: + ttmathuint_x86.h + ttmathuint_x86_64.h + ttmathuint_noasm.h + */ + +#ifdef TTMATH_NOASM + static uint AddTwoWords(uint a, uint b, uint carry, uint * result); + static uint SubTwoWords(uint a, uint b, uint carry, uint * result); + +#ifdef TTMATH_PLATFORM64 + + union uint_ + { + struct + { + unsigned int low; // 32 bit + unsigned int high; // 32 bit + } u_; + + uint u; // 64 bit + }; + + + static void DivTwoWords2(uint a,uint b, uint c, uint * r, uint * rest); + static uint DivTwoWordsNormalize(uint_ & a_, uint_ & b_, uint_ & c_); + static uint DivTwoWordsUnnormalize(uint u, uint d); + static unsigned int DivTwoWordsCalculate(uint_ u_, unsigned int u3, uint_ v_); + static void MultiplySubtract(uint_ & u_, unsigned int & u3, unsigned int & q, uint_ v_); + +#endif // TTMATH_PLATFORM64 +#endif // TTMATH_NOASM + + +private: + uint Rcl2_one(uint c); + uint Rcr2_one(uint c); + uint Rcl2(uint bits, uint c); + uint Rcr2(uint bits, uint c); + +public: + static const char * LibTypeStr(); + static LibTypeCode LibType(); + uint Add(const UInt & ss2, uint c=0); + uint AddInt(uint value, uint index = 0); + uint AddTwoInts(uint x2, uint x1, uint index); + static uint AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + uint Sub(const UInt & ss2, uint c=0); + uint SubInt(uint value, uint index = 0); + static uint SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + static sint FindLeadingBitInWord(uint x); + static sint FindLowestBitInWord(uint x); + static uint SetBitInWord(uint & value, uint bit); + static void MulTwoWords(uint a, uint b, uint * result_high, uint * result_low); + static void DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest); + +}; + + + +/*! + this specialization is needed in order to not confused the compiler "error: ISO C++ forbids zero-size array" + when compiling Mul3Big2() method +*/ +template<> +class UInt<0> +{ +public: + uint table[1]; + + void Mul2Big(const UInt<0> &, UInt<0> &) { TTMATH_ASSERT(false) }; + void SetZero() { TTMATH_ASSERT(false) }; + uint AddTwoInts(uint, uint, uint) { TTMATH_ASSERT(false) return 0; }; +}; + + +} //namespace + + +#include "ttmathuint_x86.h" +#include "ttmathuint_x86_64.h" +#include "ttmathuint_noasm.h" + +#endif diff --git a/ttmath/ttmathuint_noasm.h b/ttmath/ttmathuint_noasm.h new file mode 100644 index 0000000..ed3c180 --- /dev/null +++ b/ttmath/ttmathuint_noasm.h @@ -0,0 +1,1013 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef headerfilettmathuint_noasm +#define headerfilettmathuint_noasm + + +#ifdef TTMATH_NOASM + +/*! + \file ttmathuint_noasm.h + \brief template class UInt with methods without any assembler code + + this file is included at the end of ttmathuint.h +*/ + + +namespace ttmath +{ + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + template + const char * UInt::LibTypeStr() + { + #ifdef TTMATH_PLATFORM32 + static const char info[] = "no_asm_32"; + #endif + + #ifdef TTMATH_PLATFORM64 + static const char info[] = "no_asm_64"; + #endif + + return info; + } + + + /*! + returning the currect type of the library + */ + template + LibTypeCode UInt::LibType() + { + #ifdef TTMATH_PLATFORM32 + LibTypeCode info = no_asm_32; + #endif + + #ifdef TTMATH_PLATFORM64 + LibTypeCode info = no_asm_64; + #endif + + return info; + } + + + /*! + this method adds two words together + returns carry + + this method is created only when TTMATH_NOASM macro is defined + */ + template + uint UInt::AddTwoWords(uint a, uint b, uint carry, uint * result) + { + uint temp; + + if( carry == 0 ) + { + temp = a + b; + + if( temp < a ) + carry = 1; + } + else + { + carry = 1; + temp = a + b + carry; + + if( temp > a ) // !(temp<=a) + carry = 0; + } + + *result = temp; + + return carry; + } + + + + /*! + this method adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + + template + uint UInt::Add(const UInt & ss2, uint c) + { + uint i; + + for(i=0 ; i + uint UInt::AddInt(uint value, uint index) + { + uint i, c; + + TTMATH_ASSERT( index < value_size ) + + + c = AddTwoWords(table[index], value, 0, &table[index]); + + for(i=index+1 ; i + uint UInt::AddTwoInts(uint x2, uint x1, uint index) + { + uint i, c; + + TTMATH_ASSERT( index < value_size - 1 ) + + + c = AddTwoWords(table[index], x1, 0, &table[index]); + c = AddTwoWords(table[index+1], x2, c, &table[index+1]); + + for(i=index+2 ; i + uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + uint i, c = 0; + + TTMATH_ASSERT( ss1_size >= ss2_size ) + + for(i=0 ; i + uint UInt::SubTwoWords(uint a, uint b, uint carry, uint * result) + { + if( carry == 0 ) + { + *result = a - b; + + if( a < b ) + carry = 1; + } + else + { + carry = 1; + *result = a - b - carry; + + if( a > b ) // !(a <= b ) + carry = 0; + } + + return carry; + } + + + + + /*! + this method's subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + uint i; + + for(i=0 ; i + uint UInt::SubInt(uint value, uint index) + { + uint i, c; + + TTMATH_ASSERT( index < value_size ) + + + c = SubTwoWords(table[index], value, 0, &table[index]); + + for(i=index+1 ; i + uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + uint i, c = 0; + + TTMATH_ASSERT( ss1_size >= ss2_size ) + + for(i=0 ; i + uint UInt::Rcl2_one(uint c) + { + uint i, new_c; + + if( c != 0 ) + c = 1; + + for(i=0 ; i this -> return value + + the highest *bit* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 + */ + template + uint UInt::Rcr2_one(uint c) + { + sint i; // signed i + uint new_c; + + if( c != 0 ) + c = TTMATH_UINT_HIGHEST_BIT; + + for(i=sint(value_size)-1 ; i>=0 ; --i) + { + new_c = (table[i] & 1) ? TTMATH_UINT_HIGHEST_BIT : 0; + table[i] = (table[i] >> 1) | c; + c = new_c; + } + + TTMATH_LOGC("UInt::Rcr2_one", c) + + return c; + } + + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bits* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 + */ + template + uint UInt::Rcl2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits> move; + + for(i=0 ; i> move; + table[i] = (table[i] << bits) | c; + c = new_c; + } + + TTMATH_LOGC("UInt::Rcl2", c) + + return (c & 1); + } + + + + + /*! + this method moves all bits into the right hand side + C -> this -> return value + + the highest *bits* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 + */ + template + uint UInt::Rcr2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits=0 ; --i) + { + new_c = table[i] << move; + table[i] = (table[i] >> bits) | c; + c = new_c; + } + + TTMATH_LOGC("UInt::Rcr2", c) + + return (c & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; + } + + + + + /*! + this method returns the number of the highest set bit in x + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLeadingBitInWord(uint x) + { + if( x == 0 ) + return -1; + + uint bit = TTMATH_BITS_PER_UINT - 1; + + while( (x & TTMATH_UINT_HIGHEST_BIT) == 0 ) + { + x = x << 1; + --bit; + } + + return bit; + } + + + + /*! + this method returns the number of the highest set bit in x + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLowestBitInWord(uint x) + { + if( x == 0 ) + return -1; + + uint bit = 0; + + while( (x & 1) == 0 ) + { + x = x >> 1; + ++bit; + } + + return bit; + } + + + + /*! + this method sets a special bit in the 'value' + and returns the last state of the bit (zero or one) + + bit is from <0,TTMATH_BITS_PER_UINT-1> + + e.g. + uint x = 100; + uint bit = SetBitInWord(x, 3); + now: x = 108 and bit = 0 + */ + template + uint UInt::SetBitInWord(uint & value, uint bit) + { + TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) + + uint mask = 1; + + if( bit > 0 ) + mask = mask << bit; + + uint last = value & mask; + value = value | mask; + + return (last != 0) ? 1 : 0; + } + + + + + + + /*! + * + * Multiplication + * + * + */ + + + /*! + multiplication: result_high:result_low = a * b + result_high - higher word of the result + result_low - lower word of the result + + this methos never returns a carry + this method is used in the second version of the multiplication algorithms + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) + { + #ifdef TTMATH_PLATFORM32 + + /* + on 32bit platforms we have defined 'unsigned long long int' type known as 'ulint' in ttmath namespace + this type has 64 bits, then we're using only one multiplication: 32bit * 32bit = 64bit + */ + + union uint_ + { + struct + { + uint low; // 32 bits + uint high; // 32 bits + } u_; + + ulint u; // 64 bits + } res; + + res.u = ulint(a) * ulint(b); // multiply two 32bit words, the result has 64 bits + + *result_high = res.u_.high; + *result_low = res.u_.low; + + #else + + /* + 64 bits platforms + + we don't have a native type which has 128 bits + then we're splitting 'a' and 'b' to 4 parts (high and low halves) + and using 4 multiplications (with additions and carry correctness) + */ + + uint_ a_; + uint_ b_; + uint_ res_high1, res_high2; + uint_ res_low1, res_low2; + + a_.u = a; + b_.u = b; + + /* + the multiplication is as follows (schoolbook algorithm with O(n^2) ): + + 32 bits 32 bits + + +--------------------------------+ + | a_.u_.high | a_.u_.low | + +--------------------------------+ + | b_.u_.high | b_.u_.low | + +--------------------------------+--------------------------------+ + | res_high1.u | res_low1.u | + +--------------------------------+--------------------------------+ + | res_high2.u | res_low2.u | + +--------------------------------+--------------------------------+ + + 64 bits 64 bits + */ + + + uint_ temp; + + res_low1.u = uint(b_.u_.low) * uint(a_.u_.low); + + temp.u = uint(res_low1.u_.high) + uint(b_.u_.low) * uint(a_.u_.high); + res_low1.u_.high = temp.u_.low; + res_high1.u_.low = temp.u_.high; + res_high1.u_.high = 0; + + res_low2.u_.low = 0; + temp.u = uint(b_.u_.high) * uint(a_.u_.low); + res_low2.u_.high = temp.u_.low; + + res_high2.u = uint(b_.u_.high) * uint(a_.u_.high) + uint(temp.u_.high); + + uint c = AddTwoWords(res_low1.u, res_low2.u, 0, &res_low2.u); + AddTwoWords(res_high1.u, res_high2.u, c, &res_high2.u); // there is no carry from here + + *result_high = res_high2.u; + *result_low = res_low2.u; + + #endif + } + + + + + /*! + * + * Division + * + * + */ + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + * + * WARNING: + * the c has to be suitably large for the result being keeped in one word, + * if c is equal zero there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a, uint b, uint c, uint * r, uint * rest) + { + // (a < c ) for the result to be one word + TTMATH_ASSERT( c != 0 && a < c ) + + #ifdef TTMATH_PLATFORM32 + + union + { + struct + { + uint low; // 32 bits + uint high; // 32 bits + } u_; + + ulint u; // 64 bits + } ab; + + ab.u_.high = a; + ab.u_.low = b; + + *r = uint(ab.u / c); + *rest = uint(ab.u % c); + + #else + + uint_ c_; + c_.u = c; + + + if( a == 0 ) + { + *r = b / c; + *rest = b % c; + } + else + if( c_.u_.high == 0 ) + { + // higher half of 'c' is zero + // then higher half of 'a' is zero too (look at the asserts at the beginning - 'a' is smaller than 'c') + uint_ a_, b_, res_, temp1, temp2; + + a_.u = a; + b_.u = b; + + temp1.u_.high = a_.u_.low; + temp1.u_.low = b_.u_.high; + + res_.u_.high = (unsigned int)(temp1.u / c); + temp2.u_.high = (unsigned int)(temp1.u % c); + temp2.u_.low = b_.u_.low; + + res_.u_.low = (unsigned int)(temp2.u / c); + *rest = temp2.u % c; + + *r = res_.u; + } + else + { + return DivTwoWords2(a, b, c, r, rest); + } + + #endif + } + + +#ifdef TTMATH_PLATFORM64 + + + /*! + this method is available only on 64bit platforms + + the same algorithm like the third division algorithm in ttmathuint.h + but now with the radix=2^32 + */ + template + void UInt::DivTwoWords2(uint a, uint b, uint c, uint * r, uint * rest) + { + // a is not zero + // c_.u_.high is not zero + + uint_ a_, b_, c_, u_, q_; + unsigned int u3; // 32 bit + + a_.u = a; + b_.u = b; + c_.u = c; + + // normalizing + uint d = DivTwoWordsNormalize(a_, b_, c_); + + // loop from j=1 to j=0 + // the first step (for j=2) is skipped because our result is only in one word, + // (first 'q' were 0 and nothing would be changed) + u_.u_.high = a_.u_.high; + u_.u_.low = a_.u_.low; + u3 = b_.u_.high; + q_.u_.high = DivTwoWordsCalculate(u_, u3, c_); + MultiplySubtract(u_, u3, q_.u_.high, c_); + + u_.u_.high = u_.u_.low; + u_.u_.low = u3; + u3 = b_.u_.low; + q_.u_.low = DivTwoWordsCalculate(u_, u3, c_); + MultiplySubtract(u_, u3, q_.u_.low, c_); + + *r = q_.u; + + // unnormalizing for the remainder + u_.u_.high = u_.u_.low; + u_.u_.low = u3; + *rest = DivTwoWordsUnnormalize(u_.u, d); + } + + + + + template + uint UInt::DivTwoWordsNormalize(uint_ & a_, uint_ & b_, uint_ & c_) + { + uint d = 0; + + for( ; (c_.u & TTMATH_UINT_HIGHEST_BIT) == 0 ; ++d ) + { + c_.u = c_.u << 1; + + uint bc = b_.u & TTMATH_UINT_HIGHEST_BIT; // carry from 'b' + + b_.u = b_.u << 1; + a_.u = a_.u << 1; // carry bits from 'a' are simply skipped + + if( bc ) + a_.u = a_.u | 1; + } + + return d; + } + + + template + uint UInt::DivTwoWordsUnnormalize(uint u, uint d) + { + if( d == 0 ) + return u; + + u = u >> d; + + return u; + } + + + template + unsigned int UInt::DivTwoWordsCalculate(uint_ u_, unsigned int u3, uint_ v_) + { + bool next_test; + uint_ qp_, rp_, temp_; + + qp_.u = u_.u / uint(v_.u_.high); + rp_.u = u_.u % uint(v_.u_.high); + + TTMATH_ASSERT( qp_.u_.high==0 || qp_.u_.high==1 ) + + do + { + bool decrease = false; + + if( qp_.u_.high == 1 ) + decrease = true; + else + { + temp_.u_.high = rp_.u_.low; + temp_.u_.low = u3; + + if( qp_.u * uint(v_.u_.low) > temp_.u ) + decrease = true; + } + + next_test = false; + + if( decrease ) + { + --qp_.u; + rp_.u += v_.u_.high; + + if( rp_.u_.high == 0 ) + next_test = true; + } + } + while( next_test ); + + return qp_.u_.low; + } + + + template + void UInt::MultiplySubtract(uint_ & u_, unsigned int & u3, unsigned int & q, uint_ v_) + { + uint_ temp_; + + uint res_high; + uint res_low; + + MulTwoWords(v_.u, q, &res_high, &res_low); + + uint_ sub_res_high_; + uint_ sub_res_low_; + + temp_.u_.high = u_.u_.low; + temp_.u_.low = u3; + + uint c = SubTwoWords(temp_.u, res_low, 0, &sub_res_low_.u); + + temp_.u_.high = 0; + temp_.u_.low = u_.u_.high; + c = SubTwoWords(temp_.u, res_high, c, &sub_res_high_.u); + + if( c ) + { + --q; + + c = AddTwoWords(sub_res_low_.u, v_.u, 0, &sub_res_low_.u); + AddTwoWords(sub_res_high_.u, 0, c, &sub_res_high_.u); + } + + u_.u_.high = sub_res_high_.u_.low; + u_.u_.low = sub_res_low_.u_.high; + u3 = sub_res_low_.u_.low; + } + +#endif // #ifdef TTMATH_PLATFORM64 + + + +} //namespace + + +#endif //ifdef TTMATH_NOASM +#endif + + + + diff --git a/ttmath/ttmathuint_x86.h b/ttmath/ttmathuint_x86.h new file mode 100644 index 0000000..1dd087f --- /dev/null +++ b/ttmath/ttmathuint_x86.h @@ -0,0 +1,1602 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + + +#ifndef headerfilettmathuint_x86 +#define headerfilettmathuint_x86 + + +#ifndef TTMATH_NOASM +#ifdef TTMATH_PLATFORM32 + + +/*! + \file ttmathuint_x86.h + \brief template class UInt with assembler code for 32bit x86 processors + + this file is included at the end of ttmathuint.h +*/ + + + +/*! + \brief a namespace for the TTMath library +*/ +namespace ttmath +{ + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + template + const char * UInt::LibTypeStr() + { + #ifndef __GNUC__ + static const char info[] = "asm_vc_32"; + #endif + + #ifdef __GNUC__ + static const char info[] = "asm_gcc_32"; + #endif + + return info; + } + + + /*! + returning the currect type of the library + */ + template + LibTypeCode UInt::LibType() + { + #ifndef __GNUC__ + LibTypeCode info = asm_vc_32; + #endif + + #ifdef __GNUC__ + LibTypeCode info = asm_gcc_32; + #endif + + return info; + } + + + + /*! + * + * basic mathematic functions + * + */ + + + /*! + adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it has been) + */ + template + uint UInt::Add(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + uint * p2 = const_cast(ss2.table); + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #ifndef __GNUC__ + + // this part might be compiled with for example visual c + + __asm + { + push eax + push ebx + push ecx + push edx + push esi + + mov ecx,[b] + + mov ebx,[p1] + mov esi,[p2] + + xor edx,edx // edx=0 + mov eax,[c] + neg eax // CF=1 if rax!=0 , CF=0 if rax==0 + + ttmath_loop: + mov eax,[esi+edx*4] + adc [ebx+edx*4],eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop esi + pop edx + pop ecx + pop ebx + pop eax + } + + + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + // this part should be compiled with gcc + + __asm__ __volatile__( + + "xorl %%edx, %%edx \n" + "negl %%eax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movl (%%esi,%%edx,4), %%eax \n" + "adcl %%eax, (%%ebx,%%edx,4) \n" + + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + #endif + + TTMATH_LOGC("UInt::Add", c) + + return c; + } + + + + /*! + adding one word (at a specific position) + and returning a carry (if it has been) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + AddInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 + 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::AddInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov edx, [index] + mov ebx, [p1] + + mov eax, [value] + + ttmath_loop: + add [ebx+edx*4], eax + jnc ttmath_end + + mov eax, 1 + inc edx + dec ecx + jnz ttmath_loop + + ttmath_end: + setc al + movzx edx, al + mov [c], edx + + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subl %%edx, %%ecx \n" + + "1: \n" + "addl %%eax, (%%ebx,%%edx,4) \n" + "jnc 2f \n" + + "movl $1, %%eax \n" + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%edx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddInt", c) + + return c; + } + + + + + /*! + adding only two unsigned words to the existing value + and these words begin on the 'index' position + (it's used in the multiplication algorithm 2) + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + for example if we've got value_size equal 4 and: + table[0] = 3 + table[1] = 4 + table[2] = 5 + table[3] = 6 + then let + x1 = 10 + x2 = 20 + and + index = 1 + + the result of this method will be: + table[0] = 3 + table[1] = 4 + x1 = 14 + table[2] = 5 + x2 = 25 + table[3] = 6 + + and no carry at the end of table[3] + + (of course if there was a carry in table[2](5+20) then + this carry would be passed to the table[3] etc.) + */ + template + uint UInt::AddTwoInts(uint x2, uint x1, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size - 1 ) + + #ifndef __GNUC__ + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov ebx, [p1] + mov edx, [index] + + mov eax, [x1] + add [ebx+edx*4], eax + inc edx + dec ecx + + mov eax, [x2] + + ttmath_loop: + adc [ebx+edx*4], eax + jnc ttmath_end + + mov eax, 0 + inc edx + dec ecx + jnz ttmath_loop + + ttmath_end: + setc al + movzx edx, al + mov [c], edx + + pop edx + pop ecx + pop ebx + pop eax + + } + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subl %%edx, %%ecx \n" + + "addl %%esi, (%%ebx,%%edx,4) \n" + "incl %%edx \n" + "decl %%ecx \n" + + "1: \n" + "adcl %%eax, (%%ebx,%%edx,4) \n" + "jnc 2f \n" + + "mov $0, %%eax \n" + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%eax \n" + + : "=a" (c), "=c" (dummy), "=d" (dummy2) + : "0" (x2), "1" (b), "2" (index), "b" (p1), "S" (x1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddTwoInts", c) + + return c; + } + + + + /*! + this static method addes one vector to the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5+1 + 4 3 4+3 + 2 7 2+7 + 6 6 + 9 9 + of course the carry is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint rest = ss1_size - ss2_size; + uint c; + + #ifndef __GNUC__ + + // this part might be compiled with for example visual c + __asm + { + pushad + + mov ecx, [ss2_size] + xor edx, edx // edx = 0, cf = 0 + + mov esi, [ss1] + mov ebx, [ss2] + mov edi, [result] + + ttmath_loop: + mov eax, [esi+edx*4] + adc eax, [ebx+edx*4] + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx // ecx has the cf state + + mov ebx, [rest] + or ebx, ebx + jz ttmath_end + + xor ebx, ebx // ebx = 0 + neg ecx // setting cf from ecx + mov ecx, [rest] // ecx is != 0 + + ttmath_loop2: + mov eax, [esi+edx*4] + adc eax, ebx + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop2 + + adc ecx, ecx + + ttmath_end: + mov [c], ecx + + popad + } + + #endif + + + #ifdef __GNUC__ + + // this part should be compiled with gcc + uint dummy1, dummy2, dummy3; + + __asm__ __volatile__( + "push %%edx \n" + "xor %%edx, %%edx \n" // edx = 0, cf = 0 + "1: \n" + "mov (%%esi,%%edx,4), %%eax \n" + "adc (%%ebx,%%edx,4), %%eax \n" + "mov %%eax, (%%edi,%%edx,4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" // ecx has the cf state + "pop %%eax \n" // eax = rest + + "or %%eax, %%eax \n" + "jz 3f \n" + + "xor %%ebx, %%ebx \n" // ebx = 0 + "neg %%ecx \n" // setting cf from ecx + "mov %%eax, %%ecx \n" // ecx=rest and is != 0 + "2: \n" + "mov (%%esi, %%edx, 4), %%eax \n" + "adc %%ebx, %%eax \n" + "mov %%eax, (%%edi, %%edx, 4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 2b \n" + + "adc %%ecx, %%ecx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::AddVector", c, result, ss1_size) + + return c; + } + + + /*! + subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it has been) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + uint * p2 = const_cast(ss2.table); + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + push esi + + mov ecx,[b] + + mov ebx,[p1] + mov esi,[p2] + + xor edx,edx // edx=0 + mov eax,[c] + neg eax // CF=1 if rax!=0 , CF=0 if rax==0 + + ttmath_loop: + mov eax,[esi+edx*4] + sbb [ebx+edx*4],eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop esi + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorl %%edx, %%edx \n" + "negl %%eax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movl (%%esi,%%edx,4), %%eax \n" + "sbbl %%eax, (%%ebx,%%edx,4) \n" + + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Sub", c) + + return c; + } + + + + + /*! + this method subtracts one word (at a specific position) + and returns a carry (if it was) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + SubInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 - 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::SubInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov edx, [index] + mov ebx, [p1] + + mov eax, [value] + + ttmath_loop: + sub [ebx+edx*4], eax + jnc ttmath_end + + mov eax, 1 + inc edx + dec ecx + jnz ttmath_loop + + ttmath_end: + setc al + movzx edx, al + mov [c], edx + + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subl %%edx, %%ecx \n" + + "1: \n" + "subl %%eax, (%%ebx,%%edx,4) \n" + "jnc 2f \n" + + "movl $1, %%eax \n" + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%edx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::SubInt", c) + + return c; + } + + + + /*! + this static method subtractes one vector from the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5-1 + 4 3 4-3 + 2 7 2-7 + 6 6-1 (the borrow from previous item) + 9 9 + return (carry): 0 + of course the carry (borrow) is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint rest = ss1_size - ss2_size; + uint c; + + #ifndef __GNUC__ + + // this part might be compiled with for example visual c + + /* + the asm code is nearly the same as in AddVector + only two instructions 'adc' are changed to 'sbb' + */ + __asm + { + pushad + + mov ecx, [ss2_size] + xor edx, edx // edx = 0, cf = 0 + + mov esi, [ss1] + mov ebx, [ss2] + mov edi, [result] + + ttmath_loop: + mov eax, [esi+edx*4] + sbb eax, [ebx+edx*4] + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx // ecx has the cf state + + mov ebx, [rest] + or ebx, ebx + jz ttmath_end + + xor ebx, ebx // ebx = 0 + neg ecx // setting cf from ecx + mov ecx, [rest] // ecx is != 0 + + ttmath_loop2: + mov eax, [esi+edx*4] + sbb eax, ebx + mov [edi+edx*4], eax + + inc edx + dec ecx + jnz ttmath_loop2 + + adc ecx, ecx + + ttmath_end: + mov [c], ecx + + popad + } + + #endif + + + #ifdef __GNUC__ + + // this part should be compiled with gcc + uint dummy1, dummy2, dummy3; + + __asm__ __volatile__( + "push %%edx \n" + "xor %%edx, %%edx \n" // edx = 0, cf = 0 + "1: \n" + "mov (%%esi,%%edx,4), %%eax \n" + "sbb (%%ebx,%%edx,4), %%eax \n" + "mov %%eax, (%%edi,%%edx,4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 1b \n" + + "adc %%ecx, %%ecx \n" // ecx has the cf state + "pop %%eax \n" // eax = rest + + "or %%eax, %%eax \n" + "jz 3f \n" + + "xor %%ebx, %%ebx \n" // ebx = 0 + "neg %%ecx \n" // setting cf from ecx + "mov %%eax, %%ecx \n" // ecx=rest and is != 0 + "2: \n" + "mov (%%esi, %%edx, 4), %%eax \n" + "sbb %%ebx, %%eax \n" + "mov %%eax, (%%edi, %%edx, 4) \n" + + "inc %%edx \n" + "dec %%ecx \n" + "jnz 2b \n" + + "adc %%ecx, %%ecx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::SubVector", c, result, ss1_size) + + return c; + } + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bit* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 + */ + template + uint UInt::Rcl2_one(uint c) + { + uint b = value_size; + uint * p1 = table; + + #ifndef __GNUC__ + __asm + { + push ebx + push ecx + push edx + + mov ebx, [p1] + xor edx, edx + mov ecx, [c] + neg ecx + mov ecx, [b] + + ttmath_loop: + rcl dword ptr [ebx+edx*4], 1 + + inc edx + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop edx + pop ecx + pop ebx + } + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorl %%edx, %%edx \n" // edx=0 + "negl %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 + + "1: \n" + "rcll $1, (%%ebx, %%edx, 4) \n" + + "incl %%edx \n" + "decl %%ecx \n" + "jnz 1b \n" + + "adcl %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcl2_one", c) + + return c; + } + + + + /*! + this method moves all bits into the right hand side + c -> this -> return value + + the highest *bit* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 + */ + template + uint UInt::Rcr2_one(uint c) + { + uint b = value_size; + uint * p1 = table; + + #ifndef __GNUC__ + __asm + { + push ebx + push ecx + + mov ebx, [p1] + mov ecx, [c] + neg ecx + mov ecx, [b] + + ttmath_loop: + rcr dword ptr [ebx+ecx*4-4], 1 + + dec ecx + jnz ttmath_loop + + adc ecx, ecx + mov [c], ecx + + pop ecx + pop ebx + } + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ __volatile__( + + "negl %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 + + "1: \n" + "rcrl $1, -4(%%ebx, %%ecx, 4) \n" + + "decl %%ecx \n" + "jnz 1b \n" + + "adcl %%ecx, %%ecx \n" + + : "=c" (c), "=a" (dummy) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcr2_one", c) + + return c; + } + + + +#ifdef _MSC_VER +#pragma warning (disable : 4731) +//warning C4731: frame pointer register 'ebp' modified by inline assembly code +#endif + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bits* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 + */ + template + uint UInt::Rcl2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits edx -> cf) (cl times) + "movl %%edx, %%ebp \n" // ebp = edx = mask + "movl %%esi, %%ecx \n" + + "xorl %%edx, %%edx \n" + "movl %%edx, %%esi \n" + "orl %%eax, %%eax \n" + "cmovnz %%ebp, %%esi \n" // if(c) esi=mask else esi=0 + + "1: \n" + "roll %%cl, (%%ebx,%%edx,4) \n" + + "movl (%%ebx,%%edx,4), %%eax \n" + "andl %%ebp, %%eax \n" + "xorl %%eax, (%%ebx,%%edx,4) \n" + "orl %%esi, (%%ebx,%%edx,4) \n" + "movl %%eax, %%esi \n" + + "incl %%edx \n" + "decl %%edi \n" + "jnz 1b \n" + + "and $1, %%eax \n" + + "pop %%ebp \n" + + : "=a" (c), "=D" (dummy), "=S" (dummy2), "=d" (dummy3) + : "0" (c), "1" (b), "b" (p1), "c" (bits) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcl2", c) + + return c; + } + + + + + /*! + this method moves all bits into the right hand side + C -> this -> return value + + the highest *bits* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 + */ + template + uint UInt::Rcr2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits + sint UInt::FindLeadingBitInWord(uint x) + { + sint result; + + #ifndef __GNUC__ + __asm + { + push eax + push edx + + mov edx,-1 + bsr eax,[x] + cmovz eax,edx + mov [result], eax + + pop edx + pop eax + } + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movl $-1, %1 \n" + "bsrl %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + return result; + } + + + + /* + this method returns the number of the smallest set bit in one 32-bit word + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLowestBitInWord(uint x) + { + sint result; + + #ifndef __GNUC__ + __asm + { + push eax + push edx + + mov edx,-1 + bsf eax,[x] + cmovz eax,edx + mov [result], eax + + pop edx + pop eax + } + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movl $-1, %1 \n" + "bsfl %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + return result; + } + + + + /*! + this method sets a special bit in the 'value' + and returns the last state of the bit (zero or one) + + bit is from <0,31> + e.g. + uint x = 100; + uint bit = SetBitInWord(x, 3); + now: x = 108 and bit = 0 + */ + template + uint UInt::SetBitInWord(uint & value, uint bit) + { + TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) + + uint old_bit; + uint v = value; + + #ifndef __GNUC__ + __asm + { + push ebx + push eax + + mov eax, [v] + mov ebx, [bit] + bts eax, ebx + mov [v], eax + + setc bl + movzx ebx, bl + mov [old_bit], ebx + + pop eax + pop ebx + } + #endif + + + #ifdef __GNUC__ + __asm__ ( + + "btsl %%ebx, %%eax \n" + "setc %%bl \n" + "movzx %%bl, %%ebx \n" + + : "=a" (v), "=b" (old_bit) + : "0" (v), "1" (bit) + : "cc" ); + + #endif + + value = v; + + return old_bit; + } + + + + + /*! + multiplication: result_high:result_low = a * b + result_high - higher word of the result + result_low - lower word of the result + + this methos never returns a carry + this method is used in the second version of the multiplication algorithms + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) + { + /* + we must use these temporary variables in order to inform the compilator + that value pointed with result1 and result2 has changed + + this has no effect in visual studio but it's useful when + using gcc and options like -Ox + */ + uint result1_; + uint result2_; + + #ifndef __GNUC__ + + __asm + { + push eax + push edx + + mov eax, [a] + mul dword ptr [b] + + mov [result2_], edx + mov [result1_], eax + + pop edx + pop eax + } + + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "mull %%edx \n" + + : "=a" (result1_), "=d" (result2_) + : "0" (a), "1" (b) + : "cc" ); + + #endif + + + *result_low = result1_; + *result_high = result2_; + } + + + + + + /*! + * + * Division + * + * + */ + + + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + * + * WARNING: + * if r (one word) is too small for the result or c is equal zero + * there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a, uint b, uint c, uint * r, uint * rest) + { + uint r_; + uint rest_; + /* + these variables have similar meaning like those in + the multiplication algorithm MulTwoWords + */ + + TTMATH_ASSERT( c != 0 ) + + #ifndef __GNUC__ + __asm + { + push eax + push edx + + mov edx, [a] + mov eax, [b] + div dword ptr [c] + + mov [r_], eax + mov [rest_], edx + + pop edx + pop eax + } + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "divl %%ecx \n" + + : "=a" (r_), "=d" (rest_) + : "0" (b), "1" (a), "c" (c) + : "cc" ); + + #endif + + + *r = r_; + *rest = rest_; + + } + + + +} //namespace + + + +#endif //ifdef TTMATH_PLATFORM32 +#endif //ifndef TTMATH_NOASM +#endif diff --git a/ttmath/ttmathuint_x86_64.h b/ttmath/ttmathuint_x86_64.h new file mode 100644 index 0000000..2fedb70 --- /dev/null +++ b/ttmath/ttmathuint_x86_64.h @@ -0,0 +1,1222 @@ +/* + * This file is a part of TTMath Bignum Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2009, Tomasz Sowa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * * Neither the name Tomasz Sowa nor the names of contributors to this + * project may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef headerfilettmathuint_x86_64 +#define headerfilettmathuint_x86_64 + + +#ifndef TTMATH_NOASM +#ifdef TTMATH_PLATFORM64 + + +/*! + \file ttmathuint_x86_64.h + \brief template class UInt with assembler code for 64bit x86_64 processors + + this file is included at the end of ttmathuint.h +*/ + +#ifdef _MSC_VER +#include +#endif + + +namespace ttmath +{ + + #ifdef _MSC_VER + + extern "C" + { + uint __fastcall ttmath_adc_x64(uint* p1, const uint* p2, uint nSize, uint c); + uint __fastcall ttmath_addindexed_x64(uint* p1, uint nSize, uint nPos, uint nValue); + uint __fastcall ttmath_addindexed2_x64(uint* p1, uint nSize, uint nPos, uint nValue1, uint nValue2); + uint __fastcall ttmath_addvector_x64(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + uint __fastcall ttmath_sbb_x64(uint* p1, const uint* p2, uint nSize, uint c); + uint __fastcall ttmath_subindexed_x64(uint* p1, uint nSize, uint nPos, uint nValue); + uint __fastcall ttmath_subvector_x64(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result); + uint __fastcall ttmath_rcl_x64(uint* p1, uint nSize, uint nLowestBit); + uint __fastcall ttmath_rcr_x64(uint* p1, uint nSize, uint nLowestBit); + uint __fastcall ttmath_div_x64(uint* pnValHi, uint* pnValLo, uint nDiv); + uint __fastcall ttmath_rcl2_x64(uint* p1, uint nSize, uint nBits, uint c); + uint __fastcall ttmath_rcr2_x64(uint* p1, uint nSize, uint nBits, uint c); + }; + #endif + + + /*! + returning the string represents the currect type of the library + we have following types: + asm_vc_32 - with asm code designed for Microsoft Visual C++ (32 bits) + asm_gcc_32 - with asm code designed for GCC (32 bits) + asm_vc_64 - with asm for VC (64 bit) + asm_gcc_64 - with asm for GCC (64 bit) + no_asm_32 - pure C++ version (32 bit) - without any asm code + no_asm_64 - pure C++ version (64 bit) - without any asm code + */ + template + const char * UInt::LibTypeStr() + { + #ifdef _MSC_VER + static const char info[] = "asm_vc_64"; + #endif + + #ifdef __GNUC__ + static const char info[] = "asm_gcc_64"; + #endif + + return info; + } + + + /*! + returning the currect type of the library + */ + template + LibTypeCode UInt::LibType() + { + #ifdef _MSC_VER + LibTypeCode info = asm_vc_64; + #endif + + #ifdef __GNUC__ + LibTypeCode info = asm_gcc_64; + #endif + + return info; + } + + + /*! + * + * basic mathematic functions + * + */ + + + + /*! + this method adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + ***this method is created only on a 64bit platform*** + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Add(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + const uint * p2 = ss2.table; + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + #ifdef _MSC_VER + c = ttmath_adc_x64(p1,p2,b,c); + #endif + + #ifdef __GNUC__ + uint dummy, dummy2; + + /* + this part should be compiled with gcc + */ + __asm__ __volatile__( + + "xorq %%rdx, %%rdx \n" + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movq (%%rsi,%%rdx,8), %%rax \n" + "adcq %%rax, (%%rbx,%%rdx,8) \n" + + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Add", c) + + return c; + } + + + + /*! + this method adds one word (at a specific position) + and returns a carry (if it was) + + ***this method is created only on a 64bit platform*** + + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + AddInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 + 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::AddInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_addindexed_x64(p1,b,index,value); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subq %%rdx, %%rcx \n" + + "1: \n" + "addq %%rax, (%%rbx,%%rdx,8) \n" + "jnc 2f \n" + + "movq $1, %%rax \n" + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%rdx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddInt", c) + + return c; + } + + + + /*! + this method adds only two unsigned words to the existing value + and these words begin on the 'index' position + (it's used in the multiplication algorithm 2) + + ***this method is created only on a 64bit platform*** + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + for example if we've got value_size equal 4 and: + table[0] = 3 + table[1] = 4 + table[2] = 5 + table[3] = 6 + then let + x1 = 10 + x2 = 20 + and + index = 1 + + the result of this method will be: + table[0] = 3 + table[1] = 4 + x1 = 14 + table[2] = 5 + x2 = 25 + table[3] = 6 + + and no carry at the end of table[3] + + (of course if there was a carry in table[2](5+20) then + this carry would be passed to the table[3] etc.) + */ + template + uint UInt::AddTwoInts(uint x2, uint x1, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size - 1 ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_addindexed2_x64(p1,b,index,x1,x2); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subq %%rdx, %%rcx \n" + + "addq %%rsi, (%%rbx,%%rdx,8) \n" + "incq %%rdx \n" + "decq %%rcx \n" + + "1: \n" + "adcq %%rax, (%%rbx,%%rdx,8) \n" + "jnc 2f \n" + + "mov $0, %%rax \n" + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%rax \n" + + : "=a" (c), "=c" (dummy), "=d" (dummy2) + : "0" (x2), "1" (b), "2" (index), "b" (p1), "S" (x1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::AddTwoInts", c) + + return c; + } + + + + /*! + this static method addes one vector to the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5+1 + 4 3 4+3 + 2 7 2+7 + 6 6 + 9 9 + of course the carry is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::AddVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint c; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_addvector_x64(ss1, ss2, ss1_size, ss2_size, result); + #endif + + + #ifdef __GNUC__ + uint dummy1, dummy2, dummy3; + uint rest = ss1_size - ss2_size; + + // this part should be compiled with gcc + + __asm__ __volatile__( + "mov %%rdx, %%r8 \n" + "xor %%rdx, %%rdx \n" // rdx = 0, cf = 0 + "1: \n" + "mov (%%rsi,%%rdx,8), %%rax \n" + "adc (%%rbx,%%rdx,8), %%rax \n" + "mov %%rax, (%%rdi,%%rdx,8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 1b \n" + + "adc %%rcx, %%rcx \n" // rcx has the cf state + + "or %%r8, %%r8 \n" + "jz 3f \n" + + "xor %%rbx, %%rbx \n" // ebx = 0 + "neg %%rcx \n" // setting cf from rcx + "mov %%r8, %%rcx \n" // rcx=rest and is != 0 + "2: \n" + "mov (%%rsi, %%rdx, 8), %%rax \n" + "adc %%rbx, %%rax \n" + "mov %%rax, (%%rdi, %%rdx, 8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 2b \n" + + "adc %%rcx, %%rcx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "%r8", "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::AddVector", c, result, ss1_size) + + return c; + } + + + + /*! + this method's subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + ***this method is created only on a 64bit platform*** + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + uint b = value_size; + uint * p1 = table; + const uint * p2 = ss2.table; + + + // we don't have to use TTMATH_REFERENCE_ASSERT here + // this algorithm doesn't require it + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_sbb_x64(p1,p2,b,c); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorq %%rdx, %%rdx \n" + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "movq (%%rsi,%%rdx,8), %%rax \n" + "sbbq %%rax, (%%rbx,%%rdx,8) \n" + + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1), "S" (p2) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Sub", c) + + return c; + } + + + + /*! + this method subtracts one word (at a specific position) + and returns a carry (if it was) + + ***this method is created only on a 64bit platform*** + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + SubInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 - 2; + table[2] = 5; + + of course if there was a carry from table[2] it would be returned + */ + template + uint UInt::SubInt(uint value, uint index) + { + uint b = value_size; + uint * p1 = table; + uint c; + + TTMATH_ASSERT( index < value_size ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_subindexed_x64(p1,b,index,value); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "subq %%rdx, %%rcx \n" + + "1: \n" + "subq %%rax, (%%rbx,%%rdx,8) \n" + "jnc 2f \n" + + "movq $1, %%rax \n" + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "2: \n" + "setc %%al \n" + "movzx %%al, %%rdx \n" + + : "=d" (c), "=a" (dummy), "=c" (dummy2) + : "0" (index), "1" (value), "2" (b), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::SubInt", c) + + return c; + } + + + /*! + this static method subtractes one vector from the other + 'ss1' is larger in size or equal to 'ss2' + + ss1 points to the first (larger) vector + ss2 points to the second vector + ss1_size - size of the ss1 (and size of the result too) + ss2_size - size of the ss2 + result - is the result vector (which has size the same as ss1: ss1_size) + + Example: ss1_size is 5, ss2_size is 3 + ss1: ss2: result (output): + 5 1 5-1 + 4 3 4-3 + 2 7 2-7 + 6 6-1 (the borrow from previous item) + 9 9 + return (carry): 0 + of course the carry (borrow) is propagated and will be returned from the last item + (this method is used by the Karatsuba multiplication algorithm) + */ + template + uint UInt::SubVector(const uint * ss1, const uint * ss2, uint ss1_size, uint ss2_size, uint * result) + { + TTMATH_ASSERT( ss1_size >= ss2_size ) + + uint c; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_subvector_x64(ss1, ss2, ss1_size, ss2_size, result); + #endif + + + #ifdef __GNUC__ + + // the asm code is nearly the same as in AddVector + // only two instructions 'adc' are changed to 'sbb' + + uint dummy1, dummy2, dummy3; + uint rest = ss1_size - ss2_size; + + __asm__ __volatile__( + "mov %%rdx, %%r8 \n" + "xor %%rdx, %%rdx \n" // rdx = 0, cf = 0 + "1: \n" + "mov (%%rsi,%%rdx,8), %%rax \n" + "sbb (%%rbx,%%rdx,8), %%rax \n" + "mov %%rax, (%%rdi,%%rdx,8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 1b \n" + + "adc %%rcx, %%rcx \n" // rcx has the cf state + + "or %%r8, %%r8 \n" + "jz 3f \n" + + "xor %%rbx, %%rbx \n" // ebx = 0 + "neg %%rcx \n" // setting cf from rcx + "mov %%r8, %%rcx \n" // rcx=rest and is != 0 + "2: \n" + "mov (%%rsi, %%rdx, 8), %%rax \n" + "sbb %%rbx, %%rax \n" + "mov %%rax, (%%rdi, %%rdx, 8) \n" + + "inc %%rdx \n" + "dec %%rcx \n" + "jnz 2b \n" + + "adc %%rcx, %%rcx \n" + "3: \n" + + : "=a" (dummy1), "=b" (dummy2), "=c" (c), "=d" (dummy3) + : "1" (ss2), "2" (ss2_size), "3" (rest), "S" (ss1), "D" (result) + : "%r8", "cc", "memory" ); + + #endif + + TTMATH_VECTOR_LOGC("UInt::SubVector", c, result, ss1_size) + + return c; + } + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bit* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcl2_one(uint c) + { + sint b = value_size; + uint * p1 = table; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_rcl_x64(p1,b,c); + #endif + + + #ifdef __GNUC__ + uint dummy, dummy2; + + __asm__ __volatile__( + + "xorq %%rdx, %%rdx \n" // rdx=0 + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "rclq $1, (%%rbx, %%rdx, 8) \n" + + "incq %%rdx \n" + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy), "=d" (dummy2) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcl2_one", c) + + return c; + } + + + /*! + this method moves all bits into the right hand side + c -> this -> return value + + the highest *bit* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcr2_one(uint c) + { + sint b = value_size; + uint * p1 = table; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + c = ttmath_rcr_x64(p1,b,c); + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ __volatile__( + + "negq %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0 + + "1: \n" + "rcrq $1, -8(%%rbx, %%rcx, 8) \n" + + "decq %%rcx \n" + "jnz 1b \n" + + "adcq %%rcx, %%rcx \n" + + : "=c" (c), "=a" (dummy) + : "0" (b), "1" (c), "b" (p1) + : "cc", "memory" ); + + #endif + + TTMATH_LOGC("UInt::Rcr2_one", c) + + return c; + } + + + + /*! + this method moves all bits into the left hand side + return value <- this <- c + + the lowest *bits* will be held the 'c' and + the state of one additional bit (on the left hand side) + will be returned + + for example: + let this is 001010000 + after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcl2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits this -> return value + + the highest *bits* will be held the 'c' and + the state of one additional bit (on the right hand side) + will be returned + + for example: + let this is 000000010 + after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 + + ***this method is created only on a 64bit platform*** + */ + template + uint UInt::Rcr2(uint bits, uint c) + { + TTMATH_ASSERT( bits>0 && bits + sint UInt::FindLeadingBitInWord(uint x) + { + sint result; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + + unsigned long nIndex = 0; + + if( _BitScanReverse64(&nIndex,x) == 0 ) + result = -1; + else + result = nIndex; + + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movq $-1, %1 \n" + "bsrq %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + + return result; + } + + + /* + this method returns the number of the highest set bit in one 64-bit word + if the 'x' is zero this method returns '-1' + + ***this method is created only on a 64bit platform*** + */ + template + sint UInt::FindLowestBitInWord(uint x) + { + sint result; + + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + + unsigned long nIndex = 0; + + if( _BitScanForward64(&nIndex,x) == 0 ) + result = -1; + else + result = nIndex; + + #endif + + + #ifdef __GNUC__ + uint dummy; + + __asm__ ( + + "movq $-1, %1 \n" + "bsfq %2, %0 \n" + "cmovz %1, %0 \n" + + : "=r" (result), "=&r" (dummy) + : "r" (x) + : "cc" ); + + #endif + + + return result; + } + + + /*! + this method sets a special bit in the 'value' + and returns the last state of the bit (zero or one) + + ***this method is created only on a 64bit platform*** + + bit is from <0,63> + + e.g. + uint x = 100; + uint bit = SetBitInWord(x, 3); + now: x = 108 and bit = 0 + */ + template + uint UInt::SetBitInWord(uint & value, uint bit) + { + TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT ) + + uint old_bit; + uint v = value; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + old_bit = _bittestandset64((__int64*)&value,bit) != 0; + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "btsq %%rbx, %%rax \n" + "setc %%bl \n" + "movzx %%bl, %%rbx \n" + + : "=a" (v), "=b" (old_bit) + : "0" (v), "1" (bit) + : "cc" ); + + #endif + + value = v; + + return old_bit; + } + + + /*! + * + * Multiplication + * + * + */ + + + /*! + multiplication: result_high:result_low = a * b + result_high - higher word of the result + result_low - lower word of the result + + this methos never returns a carry + this method is used in the second version of the multiplication algorithms + + ***this method is created only on a 64bit platform*** + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result_high, uint * result_low) + { + /* + we must use these temporary variables in order to inform the compilator + that value pointed with result1 and result2 has changed + + this has no effect in visual studio but it's usefull when + using gcc and options like -O + */ + uint result1_; + uint result2_; + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + result1_ = _umul128(a,b,&result2_); + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "mulq %%rdx \n" + + : "=a" (result1_), "=d" (result2_) + : "0" (a), "1" (b) + : "cc" ); + + #endif + + + *result_low = result1_; + *result_high = result2_; + } + + + + + /*! + * + * Division + * + * + */ + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + ***this method is created only on a 64bit platform*** + + * + * WARNING: + * if r (one word) is too small for the result or c is equal zero + * there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest) + { + uint r_; + uint rest_; + /* + these variables have similar meaning like those in + the multiplication algorithm MulTwoWords + */ + + TTMATH_ASSERT( c != 0 ) + + #if !defined(__GNUC__) && !defined(_MSC_VER) + #error "another compiler than GCC or Microsoft VC is currently not supported in 64bit mode, you can compile with TTMATH_NOASM macro" + #endif + + + #ifdef _MSC_VER + + ttmath_div_x64(&a,&b,c); + r_ = a; + rest_ = b; + + #endif + + + #ifdef __GNUC__ + + __asm__ ( + + "divq %%rcx \n" + + : "=a" (r_), "=d" (rest_) + : "d" (a), "a" (b), "c" (c) + : "cc" ); + + #endif + + + *r = r_; + *rest = rest_; + } + +} //namespace + + +#endif //ifdef TTMATH_PLATFORM64 +#endif //ifndef TTMATH_NOASM +#endif + + diff --git a/ttmath/ttmathuint_x86_64_msvc.asm b/ttmath/ttmathuint_x86_64_msvc.asm new file mode 100644 index 0000000..d2ea969 --- /dev/null +++ b/ttmath/ttmathuint_x86_64_msvc.asm @@ -0,0 +1,548 @@ +; +; This file is a part of TTMath Bignum Library +; and is distributed under the (new) BSD licence. +; Author: Christian Kaiser +; + +; +; Copyright (c) 2009, Christian Kaiser +; All rights reserved. +; +; Redistribution and use in source and binary forms, with or without +; modification, are permitted provided that the following conditions are met: +; +; * Redistributions of source code must retain the above copyright notice, +; this list of conditions and the following disclaimer. +; +; * Redistributions in binary form must reproduce the above copyright +; notice, this list of conditions and the following disclaimer in the +; documentation and/or other materials provided with the distribution. +; +; * Neither the name Christian Kaiser nor the names of contributors to this +; project may be used to endorse or promote products derived +; from this software without specific prior written permission. +; +; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +; THE POSSIBILITY OF SUCH DAMAGE. +; + +; +; compile with debug info: ml64.exe /Zd /Zi ttmathuint_x86_64_msvc.asm +; compile without debug info: ml64.exe ttmathuint_x86_64_msvc.asm +; this create ttmathuint_x86_64_msvc.obj file which can be linked with your program +; + +PUBLIC ttmath_adc_x64 +PUBLIC ttmath_addindexed_x64 +PUBLIC ttmath_addindexed2_x64 +PUBLIC ttmath_addvector_x64 + +PUBLIC ttmath_sbb_x64 +PUBLIC ttmath_subindexed_x64 +PUBLIC ttmath_subvector_x64 + +PUBLIC ttmath_rcl_x64 +PUBLIC ttmath_rcr_x64 + +PUBLIC ttmath_rcl2_x64 +PUBLIC ttmath_rcr2_x64 + +PUBLIC ttmath_div_x64 + +; +; Microsoft x86_64 convention: http://msdn.microsoft.com/en-us/library/9b372w95.aspx +; +; "rax, rcx, rdx, r8-r11 are volatile." +; "rbx, rbp, rdi, rsi, r12-r15 are nonvolatile." +; + + +.CODE + + + ALIGN 8 + +;---------------------------------------- + +ttmath_adc_x64 PROC + ; rcx = p1 + ; rdx = p2 + ; r8 = nSize + ; r9 = nCarry + + xor rax, rax + xor r11, r11 + sub rax, r9 ; sets CARRY if r9 != 0 + + ALIGN 16 + loop1: + mov rax,qword ptr [rdx + r11 * 8] + adc qword ptr [rcx + r11 * 8], rax + lea r11, [r11+1] + dec r8 + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_adc_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_addindexed_x64 PROC + + ; rcx = p1 + ; rdx = nSize + ; r8 = nPos + ; r9 = nValue + + xor rax, rax ; rax = result + sub rdx, r8 ; rdx = remaining count of uints + + add qword ptr [rcx + r8 * 8], r9 + jc next1 + + ret + +next1: + mov r9, 1 + + ALIGN 16 +loop1: + dec rdx + jz done_with_cy + lea r8, [r8+1] + add qword ptr [rcx + r8 * 8], r9 + jc loop1 + + ret + +done_with_cy: + lea rax, [rax+1] ; rax = 1 + + ret + +ttmath_addindexed_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_addindexed2_x64 PROC + + ; rcx = p1 (pointer) + ; rdx = b (value size) + ; r8 = nPos + ; r9 = nValue1 + ; [esp+0x28] = nValue2 + + xor rax, rax ; return value + mov r11, rcx ; table + sub rdx, r8 ; rdx = remaining count of uints + mov r10, [esp+028h] ; r10 = nValue2 + + add qword ptr [r11 + r8 * 8], r9 + lea r8, [r8+1] + lea rdx, [rdx-1] + adc qword ptr [r11 + r8 * 8], r10 + jc next + ret + + ALIGN 16 +loop1: + lea r8, [r8+1] + add qword ptr [r11 + r8 * 8], 1 + jc next + ret + +next: + dec rdx ; does not modify CY too... + jnz loop1 + lea rax, [rax+1] + ret + +ttmath_addindexed2_x64 ENDP + + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + + +ttmath_addvector_x64 PROC + ; rcx = ss1 + ; rdx = ss2 + ; r8 = ss1_size + ; r9 = ss2_size + ; [esp+0x28] = result + + mov r10, [esp+028h] + sub r8, r9 + xor r11, r11 ; r11=0, cf=0 + + ALIGN 16 + loop1: + mov rax, qword ptr [rcx + r11 * 8] + adc rax, qword ptr [rdx + r11 * 8] + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r9 + jnz loop1 + + adc r9, r9 ; r9 has the cf state + + or r8, r8 + jz done + + neg r9 ; setting cf from r9 + mov r9, 0 ; don't use xor here (cf is used) + loop2: + mov rax, qword ptr [rcx + r11 * 8] + adc rax, r9 + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r8 + jnz loop2 + + adc r8, r8 + mov rax, r8 + + ret + +done: + mov rax, r9 + ret + +ttmath_addvector_x64 ENDP + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_sbb_x64 PROC + + ; rcx = p1 + ; rdx = p2 + ; r8 = nCount + ; r9 = nCarry + + xor rax, rax + xor r11, r11 + sub rax, r9 ; sets CARRY if r9 != 0 + + ALIGN 16 + loop1: + mov rax,qword ptr [rdx + r11 * 8] + sbb qword ptr [rcx + r11 * 8], rax + lea r11, [r11+1] + dec r8 + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_sbb_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_subindexed_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = nPos + ; r9 = nValue + + sub rdx, r8 ; rdx = remaining count of uints + + ALIGN 16 +loop1: + sub qword ptr [rcx + r8 * 8], r9 + jnc done + + lea r8, [r8+1] + mov r9, 1 + dec rdx + jnz loop1 + + mov rax, 1 + ret + +done: + xor rax, rax + ret + +ttmath_subindexed_x64 ENDP + + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +; the same asm code as in addvector_x64 only two instructions 'adc' changed to 'sbb' + +ttmath_subvector_x64 PROC + ; rcx = ss1 + ; rdx = ss2 + ; r8 = ss1_size + ; r9 = ss2_size + ; [esp+0x28] = result + + mov r10, [esp+028h] + sub r8, r9 + xor r11, r11 ; r11=0, cf=0 + + ALIGN 16 + loop1: + mov rax, qword ptr [rcx + r11 * 8] + sbb rax, qword ptr [rdx + r11 * 8] + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r9 + jnz loop1 + + adc r9, r9 ; r9 has the cf state + + or r8, r8 + jz done + + neg r9 ; setting cf from r9 + mov r9, 0 ; don't use xor here (cf is used) + loop2: + mov rax, qword ptr [rcx + r11 * 8] + sbb rax, r9 + mov qword ptr [r10 + r11 * 8], rax + inc r11 + dec r8 + jnz loop2 + + adc r8, r8 + mov rax, r8 + + ret + +done: + mov rax, r9 + ret + +ttmath_subvector_x64 ENDP + + + + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcl_x64 PROC + ; rcx = p1 + ; rdx = b + ; r8 = nLowestBit + + mov r11, rcx ; table + xor r10, r10 + neg r8 ; CY set if r8 <> 0 + + ALIGN 16 +loop1: + rcl qword ptr [r11 + r10 * 8], 1 + lea r10, [r10+1] + dec rdx + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_rcl_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcr_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = nLowestBit + + xor r10, r10 + neg r8 ; CY set if r8 <> 0 + + ALIGN 16 +loop1: + rcr qword ptr -8[rcx + rdx * 8], 1 + dec rdx + jnz loop1 + + setc al + movzx rax, al + + ret + +ttmath_rcr_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_div_x64 PROC + + ; rcx = &Hi + ; rdx = &Lo + ; r8 = nDiv + + mov r11, rcx + mov r10, rdx + + mov rdx, qword ptr [r11] + mov rax, qword ptr [r10] + div r8 + mov qword ptr [r10], rdx ; remainder + mov qword ptr [r11], rax ; value + + ret + +ttmath_div_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcl2_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = bits + ; r9 = c + + push rbx + + mov r10, rcx ; r10 = p1 + xor rax, rax + + mov rcx, 64 + sub rcx, r8 + + mov r11, -1 + shr r11, cl ; r11 = mask + + mov rcx, r8 ; rcx = count of bits + + mov rbx, rax ; rbx = old value = 0 + or r9, r9 + cmovnz rbx, r11 ; if (c) then old value = mask + + mov r9, rax ; r9 = index (0..nSize-1) + + ALIGN 16 +loop1: + rol qword ptr [r10+r9*8], cl + mov rax, qword ptr [r10+r9*8] + and rax, r11 + xor qword ptr [r10+r9*8], rax + or qword ptr [r10+r9*8], rbx + mov rbx, rax + + lea r9, [r9+1] + dec rdx + + jnz loop1 + + and rax, 1 + pop rbx + ret + +ttmath_rcl2_x64 ENDP + +;---------------------------------------- + + ALIGN 8 + +;---------------------------------------- + +ttmath_rcr2_x64 PROC + ; rcx = p1 + ; rdx = nSize + ; r8 = bits + ; r9 = c + + push rbx + mov r10, rcx ; r10 = p1 + xor rax, rax + + mov rcx, 64 + sub rcx, r8 + + mov r11, -1 + shl r11, cl ; r11 = mask + + mov rcx, r8 ; rcx = count of bits + + mov rbx, rax ; rbx = old value = 0 + or r9, r9 + cmovnz rbx, r11 ; if (c) then old value = mask + + mov r9, rdx ; r9 = index (0..nSize-1) + lea r9, [r9-1] + + ALIGN 16 +loop1: + ror qword ptr [r10+r9*8], cl + mov rax, qword ptr [r10+r9*8] + and rax, r11 + xor qword ptr [r10+r9*8], rax + or qword ptr [r10+r9*8], rbx + mov rbx, rax + + lea r9, [r9-1] + dec rdx + + jnz loop1 + + rol rax, 1 + and rax, 1 + pop rbx + + ret + +ttmath_rcr2_x64 ENDP + +END