commit ab42f75285cbbcc75f9fbccb40bc3fc894d6fd04 Author: Tomasz Sowa Date: Sun Jan 21 20:02:44 2007 +0000 initial import git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@1 e52654a7-88a9-db11-a3e9-0013d4bc506e diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..a224f32 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,4 @@ +Version 0.6.2 (2007.01.10): + * New division algorithm (radix b) where b is 2^32 + + diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..a99db80 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,28 @@ +Copyright (c) 2006-2007, 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. diff --git a/README b/README new file mode 100644 index 0000000..139597f --- /dev/null +++ b/README @@ -0,0 +1,2 @@ + + diff --git a/TODO b/TODO new file mode 100644 index 0000000..5ce5641 --- /dev/null +++ b/TODO @@ -0,0 +1,7 @@ +TODO TTMath Library +=================== + + + + + diff --git a/ttmath/ttmath.h b/ttmath/ttmath.h new file mode 100644 index 0000000..960cd64 --- /dev/null +++ b/ttmath/ttmath.h @@ -0,0 +1,530 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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. +*/ + +#include "ttmathbig.h" + +#include + + + +namespace ttmath +{ + + /*! + the factorial from given 'x' + e.g. + Factorial(4) = 4! = 1*2*3*4 + */ + template + Big Factorial(const Big & x, ErrorCode * err = 0, const volatile StopCalculating * stop = 0) + { + Big result; + + result.SetOne(); + + if( x.IsSign() ) + { + if( err ) + *err = err_improper_argument; + + return result; + } + + if( !x.exponent.IsSign() && !x.exponent.IsZero() ) + { + // when x>0 there's no sense to calculate the formula + // (we can't add one into the x bacause + // we don't have enough bits in our mantissa) + if( err ) + *err = err_overflow; + + return result; + } + + Big multipler; + Big one; + uint carry = 0; + + one = result; // =1 + multipler = result; // =1 + + while( !carry && multipler < x ) + { + if( stop && stop->WasStopSignal() ) + { + if( err ) + *err = err_interrupt; + + return result; + } + + carry += multipler.Add(one); + carry += result.Mul(multipler); + } + + + if( err ) + { + if( carry ) + *err = err_overflow; + else + *err = err_ok; + } + + return result; + } + + + /*! + absolute value of x + e.g. -2 = 2 + 2 = 2 + */ + template + Big Abs(const Big & x) + { + Big result( x ); + result.Abs(); + + return result; + } + + + /*! + this method skips the fraction from x + e.g 2.2 = 2 + 2.7 = 2 + -2.2 = 2 + -2.7 = 2 + */ + template + Big SkipFraction(const Big & x) + { + Big result( x ); + result.SkipFraction(); + + return result; + } + + + /*! + this method rounds to the nearest integer value + e.g 2.2 = 2 + 2.7 = 3 + -2.2 = -2 + -2.7 = -3 + */ + template + Big Round(const Big & x) + { + Big result( x ); + result.Round(); + + return result; + } + + + /*! + this method calculates the natural logarithm (logarithm with the base 'e') + */ + template + Big Ln(const Big & x, ErrorCode * err = 0) + { + Big 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 method calculates the logarithm + */ + template + Big Log(const Big & base, const Big & x, ErrorCode * err = 0) + { + Big result; + + uint state = result.Log(base,x); + + 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 method calculates the expression e^x + */ + template + Big Exp(const Big & x, ErrorCode * err = 0) + { + Big result; + + uint state = result.Exp(x); + + if( err ) + if( state!=0 ) + *err = err_overflow; + else + *err = err_ok; + + return result; + } + + + /*! + * + * trigonometric functions + * + */ + + + /*! + an auxiliary function for calculating the Sin + (you don't have to call this function) + */ + template + void PrepareSin(Big & x, bool & change_sign) + { + Big 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 > temp ) + { + x.Div( temp ); + x.RemainFraction(); + x.Mul( temp ); + } + + // 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; + } + } + + + /*! + an auxiliary function for calculating the Sin + (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 + Big Sin0pi05(const Big & x) + { + Big result; + Big numerator, denominator; + Big d_numerator, d_denominator; + Big 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 + Big pi05; + pi05.Set05Pi(); + + temp = x; + temp.Sub( pi05 ); + d_numerator = temp; + d_numerator.Mul( temp ); + + d_denominator = one; + } + + int c = 0; + bool addition = false; + + old_result = result; + for(int i=1 ; i<5000 ; ++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 breaks 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; + } + + + /*! + this function calulates the Sin + */ + template + Big Sin(Big x) + { + Big one; + bool change_sign; + + PrepareSin( x, change_sign ); + Big result = Sin0pi05( x ); + + one.SetOne(); + + if( result > one ) + result = one; + else + if( result.IsSign() ) + result.SetZero(); + + if( change_sign ) + result.ChangeSign(); + + return result; + } + + + /*! + this function calulates the Cos + we're using the formula cos(x) = sin(x + PI/2) + */ + template + Big Cos(Big x) + { + Big pi05; + pi05.Set05Pi(); + + x.Add( pi05 ); + + return Sin(x); + } + + + /*! + this function calulates the Tan + 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 precise + because Tan receives its values from -infinity to +infinity + and when we calculate it from any series then we can make + a small mistake than calculating 'sin/cos' + */ + template + Big Tan(const Big & x, ErrorCode * err = 0) + { + Big result = Cos(x); + + if( result.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + return result; + } + + if( err ) + *err = err_ok; + + return Sin(x) / result; + } + + + /*! + this function calulates the CTan + we're using the formula tan(x) = cos(x) / sin(x) + + (why do we make it in this way? + look at the info in Tan() function) + */ + template + Big CTan(const Big & x, ErrorCode * err = 0) + { + Big result = Sin(x); + + if( result.IsZero() ) + { + if( err ) + *err = err_improper_argument; + + return result; + } + + if( err ) + *err = err_ok; + + return Cos(x) / result; + } + + +} // namespace + + + + + +#endif diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h new file mode 100644 index 0000000..3995fe1 --- /dev/null +++ b/ttmath/ttmathbig.h @@ -0,0 +1,2824 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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 big numbers +*/ + +#include "ttmathint.h" + +namespace ttmath +{ + + +/*! + \brief it implements the big value +*/ +template +class Big +{ + +/* + value = mantissa * 2^exponent + + exponent - integer value with a sign + mantissa - 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; + + +/*! + the number of a bit from 'info' which means that a value is with the sign + (when the bit is set) +*/ +#define TTMATH_BIG_SIGN 128 + + + + +public: + + + /*! + 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 as zero as well + + 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() ) + return 0; + + if( CorrectZero() ) + return 0; + + uint comp = mantissa.CompensationToLeft(); + + return exponent.Sub( comp ); + } + + +private: + + /*! + if 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() ) + { + Abs(); + exponent.SetZero(); + + return true; + } + + return false; + } + + + + +public: + + /*! + it sets value zero + */ + void SetZero() + { + info = 0; + exponent.SetZero(); + mantissa.SetZero(); + + /* + we don't have to compensate zero + */ + } + + + /*! + it sets value one + */ + void SetOne() + { + info = 0; + mantissa.SetOne(); + exponent.SetZero(); + Standardizing(); + } + + + /*! + it sets value 0.5 + */ + void SetDotOne() + { + SetOne(); + exponent.SubOne(); + } + + + /*! + it sets value pi + */ + void SetPi() + { + static const uint 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, 0xf0139f9d, 0x88e637cb + }; + // 78 unsigned words + // this is static table which represents the value Pi (mantissa of its) + // (first is the highest word) + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(uint)); + exponent = -int(man)*int(BITS_PER_UINT) + 2; + info = 0; + } + + + /*! + it sets value 0.5 * pi + */ + void Set05Pi() + { + SetPi(); + exponent = -int(man)*int(BITS_PER_UINT) + 1; + } + + + /*! + it sets value 2 * pi + */ + void Set2Pi() + { + SetPi(); + exponent = -int(man)*int(BITS_PER_UINT) + 3; + } + + + /*! + it sets value e + (the base of natural logarithm) + */ + void SetE() + { + static const uint 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, 0x645b2194, 0x41468794 + }; + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(uint)); + exponent = -int(man)*int(BITS_PER_UINT) + 2; + info = 0; + } + + + /*! + it sets value ln(2) + the natural logarithm from value 2 + */ + void SetLn2() + { + static const uint 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, 0x228a4ef8, 0x6e1adf84, 0x08689fa8 + }; + + mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(uint)); + exponent = -int(man)*int(BITS_PER_UINT); + info = 0; + } + + + /*! + it sets the maximum value which can be held in this type + */ + void SetMax() + { + info = 0; + mantissa.SetMaxValue(); + exponent.SetMaxValue(); + + // we don't have to use 'Standardizing()' because the last bit from + // the mantissa is set + } + + + /*! + it sets the minimum value which can be held in this type + */ + void SetMin() + { + info = 0; + SetSign(); + + mantissa.SetMaxValue(); + exponent.SetMaxValue(); + + // we don't have to use 'Standardizing()' because the last bit from + // the mantissa is set + } + + + /*! + it's testing whether there is a value zero or not + */ + bool IsZero() const + { + /* + we only have to test the mantissa + */ + return mantissa.IsZero(); + } + + + /*! + it returns true when there's the sign set + */ + bool IsSign() const + { + return (info & TTMATH_BIG_SIGN) == TTMATH_BIG_SIGN; + } + + + /*! + it clears the sign + (there'll be a absolute value) + + e.g. + -1 -> 1 + 2 -> 2 + */ + void Abs() + { + info &= ~TTMATH_BIG_SIGN; + } + + + /*! + it sets the sign + + e.g. + -1 -> -1 + 2 -> -2 + */ + void SetSign() + { + if( IsZero() ) + return; + + info |= TTMATH_BIG_SIGN; + } + + + /*! + it changes the sign + + e.g. + -1 -> 1 + 2 -> -2 + */ + void ChangeSign() + { + if( IsZero() ) + return; + + info = (info & (~TTMATH_BIG_SIGN)) | ((~info) & TTMATH_BIG_SIGN); + } + + + + + + /*! + * + * basic mathematic functions + * + */ + + + /*! + Addition this = this + ss2 + + it returns carry if the sum is too big + */ + uint Add(Big ss2) + { + Int exp_offset( exponent ); + Int mantissa_size_in_bits( man * BITS_PER_UINT ); + int 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 short for taking into consideration in the sum + return 0; + } + else + if( exp_offset < mantissa_size_in_bits ) + { + // moving 'exp_offset' times + ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); + } + else + { + // exp_offset == mantissa_size_in_bits + // we're rounding 'this' about one (up or down depending on a ss2 sign) + ss2.mantissa.SetOne(); + } + + + if( IsSign() == ss2.IsSign() ) + { + // values have the same signs + if( mantissa.Add(ss2.mantissa) ) + { + mantissa.Rcr(1); + c = exponent.AddOne(); + } + } + else + { + // values have different signs + if( mantissa.Sub(ss2.mantissa) ) + { + mantissa.Rcl(1); + c = exponent.SubOne(); + } + } + + c += Standardizing(); + + return (c==0)? 0 : 1; + } + + + /*! + Subtraction this = this - ss2 + + it returns carry if the result is too big + */ + uint Sub(Big ss2) + { + ss2.ChangeSign(); + + return Add(ss2); + } + + + /*! + multiplication this = this * ss2 + this method returns carry + */ + uint Mul(const Big & ss2) + { + MATHTT_THIS_ASSERT( ss2 ) + + UInt man_result; + int i,c; + + // man_result = mantissa * ss2.mantissa + mantissa.Mul(ss2.mantissa, man_result); + + // 'i' will be from 0 to man*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(); + + c = exponent.Add( man * BITS_PER_UINT - i ); + c += exponent.Add( ss2.exponent ); + + for(i=0 ; i & ss2) + { + MATHTT_THIS_ASSERT( ss2 ) + + UInt man1; + UInt man2; + uint i,c; + + if( ss2.IsZero() ) + { + // we don't divide by zero + return 1; + } + + for(i=0 ; i + uint PowUInt(UInt pow) + { + if(pow.IsZero() && IsZero()) + // we don't define zero^zero + return 1; + + Big start(*this); + Big result; + result.SetOne(); + + while( !pow.IsZero() ) + { + if( pow.table[0] & 1 ) + if( result.Mul(start) ) + return 1; + + if( start.Mul(start) ) + return 1; + + pow.Rcr(); + } + + *this = result; + + return 0; + } + + + /*! + power this = this ^ pow + p can be with a sign + p can be negative + */ + template + uint PowInt(Int pow) + { + if( !pow.IsSign() ) + return PowUInt(pow); + + + if( IsZero() ) + // if 'p' is negative then + // 'this' must be different from zero + return 1; + + if( pow.ChangeSign() ) + return 1; + + Big t(*this); + if( t.PowUInt(pow) ) + return 1; + + SetOne(); + if( Div(t) ) + return 1; + + return 0; + } + + + /*! + this method returns true if 'this' mod 2 is equal one + */ + bool Mod2() const + { + if( exponent>int(0) || exponent<=-int(man*BITS_PER_UINT) ) + return false; + + int exp_int = exponent.ToInt(); + // 'exp_int' is negative (or zero), we set its as positive + exp_int = -exp_int; + + int value = mantissa.table[ exp_int / BITS_PER_UINT ]; + value >>= (exp_int % BITS_PER_UINT); + + return bool(value & 1); + } + + + /*! + power this = this ^ abs([pow]) + pow without a sign and without a fraction + */ + uint PowBUInt(Big pow) + { + if( pow.IsZero() && IsZero() ) + return 1; + + if( pow.IsSign() ) + pow.Abs(); + + Big start(*this), start_temp; + Big result; + Big one; + Int e_one; + + e_one.SetOne(); + one.SetOne(); + result.SetOne(); + + while( pow >= one ) + { + if( pow.Mod2() ) + if( result.Mul(start) ) + return 1; + + start_temp = start; + if( start.Mul(start_temp) ) + return 1; + + pow.exponent.Sub( e_one ); + } + + *this = result; + + return 0; + } + + + /*! + power this = this ^ [pow] + pow without a fraction + pow can be negative + */ + uint PowBInt(const Big & pow) + { + MATHTT_THIS_ASSERT( pow ) + + if( !pow.IsSign() ) + return PowBUInt(pow); + + if( IsZero() ) + // if 'pow' is negative then + // 'this' must be different from zero + return 1; + + Big temp(*this); + if( temp.PowBUInt(pow) ) + return 1; + + SetOne(); + if( Div(temp) ) + return 1; + + return 0; + } + + + /*! + power this = this ^ pow + pow can be negative and with fraction + + return values: + 1 - carry + 2 - incorrect argument ('this' or 'pow') + */ + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + there should be 'int Pow(const Big & pow)' + but vc2005express doesn't want to compile it perfect, that means + when using 'Maximize Speed /O2' the result of compilation doesn't work property + for example 10^(1/2) is a big value + i don't know where is the problem, with this source code or in the compilator + (it is when we're using 'Big<3,10>' or bigger values in parsing) + /gcc 3.4.2 works perfect (with -O3 optimalization flag)/ + + (we also can change 'Div' instead modifying this 'Pow' -- it'll be the same effect, + this error is only when we're using our mathematic parser) + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ + +#ifdef __GNUC__ + int Pow(const Big & pow) +#else + int Pow(const Big pow) +#endif + { + MATHTT_THIS_ASSERT( pow ) + + if( IsZero() ) + { + // 0^pow will be 0 only for pow>0 + if( pow.IsSign() || pow.IsZero() ) + return 2; + + SetZero(); + + return 0; + } + + Big pow_frac( pow ); + pow_frac.RemainFraction(); + + if( pow_frac.IsZero() ) + return PowBInt( pow ); + + // pow is with fraction (not integer) + // result = e^(pow * ln(this) ) where 'this' must be greater than 0 + + // IsZero() was tested before + if( IsSign() ) + return 2; + + Big temp; + uint c = temp.Ln(*this); + c += temp.Mul(pow); + c += Exp(temp); + + return (c==0)? 0 : 1; + } + + +private: + + /*! + 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) + { + MATHTT_THIS_ASSERT( x ) + + Big denominator, denominator_i; + Big one, old_value, next_part; + Big numerator = x; + + SetOne(); + one.SetOne(); + denominator.SetOne(); + denominator_i.SetOne(); + + // we assume only 'max_loop' iterations of our loop + // every 'step_test' times we make a test + const uint max_loop = 2000; + const uint step_test = 5; + + // we begin from 1 in order to not testing at the start + for(uint i=1 ; i<=max_loop ; ++i) + { + bool testing = ((i % step_test) == 0); + + if( testing ) + old_value = *this; + + 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 && old_value==*this ) + // we've added a next part of the formula but the result + // is still the same then we break the loop + break; + + // 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; + } + } + + + +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.IsZero() ) + { + SetOne(); + return 0; + } + + // m will be the value of the mantissa in range (-1,1) + Big m(x); + m.exponent = -int(man*BITS_PER_UINT); + + // 'e_' will be the value of '2^exponent' + // e_.mantissa.table[man-1] = uint_the_highest_bit; and + // e_.exponent.Add(1) mean: + // e_.mantissa.table[0] = 1; + // e_.Standardizing(); + // e_.exponent.Add(man*BITS_PER_UINT) + // (we must add 'man*BITS_PER_UINT' because we've taken it from the mantissa) + Big e_(x); + e_.mantissa.SetZero(); + e_.mantissa.table[man-1] = uint_the_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 += PowBUInt(e_); + } + + return (c==0)? 0 : 1; + } + + + + +private: + + /*! + 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 + ... ] + + parts - it's used for approximation, it means how many parts of the above formula + will be caltulated, when equals 0 then it is ommited + + */ + void LnSurrounding1(const Big & x) + { + 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(); + + // we assume only 'max_loop' iterations of our loop + // every 'step_test' times we make a test + const uint max_loop = 2000; + const uint step_test = 5; + + // we begin from 1 in order to not testing at the beginning + for(uint i=1 ; i< max_loop+1 ; ++i) + { + bool testing = ((i % step_test) == 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; + + if( testing ) + old_value = *this; + + // there shouldn't be a carry here + Add(next_part); + + if( testing && 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; + + 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(); + } + + + + +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 + 2 - incorrect argument (x<=0) + + parts: look at the LnSurrounding1() method + */ + uint Ln(const Big & x) + { + MATHTT_THIS_ASSERT( x ) + + if( x.IsSign() || x.IsZero() ) + return 2; + + // m will be the value of the mantissa in range <1,2) + Big m(x); + m.exponent = -int(man*BITS_PER_UINT - 1); + LnSurrounding1(m); + + Big exponent_temp; + exponent_temp.FromInt( x.exponent ); + + // we must add 'man*BITS_PER_UINT-1' because we've taken it from the mantissa + uint c = exponent_temp.Add(man*BITS_PER_UINT-1); + + Big ln2; + ln2.SetLn2(); + + c += exponent_temp.Mul(ln2); + c += Add(exponent_temp); + + return (c==0)? 0 : 1; + } + + + + /*! + Logarithm with a base 'base' -- this = Log(x) with a base '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) + + + parts: look at the LnSurrounding1() method + we pass this value only into 'ln(x)' method + because if we passed 'parts' into 'ln(base)' as well then + the error (after dividing) would be too great + */ + uint Log(const Big & base, const Big & x) + { + MATHTT_THIS_ASSERT( base ) + MATHTT_THIS_ASSERT( x ) + + if( x.IsSign() || x.IsZero() ) + return 2; + + Big denominator;; + denominator.SetOne(); + + if( base.IsSign() || base.IsZero() || base==denominator ) + 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 start + // there can be only a carry + uint c = Ln(x); + + // we don't pass the 'parts' here (the error after dividing would be to great) + c += denominator.Ln(base); + c += Div(denominator); + + return (c==0)? 0 : 1; + } + + + + + /*! + * + * convertion method + * + */ + + + /*! + this method sets 'result' as the one word of type int + + if the value is too big this method returns a carry (1) + */ + uint ToInt(int & result) const + { + result = 0; + + if( IsZero() ) + return 0; + + int maxbit = -int(man*BITS_PER_UINT); + + if( exponent > maxbit + int(BITS_PER_UINT) ) + // if exponent > (maxbit + int(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; + + UInt mantissa_temp(mantissa); + // exponent is from a range of (-maxbit,0> + int how_many_bits = exponent.ToInt(); + + // how_many_bits is negative, we'll make it positive + how_many_bits = -how_many_bits; + + // we're taking into an account only the last word in a mantissa table + mantissa_temp.Rcr( how_many_bits % BITS_PER_UINT, 0 ); + result = mantissa_temp.table[ man-1 ]; + + // the exception for the minimal value + if( IsSign() && result == uint_the_highest_bit ) + return 0; + + if( (result & uint_the_highest_bit) != 0 ) + // the value is too big + return 1; + + if( IsSign() ) + result = -int(result); + + return 0; + } + + + /*! + this method sets the value in '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; + + int maxbit = -int(man*BITS_PER_UINT); + + if( exponent > maxbit + int(int_size*BITS_PER_UINT) ) + // if exponent > (maxbit + int(int_size*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; + + UInt mantissa_temp(mantissa); + int how_many_bits = exponent.ToInt(); + + if( how_many_bits < 0 ) + { + how_many_bits = -how_many_bits; + uint index = how_many_bits / BITS_PER_UINT; + mantissa_temp.Rcr( how_many_bits % BITS_PER_UINT, 0 ); + + for(uint i=index, a=0 ; i min; + min.SetMinValue(); + + if( result == min ) + return 0; + } + + if( (result.table[int_size-1] & uint_the_highest_bit) != 0 ) + // the value is too big + return 1; + + if( IsSign() ) + result.ChangeSign(); + + return 0; + } + + + /*! + a method for converting 'int' to this class + */ + void FromInt(int value) + { + bool is_sign = false; + + if( value < 0 ) + { + value = -value; + is_sign = true; + } + + info = 0; + mantissa = value; + exponent.SetZero(); + + if( is_sign ) + SetSign(); + + // there shouldn't be a carry because 'value' has the type 'int' + Standardizing(); + } + + + /*! + an operator= for converting 'int' to this class + */ + Big & operator=(int value) + { + FromInt(value); + + return *this; + } + + + /*! + a constructor for converting 'int' to this class + */ + Big(int value) + { + FromInt(value); + } + + + /*! + a method for converting from 'Int' to this class + */ + template + void FromInt(Int value) + { + info = 0; + + if( value.IsSign() ) + { + value.ChangeSign(); + SetSign(); + } + + uint minimum_size = (int_size < man)? int_size : man; + int compensation = (int)value.CompensationToLeft(); + exponent = (int(int_size)-int(man)) * int(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; + + } + + + /*! + 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); + } + + + /*! + a default constructor + + warning: we don't set any of the members to zero etc. + */ + Big() + { + } + + + /*! + a destructor + */ + virtual ~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 the value into the string with a base equal 'base' + + input: + base - the base on which the value will be showed + + if 'always_scientific' is true the result will be showed in 'scientific' mode + + if 'always_scientific' is false the result will be showed + either as 'scientific' or 'normal' mode, it depends whether the abs(exponent) + is greater than 'when_scientific' or not, if it's greater the value + will be printed as 'scientific' + + if 'max_digit_after_comma' is equal -1 that all digits in the mantissa + will be printed + + if 'max_digit_after_comma' is equal -2 that not mattered digits + in the mantissa will be cut off + (zero characters at the end -- after the comma operator) + + if 'max_digit_after_comma' is equal or greater than zero + that only 'max_digit_after_comma' after the comma operator will be showed + (if 'max_digit_after_comma' is equal zero there'll be showed only + integer value without the comma) + for example when the value is: + 12.345678 and max_digit_after_comma is 4 + then the result will be + 12.3457 (the last digit was rounded) + + if there isn't the comma operator (when the value is too big and we're printing + it not as scientific) 'max_digit_after_comma' will be ignored + + output: + return value: + 0 - ok and 'result' will be an object of type std::string which holds the value + 1 - if there was a carry + */ + uint ToString( std::string & result, + uint base = 10, + bool always_scientific = false, + int when_scientific = 15, + int max_digit_after_comma = -2 ) const + { + static char error_overflow_msg[] = "overflow"; + result.erase(); + + if(base<2 || base>16) + { + 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, base, new_exp) ) + { + result = error_overflow_msg; + return 1; + } + + /* + we're rounding the mantissa only if the base is different from 2,4,8 or 16 + (this formula means that the number of bits in the base is greater than one) + */ + if( base!=2 && base!=4 && base!=8 && base!=16 ) + if( ToString_RoundMantissa(result, base, new_exp) ) + { + result = error_overflow_msg; + return 1; + } + + if( ToString_SetCommaAndExponent( result, base, new_exp, always_scientific, + when_scientific, max_digit_after_comma ) ) + { + result = error_overflow_msg; + return 1; + } + + if( IsSign() ) + result.insert(result.begin(), '-'); + + // converted successfully + return 0; + } + + +private: + + + /*! + 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 (private) + + 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 to 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 take: + new_exp = [log base (2^exponent)] + 1 <- where [x] means integer value from x + */ + uint ToString_CreateNewMantissaAndExponent( std::string & new_man, uint base, + Int & new_exp) const + { + uint c = 0; + + if(base<2 || base>16) + return 1; + + // the speciality for base equal 2 + if( base == 2 ) + return ToString_CreateNewMantissaAndExponent_Base2(new_man, new_exp); + + // 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)] + 1 + Big new_exp_; + c += new_exp_.ToString_Log(base, temp); // this logarithm isn't very complicated + new_exp_.SkipFraction(); + temp.SetOne(); + c += new_exp_.Add( temp ); + + // 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_(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_ ); + + // moving all bits of the mantissa into the right + // (how many times to move depend on the exponent) + c += temp.ToString_MoveMantissaIntoRight(); + + // on account of we take 'new_exp' as small as it's + // 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, base); + + // because we had used a bigger type for calculating I think we + // shouldn't have had a carry + // (in the future this can be changed) + + 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(uint base, const Big & x) + { + MATHTT_THIS_ASSERT( x ) + + 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); + + static Big log_history[15] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + Big * log_value = log_history + base - 2; + + if( log_value->IsZero() ) + { + // we don't have 'base' in 'log_history' then we calculate it now + Big base_(base); + c += temp.Ln(base_); + c += Div(temp); + + // the next time we'll get the 'Ln(base)' from the history, + // this 'log_history' can have (16-2+1) items max + + *log_value = temp; + } + else + { + // we've calculated the 'Ln(base)' beforehand and we're using it now + + c += Div( *log_value ); + } + + return (c==0)? 0 : 1; + } + + + /*! + 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 <= -int(man*BITS_PER_UINT) ) + // if 'exponent' is <= than '-int(man*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*BITS_PER_UINT, 0> + int 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) + + (we can make that speciality when the base is 4,8 or 16 as well + but maybe in further time) + */ + uint ToString_CreateNewMantissaAndExponent_Base2( std::string & new_man, + Int & new_exp ) const + { + for( int i=man-1 ; i>=0 ; --i ) + { + uint value = mantissa.table[i]; + + for( unsigned int bit=0 ; bit & new_exp) const + { + // we must have minimum two characters + if( new_man.length() < 2 ) + return 0; + + std::string::size_type i = new_man.length() - 1; + + // we're erasing the last character + uint digit = UInt::CharToDigit( new_man[i] ); + new_man.erase( i, 1 ); + uint carry = new_exp.AddOne(); + + // if the last character is greater or equal 'base/2' + // we'll add one into the new mantissa + if( digit >= base / 2 ) + ToString_RoundMantissa_AddOneIntoMantissa(new_man, base); + + return carry; + } + + + /*! + an auxiliary method for converting into the string + + this method addes one into the new mantissa + */ + void ToString_RoundMantissa_AddOneIntoMantissa(std::string & new_man, uint base) const + { + if( new_man.empty() ) + return; + + int i = int( 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] == MATHTT_COMMA_CHARACTER_1 ) + continue; + + // we're adding one + uint digit = UInt::CharToDigit( new_man[i] ) + 1; + + if( digit == base ) + digit = 0; + else + was_carry = false; + + new_man[i] = UInt::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 + */ + int ToString_SetCommaAndExponent( std::string & new_man, uint base, Int & new_exp, + bool always_scientific, + int when_scientific, + int max_digit_after_comma ) const + { + int 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) + + int offset = int( 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' + + if( !always_scientific ) + { + if( scientific_exp > when_scientific || scientific_exp < -int(when_scientific) ) + always_scientific = true; + } + + // 'always_scientific' could be changed + if( !always_scientific ) + ToString_SetCommaAndExponent_Normal(new_man, base, new_exp, max_digit_after_comma); + else + // we're passing the 'scientific_exp' instead of 'new_exp' here + ToString_SetCommaAndExponent_Scientific(new_man, base, scientific_exp, max_digit_after_comma); + + return (carry==0)? 0 : 1; + } + + + /*! + an auxiliary method for converting into the string + */ + void ToString_SetCommaAndExponent_Normal(std::string & new_man, uint base, + Int & new_exp, int max_digit_after_comma) const + { + if( new_exp >= 0 ) + return ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp); + else + return ToString_SetCommaAndExponent_Normal_SetCommaInside(new_man, base, new_exp, max_digit_after_comma); + } + + + /*! + an auxiliary method for converting into the string + */ + void ToString_SetCommaAndExponent_Normal_AddingZero(std::string & 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 + */ + void ToString_SetCommaAndExponent_Normal_SetCommaInside(std::string & new_man, + uint base, Int & new_exp, int max_digit_after_comma) const + { + // new_exp is < 0 + + int new_man_len = int(new_man.length()); // 'new_man_len' with a sign + int e = -( new_exp.ToInt() ); // 'e' will be positive + + if( new_exp > -new_man_len ) + { + // we're setting the comma within the mantissa + + int index = new_man_len - e; + new_man.insert( new_man.begin() + index, MATHTT_COMMA_CHARACTER_1); + } + else + { + // we're adding zero characters before the mantissa + + uint how_many = e - new_man_len; + std::string man_temp(how_many+1, '0'); + + man_temp.insert( man_temp.begin()+1, MATHTT_COMMA_CHARACTER_1); + new_man.insert(0, man_temp); + } + + ToString_CorrectDigitsAfterComma(new_man, base, max_digit_after_comma); + } + + + /*! + an auxiliary method for converting into the string + */ + void ToString_SetCommaAndExponent_Scientific( std::string & new_man, + uint base, + Int & scientific_exp, + int max_digit_after_comma ) const + { + if( new_man.empty() ) + return; + + new_man.insert( new_man.begin()+1, MATHTT_COMMA_CHARACTER_1 ); + + ToString_CorrectDigitsAfterComma(new_man, base, max_digit_after_comma); + + if( 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) + new_man += "*10^"; + } + + std::string temp_exp; + scientific_exp.ToString( temp_exp, base ); + + new_man += temp_exp; + } + + + /*! + an auxiliary method for converting into the string + + we can call this method only if we've put the comma operator into the mantissa's string + */ + void ToString_CorrectDigitsAfterComma(std::string & new_man, uint base, + int max_digit_after_comma) const + { + switch( max_digit_after_comma ) + { + case -1: + // the mantissa will be unchanged + break; + + case -2: + ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(new_man); + break; + + default: + ToString_CorrectDigitsAfterComma_Round(new_man, base, max_digit_after_comma); + break; + } + } + + + /*! + an auxiliary method for converting into the string + */ + void ToString_CorrectDigitsAfterComma_CutOffZeroCharacters(std::string & new_man) 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; + + // if directly before the first zero is the comma operator + // we're cutting it as well + if( i>0 && new_man[i]==MATHTT_COMMA_CHARACTER_1 ) + --i; + + new_man.erase(i+1, new_man.length()-i-1); + } + + + /*! + an auxiliary method for converting into the string + */ + void ToString_CorrectDigitsAfterComma_Round(std::string & new_man, uint base, + int max_digit_after_comma) const + { + // first we're looking for the comma operator + std::string::size_type index = new_man.find(MATHTT_COMMA_CHARACTER_1, 0); + + if( index == std::string::npos ) + // nothing was found (actually there can't be this situation) + return; + + // we're calculating how many digits there are at the end (after the comma) + // 'after_comma' will be greater than zero because at the end + // we have at least one digit + std::string::size_type after_comma = new_man.length() - index - 1; + + // if 'max_digit_after_comma' is greater than 'after_comma' (or equal) + // we don't have anything for cutting + if( std::string::size_type(max_digit_after_comma) >= after_comma ) + return; + + uint last_digit = UInt::CharToDigit( new_man[ index + max_digit_after_comma + 1 ], base ); + + // we're cutting the rest of the string + new_man.erase(index + max_digit_after_comma + 1, after_comma - max_digit_after_comma); + + if( max_digit_after_comma == 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 >= base / 2 ) + // we must round here + ToString_RoundMantissa_AddOneIntoMantissa(new_man, base); + } + + + + +public: + + + /*! + a method for converting a string into its value + + it returns 1 if the value will be too big -- we cannot pass it into the range + of our class Big + + 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 will have finished its job + it set the pointer to the new first character after this parsed value + */ + int FromString(const char * source, uint base = 10, const char ** after_source = 0) + { + bool is_sign; + + if( base<2 || base>16 ) + { + if( after_source ) + *after_source = source; + + return 1; + } + + SetZero(); + FromString_TestNewBase( source, base ); + FromString_TestSign( source, is_sign ); + + int c = FromString_ReadPartBeforeComma( source, base ); + + if( FromString_TestCommaOperator(source) ) + c += FromString_ReadPartAfterComma( source, base ); + + if( base==10 && FromString_TestScientific(source) ) + c += FromString_ReadPartScientific( source ); + + if( is_sign && !IsZero() ) + ChangeSign(); + + if( after_source ) + *after_source = source; + + return (c==0)? 0 : 1; + } + + + +private: + + + /*! + we're testing whether a user wants to change the base + + if there's a '#' character it means that the user wants the base to be 16, + if '&' the base will be 2 + */ + void FromString_TestNewBase( const char * & source, uint & base ) + { + UInt::SkipWhiteCharacters(source); + + if( *source == '#' ) + { + base = 16; + ++source; + } + else + if( *source == '&' ) + { + base = 2; + ++source; + } + } + + + /*! + we're testing whether the value is with the sign + + (this method is used from 'FromString_ReadPartScientific' too) + */ + void FromString_TestSign( const char * & source, bool & is_sign ) + { + UInt::SkipWhiteCharacters(source); + + is_sign = false; + + if( *source == '-' ) + { + is_sign = true; + ++source; + } + else + if( *source == '+' ) + { + ++source; + } + } + + + /*! + we're testing whether is there a comma operator + */ + bool FromString_TestCommaOperator(const char * & source) + { + if( (*source == MATHTT_COMMA_CHARACTER_1) || + (*source == MATHTT_COMMA_CHARACTER_2 && MATHTT_COMMA_CHARACTER_2 != 0 ) ) + { + ++source; + + return true; + } + + return false; + } + + + /*! + this method reads the first part of a string + (before the comma operator) + */ + uint FromString_ReadPartBeforeComma( const char * & source, uint base ) + { + int character; + Big temp; + Big base_( base ); + + UInt::SkipWhiteCharacters( source ); + + for( ; (character=UInt::CharToDigit(*source, base)) != -1 ; ++source ) + { + 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) + */ + uint FromString_ReadPartAfterComma( const char * & source, uint base ) + { + int character, c = 0, index = 1; + Big part, power, old_value, base_( base ); + + // we don't remove any white characters here + + power.SetOne(); + + for( ; (character=UInt::CharToDigit(*source, base)) != -1 ; ++source, ++index ) + { + 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 = *this; + + // there actually shouldn't be a carry here + c += Add( part ); + + if( testing && old_value == *this ) + // 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( ; UInt::CharToDigit(*source, base) != -1 ; ++source ); + + 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 + */ + bool FromString_TestScientific(const char * & source) + { + UInt::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 + */ + uint FromString_ReadPartScientific( const char * & source ) + { + int c = 0; + Big new_exponent, temp; + bool was_sign = false; + + FromString_TestSign( source, was_sign ); + FromString_ReadPartScientific_ReadExponent( source, new_exponent ); + + if( was_sign ) + new_exponent.ChangeSign(); + + temp = 10; + c += temp.PowBInt( 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) + */ + uint FromString_ReadPartScientific_ReadExponent( const char * & source, Big & new_exponent ) + { + int character; + Big base, temp; + + UInt::SkipWhiteCharacters(source); + + new_exponent.SetZero(); + base = 10; + + for( ; (character=UInt::CharToDigit(*source, 10)) != -1 ; ++source ) + { + temp = character; + + if( new_exponent.Mul(base) ) + return 1; + + if( new_exponent.Add(temp) ) + return 1; + } + + return 0; + } + + +public: + + + /*! + a method for converting a string into its value + */ + int FromString(const std::string & string, uint base = 10) + { + return FromString( string.c_str(), base ); + } + + + /*! + 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 std::string & 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 std::string & 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) + */ + bool SmallerWithoutSignThan(const Big & ss2) const + { + // we should check the mantissas beforehand because sometimes we can have + // a mantissa set to zero but in the exponent something another value + // (maybe we've forgotten about calling CorrectZero() ?) + if( mantissa.IsZero() ) + { + if( ss2.mantissa.IsZero() ) + // we've got two zeroes + return false; + else + // this==0 and ss2!=0 + return true; + } + + if( ss2.mantissa.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) + */ + bool GreaterWithoutSignThan(const Big & ss2) const + { + // we should check the mantissas beforehand because sometimes we can have + // a mantissa set to zero but in the exponent something another value + // (maybe we've forgotten about calling CorrectZero() ?) + if( mantissa.IsZero() ) + { + if( ss2.mantissa.IsZero() ) + // we've got two zeroes + return false; + else + // this==0 and ss2!=0 + return false; + } + + if( ss2.mantissa.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) + */ + bool EqualWithoutSign(const Big & ss2) const + { + // we should check the mantissas beforehand because sometimes we can have + // a mantissa set to zero but in the exponent something another value + // (maybe we've forgotten about calling CorrectZero() ?) + if( mantissa.IsZero() ) + { + if( ss2.mantissa.IsZero() ) + // we've got two zeroes + return true; + else + // this==0 and ss2!=0 + return false; + } + + if( ss2.mantissa.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 + + it's not changing 'this' but the changed value will be 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) const + { + Sub(ss2); + + return *this; + } + + + Big operator+(const Big & ss2) const + { + Big temp(*this); + + temp.Add(ss2); + + return temp; + } + + + Big & operator+=(const Big & ss2) const + { + Add(ss2); + + return *this; + } + + + Big operator*(const Big & ss2) const + { + Big temp(*this); + + temp.Mul(ss2); + + return temp; + } + + + Big & operator*=(const Big & ss2) const + { + Mul(ss2); + + return *this; + } + + + Big operator/(const Big & ss2) const + { + Big temp(*this); + + temp.Div(ss2); + + return temp; + } + + + Big & operator/=(const Big & ss2) const + { + 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( IsZero() ) + return; + + if( !exponent.IsSign() ) + // exponent >=0 -- the value don't have any fractions + return; + + if( exponent <= -int(man*BITS_PER_UINT) ) + { + // the value is from (-1,1), we return zero + SetZero(); + return; + } + + // exponent is in range (-man*BITS_PER_UINT, 0) + int 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( IsZero() ) + return; + + if( !exponent.IsSign() ) + { + // exponent >= 0 -- the value doesn't have any fractions + // we return zero + SetZero(); + return; + } + + if( exponent <= -int(man*BITS_PER_UINT) ) + { + // the value is from (-1,1) + // we don't make anything with the value + return; + } + + // e will be from (-man*BITS_PER_UINT, 0) + int e = exponent.ToInt(); + + int how_many_bits_leave = man*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 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; + + half.SetDotOne(); + + if( IsSign() ) + { + // 'this' is < 0 + c = Sub( half ); + } + else + { + // 'this' is >= 0 + c = Add( half ); + } + + SkipFraction(); + + return c; + } + + + + + + /*! + * + * input/output operators for standard streams + * + */ + + friend std::ostream & operator<<(std::ostream & s, const Big & l) + { + std::string ss; + + l.ToString(ss); + s << ss; + + return s; + } + + + friend std::istream & operator>>(std::istream & s, Big & l) + { + std::string ss; + + // 'char' for operator>> + unsigned char z; + bool was_comma = 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) + } + + // we're reading only digits (base=10) and only one comma operator + while( s.good() && + ( UInt::CharToDigit(z, 10)>=0 || (!was_comma && z==MATHTT_COMMA_CHARACTER_1) ) + ) + { + if( z == MATHTT_COMMA_CHARACTER_1 ) + was_comma = true; + + ss += z; + z = s.get(); + } + + // we're leaving the last readed character + // (it's not belonging to the value) + s.unget(); + + l.FromString( ss ); + + return s; + } + +}; + + +} // namespace + +#endif diff --git a/ttmath/ttmathint.h b/ttmath/ttmathint.h new file mode 100644 index 0000000..4b2553b --- /dev/null +++ b/ttmath/ttmathint.h @@ -0,0 +1,997 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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 it implements the big integer value with the sign + + value_size - how many bytes specify our value (value_size = 1 -> 4 bytes -> 32 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 SetMaxValue() + { + UInt::SetMaxValue(); + UInt::table[value_size-1] = ~uint_the_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 SetMinValue() + { + UInt::SetZero(); + UInt::table[value_size-1] = uint_the_highest_bit; + } + + + /*! + this method sets -1 as the value + (-1 is equal the max value in an unsigned type) + */ + void SetSignOne() + { + UInt::SetMaxValue(); + } + + + /*! + 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.SetMinValue(); + + /* + if the value is equal that one which has been returned from SetMinValue + 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 always make a negative value + */ + 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 returns the absolute value + + it can return carry (1) (look on ChangeSign() for details) + */ + uint Abs() + { + if( !IsSign() ) + return 0; + + return ChangeSign(); + } + + + + + /*! + * + * basic mathematic functions + * + */ + + /*! + this method adds two value with sign and returns 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); + + 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; + } + + + /*! + this method subtracts two values with the 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); + + 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; + } + + + /*! + this method adds one to the value and returns carry + */ + uint AddOne() + { + Int temp; + + temp.SetOne(); + + return Add(temp); + } + + + /*! + this method subtracts one from the value and returns carry + */ + uint SubOne() + { + Int temp; + + temp.SetOne(); + + return Sub(temp); + } + + + + /*! + 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 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 diffrent that means if the result + is different from that one which has been returned from SetMinValue() + that is carry (result too big) but if the result is equal SetMinValue() + 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 SetMinValue() + (there is ok situation) + */ + if( ss1_is_sign != ss2_is_sign ) + { + Int temp; + temp.SetMinValue(); + + 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 + function returns the remainder + + 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) = result * this(new) + remainder + */ + Int Div(Int ss2) + { + bool ss1_is_sign, ss2_is_sign; + Int remainder; + + 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(); + + remainder = UInt::Div(ss2); + + if( ss1_is_sign != ss2_is_sign ) + SetSign(); + + if( ss1_is_sign ) + remainder.SetSign(); + + return remainder; + } + + + + + + /*! + * + * convertion methods + * + */ + + /*! + this method convert an UInt type to 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) + { + uint min_size = (value_size < argument_size)? value_size : argument_size; + uint i; + + for(i=0 ; i::table[i] = p.table[i]; + + + if( i < value_size ) + { + uint fill = (p.table[argument_size-1] & uint_the_highest_bit)? uint_max_value : 0; + + for( ; i::table[i] = fill; + } + else + { + uint test = (UInt::table[value_size-1] & uint_the_highest_bit)? uint_max_value : 0; + + for( ; i type to this class + + it doesn't return a carry + */ + template + Int & operator=(const Int & p) + { + FromInt(p); + + return *this; + } + + + /*! + the default assignment operator + */ + Int & operator=(const Int & p) + { + FromInt(p); + + return *this; + } + + + /*! + this method convert an int type to this class + */ + Int & operator=(int i) + { + if(i<0) + SetSignOne(); + else + UInt::SetZero(); + + UInt::table[0] = uint(i); + + return *this; + } + + + /*! + constructor for converting an uint to this class + */ + Int(int i) + { + operator=(i); + } + + + /*! + constructor for converting string to this class (with base=10) + */ + Int(const char * s) + { + FromString(s); + } + + + /*! + constructor for converting string to this class (with base=10) + */ + Int(const std::string & s) + { + FromString( s.c_str() ); + } + + + /*! + default constructor + + we don't clear table etc. + */ + Int() + { + } + + + /*! + the copying constructor + */ + template + Int(const Int & u) : UInt::size(value_size) + { + // look that 'size' we still set as 'value_size' and not as u.value_size + + operator=(u); + } + + + /*! + a destructor + */ + virtual ~Int() + { + } + + /*! + this method returns the lowest value from table with the sign + + we must be sure when we using this method whether the value + will hold in an int type or not (the rest value from table must be zero or -1) + */ + int ToInt() const + { + return int( UInt::table[0] ); + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::string & 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); + } + } + + + + + /*! + 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) + */ + uint FromString(const char * s, uint b = 10) + { + bool is_sign = false; + + UInt::SkipWhiteCharacters(s); + + if( *s == '-' ) + { + is_sign = true; + UInt::SkipWhiteCharacters(++s); + } + else + if( *s == '+' ) + { + UInt::SkipWhiteCharacters(++s); + } + + if( UInt::FromString(s,b) ) + return 1; + + if( is_sign ) + { + Int mmin; + + mmin.SetMinValue(); + + /* + the reference to mmin will be automatically converted to the reference + to a UInt type + (this value can be equal mmin -- look at a description in ChangeSign()) + */ + if( UInt::operator>( mmin ) ) + return 1; + + ChangeSign(); + } + else + { + Int mmax; + + mmax.SetMaxValue(); + + if( UInt::operator>( mmax ) ) + return 1; + } + + return 0; + } + + + /*! + 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() ); + } + + + /*! + 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 std::string & s) + { + FromString( s.c_str() ); + + return *this; + } + + + + + /*! + * + * methods for comparing + * + * operators == and != will be the same as in the base class (UInt) + * + */ + + bool operator<(const Int & l) const + { + int i=value_size-1; + + int a1 = int(UInt::table[i]); + int a2 = int(l.table[i]); + + if( a1 != a2 ) + return a1 < a2; + + +// comparison as int +// if( int(UInt::table[i]) != int(l.table[i]) ) +// return int(UInt::table[i]) < int(l.table[i]); + + 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 + { + int i=value_size-1; + + + int a1 = int(UInt::table[i]); + int a2 = int(l.table[i]); + + if( a1 != a2 ) + return a1 > a2; + + // comparison as int +// if( int(UInt::table[i]) != int(l.table[i]) ) +// return int(UInt::table[i]) > int(l.table[i]); + + 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 + { + int i=value_size-1; + + + int a1 = int(UInt::table[i]); + int a2 = int(l.table[i]); + + if( a1 != a2 ) + return a1 < a2; + + // comparison as int +// if( int(UInt::table[i]) != int(l.table[i]) ) +// return int(UInt::table[i]) < int(l.table[i]); + + 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 + { + int i=value_size-1; + + + int a1 = int(UInt::table[i]); + int a2 = int(l.table[i]); + + if( a1 != a2 ) + return a1 > a2; + + // comparison as int +// if( int(UInt::table[i]) != int(l.table[i]) ) +// return int(UInt::table[i]) > int(l.table[i]); + + 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 ); + + return remainder; + } + + + Int & operator%=(const Int & p2) + { + Int temp(*this); + Int remainder = temp.Div( p2 ); + + 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--() + { + AddOne(); + + return *this; + } + + + UInt operator--(int) + { + UInt temp( *this ); + + SubOne(); + + return temp; + } + + + + /*! + * + * input/output operators for standard streams + * + */ + + friend std::ostream & operator<<(std::ostream & s, const Int & l) + { + std::string ss; + + l.ToString(ss); + s << ss; + + return s; + } + + + + friend std::istream & operator>>(std::istream & s, Int & l) + { + std::string ss; + + // char for operator>> + unsigned char 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() && UInt::CharToDigit(z, 10)>=0 ) + { + ss += z; + z = s.get(); + } + + // we're leaving the last readed character + // (it's not belonging to the value) + s.unget(); + + l.FromString(ss); + + return s; + } + +}; + +} // namespace + + +#endif diff --git a/ttmath/ttmathobjects.h b/ttmath/ttmathobjects.h new file mode 100644 index 0000000..81ab996 --- /dev/null +++ b/ttmath/ttmathobjects.h @@ -0,0 +1,181 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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 + +#include "ttmathtypes.h" + +#include +#include +#include + + +namespace ttmath +{ + + +class Objects +{ +public: + + struct ObjectValue + { + std::string value; + int param; + + ObjectValue() {} + ObjectValue(const std::string & v, int p) : value(v), param(p) {} + }; + + typedef std::map Table; + typedef Table::const_iterator CIterator; + + ErrorCode Add(const std::string & name, const std::string & value, int param = 0) + { + Table::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, ObjectValue(value, param)) ); + + return err_ok; + } + + + bool Empty() const + { + return table.empty(); + } + + void Clear() + { + return table.clear(); + } + + CIterator Begin() const + { + return table.begin(); + } + + CIterator End() const + { + return table.end(); + } + + ErrorCode Edit(const std::string & name, const std::string & value, int param = 0) + { + Table::iterator i = table.find(name); + + if( i == table.end() ) + // we don't have this variable in our table + return err_unknown_object; + + i->second.value = value; + i->second.param = param; + + return err_ok; + } + + + ErrorCode Delete(const std::string & name) + { + Table::iterator i = table.find(name); + + if( i == table.end() ) + // we don't have this variable in our table + return err_unknown_object; + + table.erase( i ); + + return err_ok; + } + + + ErrorCode GetValue(const std::string & name, const char * * value) const + { + Table::const_iterator i = table.find(name); + + if( i == table.end() ) + { + // we don't have this variable in our table + *value = 0; + return err_unknown_object; + } + + *value = i->second.value.c_str(); + + return err_ok; + } + + ErrorCode GetValueParam(const std::string & name, const char * * value, int * param) const + { + Table::const_iterator i = table.find(name); + + if( i == table.end() ) + { + // we don't have this variable in our table + *value = 0; + return err_unknown_object; + } + + *value = i->second.value.c_str(); + *param = i->second.param; + + return err_ok; + } + + Table * GetTable() + { + return &table; + } + + +private: + + Table table; + +}; + +} // namespace + +#endif diff --git a/ttmath/ttmathparser.h b/ttmath/ttmathparser.h new file mode 100644 index 0000000..8ba62f8 --- /dev/null +++ b/ttmath/ttmathparser.h @@ -0,0 +1,1705 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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 Mathematical parser +*/ + +#include +#include +#include +#include + +#include "ttmath.h" +#include "ttmathobjects.h" + + + +namespace ttmath +{ + +/*! + \brief Mathematical parser + + let x will be an input string means an expression for converting: + + x = [+|-]Value[operator[+|-]Value][operator[+|-]Value]... + where: + operator can be: + + (add) + - (sub) + * (mul) + / (div) + ^ (pow) + and Value can be: + constant e.g. 100 + 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, we can either use a comma or a dot in values) + (look at the macro MATHTT_COMMA_CHARACTER_2) + "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 + 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" + "semicolon operator" + "9" +*/ +template +class Parser +{ + +private: + +/*! + there are 5 mathematical operators as follows: + add (+) + sub (-) + mul (*) + div (/) + pow (^) + with their standard priorities +*/ + class MatOperator + { + public: + + enum Type + { + none,add,sub,mul,div,pow + }; + + + Type GetType() const { return type; } + int GetPriority() const { return priority; } + + + void SetType(Type t) + { + type = t; + + switch( type ) + { + case add: + case sub: + priority = 10; + break; + + case mul: + case div: + priority = 12; + break; + + case pow: + priority = 14; + break; + + default: + Error( err_internal_error ); + break; + } + } + + MatOperator(): type(none), priority(0) + { + } + + private: + + Type type; + int priority; + + }; // 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 + + when an error has occured it may be used to count the index of the wrong character +*/ +const char * pstring; + + +/*! + the base of the mathematic system (for example it may be '10') +*/ +int base; + + +/*! + 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 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; + + +/*! + 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; +} + + + +/*! + a 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 ); + } +} + + +/*! + a auxiliary method for RecurrenceParsingVariablesOrFunction(...) +*/ +void RecurrenceParsingVariablesOrFunction_AddName(bool variable, const std::string & name) +{ + if( variable ) + visited_variables.insert( name ); + else + visited_functions.insert( name ); +} + +/*! + a 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); + +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))(); + +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) +*/ + + +/*! + 'silnia' in polish language + 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, &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 ); + + result = ttmath::Sin(stack[sindex].value); +} + +void Cos(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + result = ttmath::Cos(stack[sindex].value); +} + +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(stack[sindex].value, &err); + + if(err != err_ok) + Error( err ); +} + +void CTan(int sindex, int amount_of_args, ValueType & result) +{ + if( amount_of_args != 1 ) + Error( err_improper_amount_of_arguments ); + + ErrorCode err; + result = ttmath::CTan(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 = ttmath::Round(stack[sindex].value); +} + + +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; + } +} + + +/*! + this method returns the value from a user-defined function + + (look at the description in 'CallFunction(...)') +*/ +bool GetValueOfUserDefinedFunction(const std::string & function_name, int amount_of_args, int sindex) +{ + if( !puser_functions ) + return false; + + const char * string_value; + int param; + + if( puser_functions->GetValueParam(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[20]; + + // x = x1 + sprintf(buffer,"x"); + 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); +} + + + + + +/*! + insert a function to the functions' table + + function_name - name of the function + pf - pointer to the function (to the wrapper) +*/ +void InsertFunctionToTable(const std::string & function_name, pfunction pf) +{ + functions_table.insert( std::make_pair(function_name, pf)); +} + + +/*! + insert 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 std::string & variable_name, pfunction_var pf) +{ + variables_table.insert( std::make_pair(variable_name, pf)); +} + + +/*! + this method create the table of functions +*/ +void CreateFunctionsTable() +{ + /* + names of functions should consist of small letters + */ + InsertFunctionToTable(std::string("factorial"), &Parser::Factorial); + InsertFunctionToTable(std::string("abs"), &Parser::Abs); + InsertFunctionToTable(std::string("sin"), &Parser::Sin); + InsertFunctionToTable(std::string("cos"), &Parser::Cos); + InsertFunctionToTable(std::string("tan"), &Parser::Tan); + InsertFunctionToTable(std::string("ctan"), &Parser::CTan); + InsertFunctionToTable(std::string("int"), &Parser::Int); + InsertFunctionToTable(std::string("round"), &Parser::Round); + InsertFunctionToTable(std::string("ln"), &Parser::Ln); + InsertFunctionToTable(std::string("log"), &Parser::Log); + InsertFunctionToTable(std::string("exp"), &Parser::Exp); + InsertFunctionToTable(std::string("max"), &Parser::Max); + InsertFunctionToTable(std::string("min"), &Parser::Min); +} + + +/*! + this method create the table of variables +*/ +void CreateVariablesTable() +{ + /* + names of variables should consist of small letters + */ + InsertVariableToTable(std::string("pi"), &ValueType::SetPi); + InsertVariableToTable(std::string("e"), &ValueType::SetE); +} + + +/*! + convert 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 = ToLowerCase(*pstring); + + /* + the first letter must be from range 'a' - 'z' + */ + if( character<'a' || character>'z' ) + Error( err_unknown_character ); + + + do + { + result += character; + character = ToLowerCase( * ++pstring ); + } + while( (character>='a' && character<='z') || + (character>='0' && character<='9') ); + + + SkipWhiteCharacters(); + + + /* + if there's 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) +{ +const char * new_stack_pointer; + + int carry = result.value.FromString(pstring, base, &new_stack_pointer); + pstring = new_stack_pointer; + + if( carry ) + Error( err_overflow ); +} + + + +/*! + this method converts the character ascii c into the value in range <0;base-1> + + if the character is incorrect for this base the funcion will return -1 +*/ +int CharToDigit(int c, int 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 c; +} + + +/*! + 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=='#' || character=='&' || CharToDigit(character, base)!=-1 ) + { + /* + warning: + if we're using for example the base equal 16 + we can find a first character like 'e' that is there is not e=2.71.. + but the value 14, for this case we must use something like var::e for variables + (not implemented yet) + */ + ReadValue( result ); + } + 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; +} + + + + +/*! + this method's reading one of the mathematic operators + or the final bracket or the semicolon operator + + return values: + 0 - ok + 1 - the string is finished +*/ +int ReadOperator(Item & result) +{ + SkipWhiteCharacters(); + result.type = Item::mat_operator; + + switch( *pstring ) + { + case 0: + return 1; + + case '-': + result.moperator.SetType( MatOperator::sub ); + break; + + case '+': + result.moperator.SetType( MatOperator::add ); + break; + + case '*': + result.moperator.SetType( MatOperator::mul ); + break; + + case '/': + result.moperator.SetType( MatOperator::div ); + break; + + case '^': + result.moperator.SetType( MatOperator::pow ); + break; + + case ')': + result.type = Item::last_bracket; + break; + + case ';': + result.type = Item::semicolon; + break; + + default: + Error( err_unknown_character ); + } + + ++pstring; + +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) +{ +int res; + + + switch( mat_operator ) + { + 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: + 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 && + stack[stack_index-3].moperator.GetPriority() >= stack[stack_index-1].moperator.GetPriority() + ) + { + 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 kod = ReadValueVariableOrFunction( temp ); + + if( kod == 0 ) + { + if( stack_index < stack.size() ) + stack[stack_index] = temp; + else + stack.push_back( temp ); + + ++stack_index; + } + + if( kod == 2 ) + // there was a final bracket, we didn't push it into the stack + // (it'll be read by the 'ReadOperatorAndCheckFinalBracket' method next) + kod = 0; + + +return kod; +} + + + +/*! + this method calculate how many parameters there are on the stack + and 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 ); + + 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 + */ + if( stack[index-1].sign ) + { + stack[index-1].value.ChangeSign(); + stack[index-1].sign = false; + } + + 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; + error = err_ok; + + CreateFunctionsTable(); + CreateVariablesTable(); +} + + +/*! + the copying 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; + error = err_ok; + + /* + we don't have to call 'CreateFunctionsTable()' and 'CreateVariablesTable()' + we can only copy these tables + */ + functions_table = p.functions_table; + variables_table = p.variables_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 +*/ +void SetBase(int b) +{ + if( b>=2 && b<=16 ) + base = b; +} + + +/*! + 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; +} + + +/*! + the main method using for parsing string +*/ +ErrorCode Parse(const char * str) +{ + stack_index = 0; + pstring = str; + error = err_ok; + + stack.resize( default_stack_size ); + +// char buf_temp[] = "1111"; +// pstring = buf_temp; + + try + { + Parse(); + } + catch(ErrorCode c) + { + error = c; + } + + NormalizeStack(); + +return error; +} + + + + + +}; + +} // namespace + + +#endif diff --git a/ttmath/ttmathtypes.h b/ttmath/ttmathtypes.h new file mode 100644 index 0000000..af84c27 --- /dev/null +++ b/ttmath/ttmathtypes.h @@ -0,0 +1,284 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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 A Documented file. + + Details. +*/ + + +#include +#include +#include +#include + + + + +/*! + the version of the library +*/ +#define TTMATH_MAJOR_VER 0 +#define TTMATH_MINOR_VER 6 +#define TTMATH_REVISION_VER 2 + + + + + + + + +/*! + 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 macro MATHTT_ASSERT is set as well + and MATHTT_ASSERT can throw an exception if a condition is not fulfilled + (look at the definition of MATHTT_ASSERT) + + if you don't want any further testing put two characters '//' before this macro + e.g. + // #define MATHTT_DEBUG +*/ +#define MATHTT_DEBUG + + +/*! + 32 bit integer value without a sign + (the same on 64 bits platform (amd)) +*/ +typedef unsigned int uint; + + +/*! + how many bits there are in the uint type +*/ +#define BITS_PER_UINT 32u + + +/*! + the mask for the highest bit in the unsigned 32bits word (2^31) +*/ +#define uint_the_highest_bit 2147483648u + + +/*! + the max value of the unsigned 32bits word (2^32 - 1) + (all bits equal one) +*/ +#define uint_max_value 4294967295u + + +/*! + if you define this macro that means the version one of the multiplication algorithm + will be used in the UInt class +*/ +//#define UINT_MUL_VERSION_1 + + + +/*! + if you define this macro that means the version two of the multiplication algorithm + will be used in the UInt class + + this algorithm is much faster than previous + + you can't use both these macros together, you must use either UINT_MUL_VERSION_1 + or UINT_MUL_VERSION_2 +*/ +#define UINT_MUL_VERSION_2 + + + +/*! + characters which represent the comma operator + + MATHTT_COMMA_CHARACTER_1 is used in reading (parsing) and in writing + MATHTT_COMMA_CHARACTER_2 can be used in reading as an auxiliary comma character + that means you can input values for example 1.2345 and 1,2345 as well + + if you don't want it just put 0 there eg. + #define MATHTT_COMMA_CHARACTER_2 0 + then only MATHTT_COMMA_CHARACTER_1 will be used + + don't put here any special character which is used by the parser + (for example a semicolon ';' shouldn't be here) +*/ +#define MATHTT_COMMA_CHARACTER_1 '.' +#define MATHTT_COMMA_CHARACTER_2 ',' +////!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +//// odwrocic nazwy ma byc TTMATH + + + + +namespace ttmath +{ + /*! + error codes + */ + enum ErrorCode + { + err_ok = 0, + err_nothing_has_read = 1, + err_unknown_character = 2, + err_unexpected_final_bracket = 4, + err_stack_not_clear = 6, + err_unknown_variable = 8, + err_division_by_zero = 9, + err_interrupt = 10, + err_overflow = 11, + err_unknown_function = 12, + err_unexpected_semicolon_operator = 18, + err_improper_amount_of_arguments = 19, + err_improper_argument = 20, + err_unexpected_end = 21, + err_internal_error = 100, + + 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_this_cant_be_used = 200 + }; + + + + class StopCalculating + { + public: + virtual bool WasStopSignal() const volatile { return false; } + virtual ~StopCalculating(){} + }; + + + + + + + +// moze tutaj z runtime dziedziczyc? + //zmienic nazwe na TTMathError + class MathTTError : public std::exception + { + ErrorCode code; + + public: + MathTTError(ErrorCode c) : code(c) {} + const char* what() const throw() + { + switch( code ) + { + case err_this_cant_be_used: + return "You've used 'this' somewhere in your code but you can't use it there"; + // dac tu jakis lepszy komunikat w stylu + // 'uzyles referencji do samego siebie ale w tym miejscu nie mozesz tego zrobic' + default: + return ":)"; // temporary + } + + return "Unnamed"; + } + }; + + #ifdef MATHTT_DEBUG + #define MATHTT_ASSERT(expression, c) \ + if( !(expression) ) throw MathTTError(c); + #else + #define MATHTT_ASSERT(expression, c) + #endif + + #define MATHTT_THIS_ASSERT(expression) \ + MATHTT_ASSERT( &expression != this, err_this_cant_be_used) + + + +/* + template + class ValuesHistory + { + typedef std::map buffer_type; + buffer_type buffer; + + public: + + void AddValue(const ValueType & key, const ValueType & result) + { + buffer.insert( std::make_pair(key, result) ); + } + + bool GetValue(const ValueType & key, ValueType & result) const + { + buffer_type::iterator i = buffer.find( key ); + + if( i == buffer.end() ) + return false; + + result = *i; + + return true; + } + + uint Size() const + { + return static_cast( buffer.size() ); + } + }; +*/ + +} // namespace + + + + + +#endif diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h new file mode 100644 index 0000000..a3f72e0 --- /dev/null +++ b/ttmath/ttmathuint.h @@ -0,0 +1,2846 @@ +/* + * This file is part of TTMath Mathematical Library + * and is distributed under the (new) BSD licence. + * Author: Tomasz Sowa + */ + +/* + * Copyright (c) 2006-2007, 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 "ttmathtypes.h" + +#define TTMATH_UINT_GUARD 1234567891 + +// !!! +extern bool bylocos; + +namespace ttmath +{ + +/*! + \brief it implements the big integer value without the sign + + value_size - how many bytes specify our value (value_size = 1 -> 4 bytes -> 32 bits) + value_size = 1,2,3,4,5,6.... +*/ +template +class UInt +{ +public: + + uint guard1; + + /*! + buffer for this integer value + the first value (index 0) means the lowest word of this value + */ + uint table[value_size]; + + uint guard2; + + /*! + it returns the size of the table + */ + uint Size() const + { + return value_size; + } + + + /*! + this method sets value zero + */ + void SetZero() + { + for(uint i=0 ; i=0 && temp_table_index=0 ; --i) + table[i] = 0; + } + + + /*! + * + * basic mathematic functions + * + */ + + + /*! + 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) + */ + uint Add(const UInt & ss2, uint c=0) + { + register int b = value_size; + register uint * p1 = table; + register uint * p2 = const_cast(ss2.table); + + + #ifndef __GNUC__ + /* + this part might be compiled with for example visual c + */ + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx,[b] + + mov ebx,[p1] + mov edx,[p2] + + mov eax,0 + sub eax,[c] + + p: + mov eax,[ebx] + adc eax,[edx] + mov [ebx],eax + + inc ebx + inc ebx + inc ebx + inc ebx + + inc edx + inc edx + inc edx + inc edx + + loop p + + mov eax,0 + adc eax,eax + mov [c],eax + + pop edx + pop ecx + pop ebx + pop eax + } + #endif + + + #ifdef __GNUC__ + /* + this part should be compiled with gcc + */ + __asm__ __volatile__( + + "push %%ebx \n" + "push %%ecx \n" + "push %%edx \n" + + "movl $0, %%eax \n" + "subl %%esi, %%eax \n" + + "1: \n" + "movl (%%ebx),%%eax \n" + "adcl (%%edx),%%eax \n" + "movl %%eax,(%%ebx) \n" + + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + + "inc %%edx \n" + "inc %%edx \n" + "inc %%edx \n" + "inc %%edx \n" + + "loop 1b \n" + + "movl $0, %%eax \n" + "adcl %%eax,%%eax \n" + "movl %%eax, %%esi \n" + + "pop %%edx \n" + "pop %%ecx \n" + "pop %%ebx \n" + + : "=S" (c) + : "0" (c), "c" (b), "b" (p1), "d" (p2) + : "eax", "cc", "memory" ); + + + #if !defined(__i386__) && !defined(__amd64__) + /* + when you try to build this program on an another platform + than x86/amd64 you'll see the following message + */ + #error "This code is designed only for x86/amd64 platforms" + #endif + + + #endif + + + + return c; + } + + + + + + /*! + this method addes 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.) + */ + uint AddTwoUints(uint index, uint x2, uint x1) + { + register int b = value_size; + register uint * p1 = table; + register uint c; + + #ifndef __GNUC__ + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx, [b] + sub ecx, [index] + + mov edx, [index] + mov eax, [p1] + + lea ebx, [eax+4*edx] + + mov edx, 0 + + mov eax, [ebx] + add eax, [x1] + mov [ebx], eax + + inc ebx + inc ebx + inc ebx + inc ebx + + mov eax, [ebx] + adc eax, [x2] + mov [ebx], eax + jnc end + + dec ecx + dec ecx + jz end + + p: + inc ebx + inc ebx + inc ebx + inc ebx + + mov eax,[ebx] + adc eax, edx + mov [ebx], eax + + jnc end + + loop p + + end: + + mov eax,0 + adc eax,eax + mov [c],eax + + pop edx + pop ecx + pop ebx + pop eax + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%ebx \n" + "push %%ecx \n" + "push %%edx \n" + + "subl %%edx, %%ecx \n" + + "leal (%%ebx,%%edx,4), %%ebx \n" + + "movl $0, %%edx \n" + + "movl (%%ebx), %%eax \n" + "addl %4, %%eax \n" + "movl %%eax, (%%ebx) \n" + + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + + "movl (%%ebx), %%eax \n" + "adcl %5, %%eax \n" + "movl %%eax, (%%ebx) \n" + "jnc 2f \n" + + "dec %%ecx \n" + "dec %%ecx \n" + "jz 2f \n" + + "1: \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + + "movl (%%ebx), %%eax \n" + "adcl %%edx, %%eax \n" + "movl %%eax, (%%ebx) \n" + + "jnc 2f \n" + + "loop 1b \n" + + "2: \n" + + "movl $0, %%eax \n" + "adcl %%eax,%%eax \n" + + "pop %%edx \n" + "pop %%ecx \n" + "pop %%ebx \n" + + : "=a" (c) + : "c" (b), "d" (index), "b" (p1), "m" (x1), "m" (x2) + : "cc", "memory" ); + + #endif + + + return c; + } + + + + + + /*! + this method subtracting ss2 from the this and subtracting 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) + */ + uint Sub(const UInt & ss2, uint c=0, int last_index = -1) + { + register int b; + + if( last_index == -1 ) + b = value_size; + else + b = last_index + 1; + + + register uint * p1 = table; + register uint * p2 = const_cast(ss2.table); + + #ifndef __GNUC__ + + __asm + { + push eax + push ebx + push ecx + push edx + + mov ecx,[b] + + mov ebx,[p1] + mov edx,[p2] + + mov eax,0 + sub eax,[c] + + p: + mov eax,[ebx] + sbb eax,[edx] + mov [ebx],eax + + inc ebx + inc ebx + inc ebx + inc ebx + + inc edx + inc edx + inc edx + inc edx + + loop p + + mov eax,0 + adc eax,eax + mov [c],eax + + pop edx + pop ecx + pop ebx + pop eax + } + + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%ebx \n" + "push %%ecx \n" + "push %%edx \n" + + "movl $0, %%eax \n" + "subl %%esi, %%eax \n" + + "1: \n" + "movl (%%ebx),%%eax \n" + "sbbl (%%edx),%%eax \n" + "movl %%eax,(%%ebx) \n" + + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + + "inc %%edx \n" + "inc %%edx \n" + "inc %%edx \n" + "inc %%edx \n" + + "loop 1b \n" + + "movl $0, %%eax \n" + "adcl %%eax,%%eax \n" + "movl %%eax, %%esi \n" + + "pop %%edx \n" + "pop %%ecx \n" + "pop %%ebx \n" + + : "=S" (c) + : "0" (c), "c" (b), "b" (p1), "d" (p2) + : "eax", "cc", "memory" ); + + #endif + + + return c; + } + + + /*! + this method adds one to the existing value + */ + uint AddOne() + { + UInt temp; + + temp.SetOne(); + + return Add(temp); + } + + + /*! + this method subtracts one from the existing value + */ + uint SubOne() + { + UInt temp; + + temp.SetOne(); + + return Sub(temp); + } + + + /*! + this method moving once all bits into the left side + return value <- this <- C + + the lowest bit will hold value of 'c' and + function returns the highest bit + */ + uint Rcl(uint c=0) + { + register int b = value_size; + register uint * p1 = table; + + + #ifndef __GNUC__ + __asm + { + push eax + push ebx + push ecx + + mov ecx,[b] + mov ebx,[p1] + + mov eax,0 + sub eax,[c] + + p: + rcl dword ptr[ebx],1 + + inc ebx + inc ebx + inc ebx + inc ebx + + loop p + + mov eax,0 + adc eax,eax + mov [c],eax + + pop ecx + pop ebx + pop eax + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%ebx \n" + "push %%ecx \n" + + "movl $0,%%eax \n" + "sub %%edx,%%eax \n" + + "1: \n" + "rcll $1,(%%ebx) \n" + + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + + "loop 1b \n" + + "mov $0, %%edx \n" + "adc %%edx,%%edx \n" + + "pop %%ecx \n" + "pop %%ebx \n" + + : "=d" (c) + : "0" (c), "c" (b), "b" (p1) + : "eax", "cc", "memory" ); + + #endif + + + return c; + } + + + /*! + this method moving once all bits into the right side + C -> *this -> return value + + the highest bit will be held value of 'c' and + function returns the lowest bit + */ + uint Rcr(uint c=0) + { + register int b = value_size; + register uint * p1 = table; + + + #ifndef __GNUC__ + __asm + { + push eax + push ebx + push ecx + + mov ecx,[b] + + add ecx,ecx + add ecx,ecx + + mov ebx,[p1] + add ebx,ecx + + mov ecx,[b] + + mov eax,0 + sub eax,[c] + + p: + dec ebx + dec ebx + dec ebx + dec ebx + + rcr dword ptr [ebx],1 + + loop p + + mov eax,0 + adc eax,eax + mov [c],eax + + pop ecx + pop ebx + pop eax + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%ebx \n" + "push %%ecx \n" + + "movl %%ecx,%%eax \n" + "addl %%ecx,%%ecx \n" + "addl %%ecx,%%ecx \n" + + "addl %%ecx,%%ebx \n" + "movl %%eax, %%ecx \n" + + "movl $0, %%eax \n" + "subl %%edx, %% eax \n" + + "1: \n" + "dec %%ebx \n" + "dec %%ebx \n" + "dec %%ebx \n" + "dec %%ebx \n" + + "rcrl $1,(%%ebx) \n" + + "loop 1b \n" + + "mov $0, %%edx \n" + "adc %%edx,%%edx \n" + + "pop %%ecx \n" + "pop %%ebx \n" + + : "=d" (c) + : "0" (c), "c" (b), "b" (p1) + : "eax", "cc", "memory" ); + + #endif + + + return c; + } + + + /*! + this method moving all bits into the left side 'bits' times + return value <- this <- C + + bits is from a range of <0, man * 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) + { + int first; + int second; + int last_c = 0; + + if( bits > value_size*BITS_PER_UINT ) + bits = value_size*BITS_PER_UINT; + + int all_words = int(bits) / int(BITS_PER_UINT); + + if( all_words > 0 ) + { + // copying the first part of the value + for(first = value_size-1, second=first-all_words ; second>=0 ; --first, --second) + { + last_c = table[first] & 1; + table[first] = table[second]; + } + + // sets the rest bits of value into 'c' + uint mask = (c!=0)? uint_max_value : 0; + for( ; first>=0 ; --first ) + table[first] = mask; + } + + int rest_bits = int(bits) % int(BITS_PER_UINT); + for( ; rest_bits > 0 ; --rest_bits ) + last_c = Rcl(c); + + return last_c; + } + + + /*! + this method moving all bits into the right side 'bits' times + c -> this -> return value + + bits is from a range of <0, man * 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) + { + int first; + int second; + int last_c = 0; + + if( bits > value_size*BITS_PER_UINT ) + bits = value_size*BITS_PER_UINT; + + int all_words = int(bits) / int(BITS_PER_UINT); + + if( all_words > 0 ) + { + // copying the first part of the value + for(first=0, second=all_words ; second 0 ; --rest_bits ) + last_c = Rcr(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 + int a; + for(a=value_size-1 ; a>=0 && table[a]==0 ; --a); + + if( a < 0 ) + { + // there's a value zero + return moving; + } + + if( a != value_size-1 ) + { + moving += ( value_size-1 - a ) * BITS_PER_UINT; + + // moving all words + int i; + for(i=value_size-1 ; i>=0 && a>=0; --i, --a) + table[i] = table[a]; + + // setting the rest word to zero + for(; i>=0 ; --i) + table[i] = 0; + } + + // moving the rest bits (max BITS_PER_UINT -- only one word) + while( !IsTheHighestBitSet() ) + { + Rcl(); + ++moving; + } + + return moving; + } + + + /* + this method returns the number of the highest set bit in one 32-bit word + if the 'x' is zero this method returns '-1' + */ + static int FindLeadingBit32(uint x) + { + register int result; + + #ifndef __GNUC__ + __asm + { + push eax + + bsr eax, x + jnz found + mov eax, -1 + found: + mov result, eax + + pop eax + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "bsrl %1, %0 \n" + "jnz 1f \n" + "mov $-1, %0 \n" + "1: \n" + + : "=q" (result) + : "q" (x) + : "cc" ); + + #endif + + + return result; + } + + + /*! + 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..31> + + 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] != 0 + index = FindLeadingBit32( table[table_id] ); + + return true; + } + + + /*! + it sets the bit bit_index + + bit_index bigger or equal zero + */ + void SetBit(uint bit_index) + { + uint index = bit_index / BITS_PER_UINT; + if( index >= value_size ) + return; + + bit_index %= BITS_PER_UINT; + uint result = 1; + + if( bit_index > 0 ) + result <<= bit_index; + + table[index] |= result; + } + + + + #ifdef UINT_MUL_VERSION_1 + + /*! + the first version of the multiplication algorithm + */ + + /*! + multiplication: this = this * ss2 + + it returns carry if it has been + + we can't use a reference to the ss2 because someone can use this + method in this way: mul(*this) + */ + uint Mul(const UInt & ss2) + { + MATHTT_THIS_ASSERT( ss2 ) + + UInt ss1( *this ); + SetZero(); + + for(uint i=0; i < value_size*BITS_PER_UINT ; ++i) + { + if( Add(*this) ) + return 1; + + if( ss1.Rcl() ) + if( Add(ss2) ) + return 1; + } + + return 0; + } + + + /*! + multiplication: result = this * ss2 + + result is twice bigger than 'this' and 'ss2' + this method never returns carry + */ + void Mul(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; + + Mul(ss2, result); + + // copying result + for(i=0 ; i u( *this ); + SetZero(); + + for(uint x1=0 ; x1 & ss2, UInt & result) + { + uint r2,r1; + + result.SetZero(); + + for(uint x1=0 ; x1 dividend(*this); + SetZero(); + + int 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) + Div64(r, dividend.table[i], divisor, &table[i], &r); + + if( remainder ) + *remainder = r; + + 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 + +// !!!!!!!!!!! + we've got two algorithms: + 1. with Log(n) where n is the max value which should be held in this class + (Log(n) will be equal to the number of bits there are in the table) + (on one loop there are one Rcl one Add and one Add or Sub) + 2. if only the first word in ss2 is given (ss2.table[0] != 0) and the rest from + ss2.table is equal zero + this algorithm has O(n) where n is the number of words there are in the table + (on one loop it's only one hardware division) + + For example if we've got value_size equal 4 then: + 1 algorithm: O = 4*32 = 128 (4 words with 32 bits) * (Rcl,Add, Add|Sub) + 2 algorithm: O = 4 * Div64 (hardware) + + The second algorithm is much faster than first but at the moment it's only + used for values where only first word (ss2.table[0]) is given. +// !!!!!!!!!!! + */ + uint Div( const UInt & divisor, + UInt * remainder = 0, + uint algorithm = 1) + { + 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(); + return 0; + + case 3: // 'this' is smaller than v + if( remainder ) + *remainder = *this; + + SetZero(); + return 0; + + case 2: // 'this' is zero + if( remainder ) + remainder->SetZero(); + + SetZero(); + return 0; + + case 1: // v is zero + return 1; + } + + 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) + { + for(n = value_size-1 ; n!=0 && v.table[n]==0 ; --n); + + if( n==0 && v.table[n]==0 ) + return 1; + + for(m = value_size-1 ; 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's 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) + { + MATHTT_THIS_ASSERT( divisor ) + + int loop; + int c; + + rest.SetZero(); + loop = value_size * BITS_PER_UINT; + c = 0; + + + div_a: + c = Rcl(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(c); + return 0; + + + div_c: + c = Rcl(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(c); + c = rest.Add(divisor); + + return 0; + } + + +public: + + + /*! + the second division algorithm + + return values: + 0 - ok + 1 - division by zero + */ + uint Div2(const UInt & divisor, UInt * remainder = 0) + { + MATHTT_THIS_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); + } + + 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 ) + 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(); + --bits_diff; + } + + Sub(divisor_copy, 0, table_id); + + 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 + return 1; + + if( !FindLeadingBit(table_id, index) ) + { + // zero is divided by something + + SetZero(); + + if( remainder ) + remainder->SetZero(); + + return 0; + } + + divisor_index += divisor_table_id * BITS_PER_UINT; + index += table_id * 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; + } + + return 0; + } + + + if( Div2_DivisorGreaterOrEqual( divisor, remainder, + table_id, index, + divisor_table_id, divisor_index) ) + return 0; + + + 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_table_id, uint divisor_index ) + { + if( divisor_index > index ) + { + // divisor is greater than this + + if( remainder ) + *remainder = *this; + + SetZero(); + + 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(); + + return true; + } + else + if( table[i] == divisor.table[i] ) + { + // divisor is equal 'this' + + if( remainder ) + remainder->SetZero(); + + SetOne(); + + return true; + } + } + + 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) + { + MATHTT_THIS_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; + } + + 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); + + return 0; + } + + + +private: + + + void Div3_Division(UInt v, UInt * remainder, uint m, uint n) + { + MATHTT_ASSERT( n>=2, ttmath::err_internal_error ) + + 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) + { + uint c = 0; + + for( d = 0 ; (v.table[n-1] & uint_the_highest_bit) == 0 ; ++d ) + { + // we can move the bits only to the 'n-1' index but at the moment + // we don't have such method + // maybe it's time to write it now? + v.Rcl(0); + + c <<= 1; + + if( Rcl(0) ) + c += 1; + } + + return c; + } + + + void Div3_Unnormalize(UInt * remainder, uint n, uint d) + { + for(uint i=n ; i u_temp; + uint rp; + bool next_test; + + u_temp.table[1] = u2; + u_temp.table[0] = u1; + u_temp.DivInt(v1, &rp); + + MATHTT_ASSERT( u_temp.table[1]==0 || u_temp.table[1]==1, ttmath::err_internal_error); + + do + { + bool decrease = false; + + if( u_temp.table[1] == 1 ) + decrease = true; + else + { + UInt<2> temp1, temp2; + + UInt<2>::Mul64(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(); + +// uint rp_old = rp; + rp += v1; + + if( rp >= v1 ) // it means that there wasn't a carry (r= rp_old ) // it means that there wasn't a carry (r & uu, + const UInt & vv, uint & qp) + { + 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); + } + } + + + + + + +public: + + /*! + this method sets n firt 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*BITS_PER_UINT ) + { + SetZero(); + return; + } + + uint * p = table; + + // first we're clearing the whole words + while( n >= BITS_PER_UINT ) + { + *p++ = 0; + n -= BITS_PER_UINT; + } + + if( n == 0 ) + return; + + // and then we're clearing one word which has left + // mask -- all bits are set to one + uint mask = uint_max_value; + + mask = mask << n; + + (*p) &= mask; + } + + + /*! + it returns true if the highest bit of the value is set + */ + bool IsTheHighestBitSet() const + { + return (table[value_size-1] & uint_the_highest_bit) == uint_the_highest_bit; + } + + + /*! + it returns true if the lowest bit of the value is set + */ + bool IsTheLowestBitSet() const + { + return (*table & 1) == 1; + } + + + /*! + it returns true if the value is equal zero + */ + bool IsZero() const + { + for(uint i=0 ; i 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 int 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 int(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'; + } + + + /*! + this method convert 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::SetMaxValue() + + 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 type to this class + + it doesn't return a carry + */ + template + UInt & operator=(const UInt & p) + { + FromUInt(p); + + return *this; + } + + /*! + the default assignment operator + */ + UInt & operator=(const UInt & p) + { + FromUInt(p); + + return *this; + } + + /*! + this method convert an uint type to this class + */ + UInt & operator=(uint i) + { + SetZero(); + table[0] = i; + + return *this; + } + + + /*! + constructor for converting an uint to this class + */ + UInt(uint i) + { + guard1 = TTMATH_UINT_GUARD; + guard2 = TTMATH_UINT_GUARD; + + operator=(i); + } + + + /*! + constructor for converting string to this class (with base=10) + */ + UInt(const char * s) + { + guard1 = TTMATH_UINT_GUARD; + guard2 = TTMATH_UINT_GUARD; + + FromString(s); + } + + + /*! + constructor for converting string to this class (with base=10) + */ + UInt(const std::string & s) + { + guard1 = TTMATH_UINT_GUARD; + guard2 = TTMATH_UINT_GUARD; + + FromString( s.c_str() ); + } + + + /*! + the default constructor + + we don't clear table etc. + */ + UInt() + { + guard1 = TTMATH_UINT_GUARD; + guard2 = TTMATH_UINT_GUARD; + } + + + /*! + the copying constructor + */ + UInt(const UInt & u) + { + guard1 = TTMATH_UINT_GUARD; + guard2 = TTMATH_UINT_GUARD; + + FromUInt(u); + } + + + /*! + template for producting constructors for copying from another types + */ + template + UInt(const UInt & u) + { + guard1 = TTMATH_UINT_GUARD; + guard2 = TTMATH_UINT_GUARD; + + // look that 'size' we still set as 'value_size' and not as u.value_size + + FromUInt(u); + } + + + /*! + a destructor + */ + virtual ~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 table must be zero) + */ + uint ToUInt() const + { + return table[0]; + } + + + /*! + this method converts the value to a string with a base equal 'b' + */ + void ToString(std::string & 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 = DigitToChar( rem ); + result.insert(result.begin(), character); + } + while( !temp.IsZero() ); + + return; + } + + + + + /* + this method's ommiting any white characters from the string + */ + static void SkipWhiteCharacters(const char * & c) + { + while( (*c==' ' ) || (*c=='\t') || (*c==13 ) || (*c=='\n') ) + ++c; + } + + /*! + 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 + */ + uint FromString(const char * s, uint b = 10) + { + UInt base( b ); + UInt temp; + int z; + + SetZero(); + temp.SetZero(); + SkipWhiteCharacters(s); + + if( b<2 || b>16 ) + return 1; + + for( ; (z=CharToDigit(*s, b)) != -1 ; ++s) + { + temp.table[0] = z; + + if( Mul(base) ) + return 1; + + if( Add(temp) ) + return 1; + } + + return 0; + } + + + + /*! + 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 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 std::string & s) + { + FromString( s.c_str() ); + + return *this; + } + + + /*! + * + * methods for comparing + * + */ + + + bool CmpSmaller(const UInt & l, int index = -1) const + { + int i; + + if( index==-1 || index>=int(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; + } + + + + bool CmpBigger(const UInt & l, int index = -1) const + { + int i; + + if( index==-1 || index>=int(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; + } + + + bool CmpEqual(const UInt & l, int index = -1) const + { + int i; + + if( index==-1 || index>=int(value_size) ) + i = value_size - 1; + else + i = index; + + + for( ; i>=0 ; --i) + if( table[i] != l.table[i] ) + return false; + + return true; + } + + bool CmpSmallerEqual(const UInt & l, int index=-1) const + { + int i; + + if( index==-1 || index>=int(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; + } + + bool CmpBiggerEqual(const UInt & l, int index=-1) const + { + int i; + + if( index==-1 || index>=int(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; + } + + + // + + bool operator<(const UInt & l) const + { + for(int i=value_size-1 ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] < l.table[i]; + } + + // they're equal + return false; + } + + + + bool operator>(const UInt & l) const + { + for(int i=value_size-1 ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] > l.table[i]; + } + + // they're equal + return false; + } + + + bool operator==(const UInt & l) const + { + for(uint i=0 ; i & l) const + { + return !operator==(l); + } + + + bool operator<=(const UInt & l) const + { + for(int i=value_size-1 ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] < l.table[i]; + } + + // they're equal + return true; + } + + bool operator>=(const UInt & l) const + { + for(int i=value_size-1 ; i>=0 ; --i) + { + if( table[i] != l.table[i] ) + return table[i] > l.table[i]; + } + + // they're equal + return true; + } + + + /*! + * + * 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--() + { + AddOne(); + + return *this; + } + + + UInt operator--(int) + { + UInt temp( *this ); + + SubOne(); + + return temp; + } + + + + + + /*! + * + * input/output operators for standard streams + * + */ + + friend std::ostream & operator<<(std::ostream & s, const UInt & l) + { + std::string ss; + + l.ToString(ss); + s << ss; + + return s; + } + + + + friend std::istream & operator>>(std::istream & s, UInt & l) + { + std::string ss; + + // char for operator>> + unsigned char z; + + // operator>> omits white characters if they're set for ommiting + s >> z; + + // we're reading only digits (base=10) + while( s.good() && CharToDigit(z, 10)>=0 ) + { + ss += z; + z = s.get(); + } + + // we're leaving the last readed character + // (it's not belonging to the value) + s.unget(); + + l.FromString(ss); + + return s; + } + + +}; + + +} //namespace + + + + +#endif