From b59de3609519455d032df5c4d519792150d36eb4 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Mon, 29 Jan 2007 17:58:18 +0000 Subject: [PATCH] fixed the problem with a sign in the mathematical parser /-(1) was 1/ added UInt::AddInt and UInt::SubInt changed UInt::AddOne and UInt::SubOne (much faster now) added UInt::SetBitInWord changed UInt::SetBit (much faster now) UInt::AddTwoUints renamed to UInt::AddTwoInts UInt::FindLeadingBit32 renamed to UInt::FindLeadingBitInWord added UInt::SetBitInWord UInt::Mul64 renamed to UInt::MulTwoWords UInt::Div64 renamed to UInt::DivTwoWords and more small changes in UInt type start adding support for Amd64 (not finished yet) (added ttmathuint64.h) git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@12 e52654a7-88a9-db11-a3e9-0013d4bc506e --- CHANGELOG | 14 + ttmath/ttmath.h | 4 +- ttmath/ttmathbig.h | 178 +++++---- ttmath/ttmathint.h | 36 +- ttmath/ttmathparser.h | 14 +- ttmath/ttmathtypes.h | 105 ++++-- ttmath/ttmathuint.h | 690 ++++++++++++++++++++++------------ ttmath/ttmathuint64.h | 855 ++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 1525 insertions(+), 371 deletions(-) create mode 100644 ttmath/ttmathuint64.h diff --git a/CHANGELOG b/CHANGELOG index 66ec304..4d2d516 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,17 @@ +Version 0.6.4 (2007.01.29): + * fixed the problem with a sign in the mathematical parser /-(1) was 1/ + * added UInt::AddInt and UInt::SubInt + * changed UInt::AddOne and UInt::SubOne (much faster now) + * added UInt::SetBitInWord + * changed UInt::SetBit (much faster now) + * UInt::AddTwoUints renamed to UInt::AddTwoInts + * UInt::FindLeadingBit32 renamed to UInt::FindLeadingBitInWord + * added UInt::SetBitInWord + * UInt::Mul64 renamed to UInt::MulTwoWords + * UInt::Div64 renamed to UInt::DivTwoWords + * and more small changes in UInt type + * start adding support for Amd64 (not finished yet) (added ttmathuint64.h) + Version 0.6.3 (2007.01.22): * position of arguments (x and base) in logarithm functions are swapped * it's possible to use any multiplication algorithms in the same time diff --git a/ttmath/ttmath.h b/ttmath/ttmath.h index 7f7f296..c39fc73 100644 --- a/ttmath/ttmath.h +++ b/ttmath/ttmath.h @@ -378,11 +378,11 @@ namespace ttmath d_denominator = one; } - int c = 0; + uint c = 0; bool addition = false; old_result = result; - for(int i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) + for(uint i=1 ; i<=TTMATH_ARITHMETIC_MAX_LOOP ; ++i) { // we're starting from a second part of the formula c += numerator. Mul( d_numerator ); diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index 470e5b1..b78da54 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -52,7 +52,7 @@ namespace ttmath /*! \brief it implements the big value */ -template +template class Big { @@ -204,7 +204,7 @@ public: // (first is the highest word) mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(uint)); - exponent = -int(man)*int(TTMATH_BITS_PER_UINT) + 2; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; info = 0; } @@ -215,7 +215,7 @@ public: void Set05Pi() { SetPi(); - exponent = -int(man)*int(TTMATH_BITS_PER_UINT) + 1; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 1; } @@ -225,7 +225,7 @@ public: void Set2Pi() { SetPi(); - exponent = -int(man)*int(TTMATH_BITS_PER_UINT) + 3; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 3; } @@ -249,7 +249,7 @@ public: }; mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(uint)); - exponent = -int(man)*int(TTMATH_BITS_PER_UINT) + 2; + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT) + 2; info = 0; } @@ -274,7 +274,7 @@ public: }; mantissa.SetFromTable(temp_table, sizeof(temp_table) / sizeof(uint)); - exponent = -int(man)*int(TTMATH_BITS_PER_UINT); + exponent = -sint(man)*sint(TTMATH_BITS_PER_UINT); info = 0; } @@ -395,7 +395,7 @@ public: { Int exp_offset( exponent ); Int mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT ); - int c = 0; + uint c = 0; exp_offset.Sub( ss2.exponent ); exp_offset.Abs(); @@ -475,7 +475,7 @@ public: TTMATH_REFERENCE_ASSERT( ss2 ) UInt man_result; - int i,c; + uint i,c; // man_result = mantissa * ss2.mantissa mantissa.MulBig(ss2.mantissa, man_result); @@ -635,15 +635,16 @@ public: */ bool Mod2() const { - if( exponent>int(0) || exponent<=-int(man*TTMATH_BITS_PER_UINT) ) + if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) ) return false; - int exp_int = exponent.ToInt(); + sint 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 / TTMATH_BITS_PER_UINT ]; - value >>= (exp_int % TTMATH_BITS_PER_UINT); + // !!! here we'll use a new method (method for testing a bit) + uint value = mantissa.table[ exp_int / TTMATH_BITS_PER_UINT ]; + value >>= (uint(exp_int) % TTMATH_BITS_PER_UINT); return bool(value & 1); } @@ -727,7 +728,7 @@ public: 2 - incorrect argument ('this' or 'pow') */ /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - there should be 'int Pow(const Big & pow)' + there should be 'sint 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 @@ -740,9 +741,9 @@ public: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ #ifdef __GNUC__ - int Pow(const Big & pow) + uint Pow(const Big & pow) #else - int Pow(const Big pow) + uint Pow(const Big pow) #endif { TTMATH_REFERENCE_ASSERT( pow ) @@ -869,7 +870,7 @@ public: // m will be the value of the mantissa in range (-1,1) Big m(x); - m.exponent = -int(man*TTMATH_BITS_PER_UINT); + m.exponent = -sint(man*TTMATH_BITS_PER_UINT); // 'e_' will be the value of '2^exponent' // e_.mantissa.table[man-1] = TTMATH_UINT_HIGHEST_BIT; and @@ -1031,7 +1032,7 @@ public: // m will be the value of the mantissa in range <1,2) Big m(x); - m.exponent = -int(man*TTMATH_BITS_PER_UINT - 1); + m.exponent = -sint(man*TTMATH_BITS_PER_UINT - 1); LnSurrounding1(m); Big exponent_temp; @@ -1112,22 +1113,22 @@ public: /*! - this method sets 'result' as the one word of type int + this method sets 'result' as the one word of type sint if the value is too big this method returns a carry (1) */ - uint ToInt(int & result) const + uint ToInt(sint & result) const { result = 0; if( IsZero() ) return 0; - int maxbit = -int(man*TTMATH_BITS_PER_UINT); + sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); - if( exponent > maxbit + int(TTMATH_BITS_PER_UINT) ) - // if exponent > (maxbit + int(TTMATH_BITS_PER_UINT)) the value can't be passed - // into the 'int' type (it's too big) + if( exponent > maxbit + sint(TTMATH_BITS_PER_UINT) ) + // if exponent > (maxbit + sint(TTMATH_BITS_PER_UINT)) the value can't be passed + // into the 'sint' type (it's too big) return 1; if( exponent <= maxbit ) @@ -1136,7 +1137,7 @@ public: UInt mantissa_temp(mantissa); // exponent is from a range of (-maxbit,0> - int how_many_bits = exponent.ToInt(); + sint how_many_bits = exponent.ToInt(); // how_many_bits is negative, we'll make it positive how_many_bits = -how_many_bits; @@ -1154,7 +1155,7 @@ public: return 1; if( IsSign() ) - result = -int(result); + result = -sint(result); return 0; } @@ -1173,10 +1174,10 @@ public: if( IsZero() ) return 0; - int maxbit = -int(man*TTMATH_BITS_PER_UINT); + sint maxbit = -sint(man*TTMATH_BITS_PER_UINT); - if( exponent > maxbit + int(int_size*TTMATH_BITS_PER_UINT) ) - // if exponent > (maxbit + int(int_size*TTMATH_BITS_PER_UINT)) the value can't be passed + if( exponent > maxbit + sint(int_size*TTMATH_BITS_PER_UINT) ) + // if exponent > (maxbit + sint(int_size*TTMATH_BITS_PER_UINT)) the value can't be passed // into the 'Int' type (it's too big) return 1; @@ -1185,7 +1186,7 @@ public: return 0; UInt mantissa_temp(mantissa); - int how_many_bits = exponent.ToInt(); + sint how_many_bits = exponent.ToInt(); if( how_many_bits < 0 ) { @@ -1228,9 +1229,9 @@ public: /*! - a method for converting 'int' to this class + a method for converting 'sint' to this class */ - void FromInt(int value) + void FromInt(sint value) { bool is_sign = false; @@ -1247,15 +1248,15 @@ public: if( is_sign ) SetSign(); - // there shouldn't be a carry because 'value' has the type 'int' + // there shouldn't be a carry because 'value' has the type 'sint' Standardizing(); } /*! - an operator= for converting 'int' to this class + an operator= for converting 'sint' to this class */ - Big & operator=(int value) + Big & operator=(sint value) { FromInt(value); @@ -1264,13 +1265,29 @@ public: /*! - a constructor for converting 'int' to this class + a constructor for converting 'sint' and 'uint' to this class */ - Big(int value) + Big(sint value) { FromInt(value); } + Big(uint value) + { + FromInt( sint(value) ); + } + +#if defined _M_X64 || defined __x86_64__ + /*! + a constructor for converting 'int' to this class + (on 64bit platforms 'sint' has 64 bits and 'int' has 32 bits + */ + Big(int value) + { + FromInt( sint(value) ); + } +#endif + /*! a method for converting from 'Int' to this class @@ -1287,8 +1304,8 @@ public: } uint minimum_size = (int_size < man)? int_size : man; - int compensation = (int)value.CompensationToLeft(); - exponent = (int(int_size)-int(man)) * int(TTMATH_BITS_PER_UINT) - compensation; + sint compensation = (sint)value.CompensationToLeft(); + exponent = (sint(int_size)-sint(man)) * sint(TTMATH_BITS_PER_UINT) - compensation; // copying the highest words uint i; @@ -1404,8 +1421,8 @@ public: uint ToString( std::string & result, uint base = 10, bool always_scientific = false, - int when_scientific = 15, - int max_digit_after_comma = -2 ) const + sint when_scientific = 15, + sint max_digit_after_comma = -2 ) const { static char error_overflow_msg[] = "overflow"; result.erase(); @@ -1647,7 +1664,18 @@ private: // (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 }; + + /* + * + * this is only temporarily (for testing) + * + */ + +// static Big log_history[15] = { 0l,0l,0l,0l,0l,0l,0l,0l,0l,0l, +// 0l,0l,0l,0l,0l }; + 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() ) @@ -1689,14 +1717,14 @@ private: if( !exponent.IsSign() ) return 1; - if( exponent <= -int(man*TTMATH_BITS_PER_UINT) ) - // if 'exponent' is <= than '-int(man*TTMATH_BITS_PER_UINT)' + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) + // if 'exponent' is <= than '-sint(man*TTMATH_BITS_PER_UINT)' // it means that we must cut the whole mantissa // (there'll not be any of the valid bits) return 1; // e will be from (-man*TTMATH_BITS_PER_UINT, 0> - int e = -( exponent.ToInt() ); + sint e = -( exponent.ToInt() ); mantissa.Rcr(e,0); return 0; @@ -1717,11 +1745,11 @@ private: uint ToString_CreateNewMantissaAndExponent_Base2( std::string & new_man, Int & new_exp ) const { - for( int i=man-1 ; i>=0 ; --i ) + for( sint i=man-1 ; i>=0 ; --i ) { uint value = mantissa.table[i]; - for( unsigned int bit=0 ; bit=0 && was_carry ; --i ) @@ -1809,12 +1837,12 @@ private: 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, + uint ToString_SetCommaAndExponent( std::string & new_man, uint base, Int & new_exp, bool always_scientific, - int when_scientific, - int max_digit_after_comma ) const + sint when_scientific, + sint max_digit_after_comma ) const { - int carry = 0; + uint carry = 0; if( new_man.empty() ) return carry; @@ -1826,14 +1854,14 @@ private: // 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; + sint offset = sint( new_man.length() ) - 1; carry += scientific_exp.Add( offset ); // there shouldn't have been a carry because we're using // a greater type -- 'Int' instead of 'Int' if( !always_scientific ) { - if( scientific_exp > when_scientific || scientific_exp < -int(when_scientific) ) + if( scientific_exp > when_scientific || scientific_exp < -sint(when_scientific) ) always_scientific = true; } @@ -1852,9 +1880,10 @@ private: 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 + Int & new_exp, sint max_digit_after_comma) const { - if( new_exp >= 0 ) + //if( new_exp >= 0 ) + if( !new_exp.IsSign() ) return ToString_SetCommaAndExponent_Normal_AddingZero(new_man, new_exp); else return ToString_SetCommaAndExponent_Normal_SetCommaInside(new_man, base, new_exp, max_digit_after_comma); @@ -1884,18 +1913,18 @@ private: 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 + uint base, Int & new_exp, sint 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 + sint new_man_len = sint(new_man.length()); // 'new_man_len' with a sign + sint e = -( new_exp.ToInt() ); // 'e' will be positive if( new_exp > -new_man_len ) { // we're setting the comma within the mantissa - int index = new_man_len - e; + sint index = new_man_len - e; new_man.insert( new_man.begin() + index, TTMATH_COMMA_CHARACTER_1); } else @@ -1919,7 +1948,7 @@ private: void ToString_SetCommaAndExponent_Scientific( std::string & new_man, uint base, Int & scientific_exp, - int max_digit_after_comma ) const + sint max_digit_after_comma ) const { if( new_man.empty() ) return; @@ -1955,7 +1984,7 @@ private: 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 + sint max_digit_after_comma) const { switch( max_digit_after_comma ) { @@ -2005,7 +2034,7 @@ private: an auxiliary method for converting into the string */ void ToString_CorrectDigitsAfterComma_Round(std::string & new_man, uint base, - int max_digit_after_comma) const + sint max_digit_after_comma) const { // first we're looking for the comma operator std::string::size_type index = new_man.find(TTMATH_COMMA_CHARACTER_1, 0); @@ -2061,7 +2090,7 @@ public: 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) + uint FromString(const char * source, uint base = 10, const char ** after_source = 0) { bool is_sign; @@ -2077,7 +2106,7 @@ public: FromString_TestNewBase( source, base ); FromString_TestSign( source, is_sign ); - int c = FromString_ReadPartBeforeComma( source, base ); + uint c = FromString_ReadPartBeforeComma( source, base ); if( FromString_TestCommaOperator(source) ) c += FromString_ReadPartAfterComma( source, base ); @@ -2170,7 +2199,7 @@ private: */ uint FromString_ReadPartBeforeComma( const char * & source, uint base ) { - int character; + sint character; Big temp; Big base_( base ); @@ -2197,7 +2226,8 @@ private: */ uint FromString_ReadPartAfterComma( const char * & source, uint base ) { - int character, c = 0, index = 1; + sint character; + uint c = 0, index = 1; Big part, power, old_value, base_( base ); // we don't remove any white characters here @@ -2267,7 +2297,7 @@ private: */ uint FromString_ReadPartScientific( const char * & source ) { - int c = 0; + uint c = 0; Big new_exponent, temp; bool was_sign = false; @@ -2291,7 +2321,7 @@ private: */ uint FromString_ReadPartScientific_ReadExponent( const char * & source, Big & new_exponent ) { - int character; + sint character; Big base, temp; UInt::SkipWhiteCharacters(source); @@ -2320,7 +2350,7 @@ public: /*! a method for converting a string into its value */ - int FromString(const std::string & string, uint base = 10) + uint FromString(const std::string & string, uint base = 10) { return FromString( string.c_str(), base ); } @@ -2660,7 +2690,7 @@ public: // exponent >=0 -- the value don't have any fractions return; - if( exponent <= -int(man*TTMATH_BITS_PER_UINT) ) + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) { // the value is from (-1,1), we return zero SetZero(); @@ -2668,7 +2698,7 @@ public: } // exponent is in range (-man*TTMATH_BITS_PER_UINT, 0) - int e = exponent.ToInt(); + sint e = exponent.ToInt(); mantissa.ClearFirstBits( -e ); @@ -2698,7 +2728,7 @@ public: return; } - if( exponent <= -int(man*TTMATH_BITS_PER_UINT) ) + if( exponent <= -sint(man*TTMATH_BITS_PER_UINT) ) { // the value is from (-1,1) // we don't make anything with the value @@ -2706,9 +2736,9 @@ public: } // e will be from (-man*TTMATH_BITS_PER_UINT, 0) - int e = exponent.ToInt(); + sint e = exponent.ToInt(); - int how_many_bits_leave = man*TTMATH_BITS_PER_UINT + e; // there'll be a subtraction -- e is negative + sint how_many_bits_leave = sint(man*TTMATH_BITS_PER_UINT) + e; // there'll be a subtraction -- e is negative mantissa.Rcl( how_many_bits_leave, 0); // there'll not be a carry because the exponent is too small diff --git a/ttmath/ttmathint.h b/ttmath/ttmathint.h index d0586b0..07363fc 100644 --- a/ttmath/ttmathint.h +++ b/ttmath/ttmathint.h @@ -465,9 +465,9 @@ public: /*! - this method convert an int type to this class + this method convert an sint type to this class */ - Int & operator=(int i) + Int & operator=(sint i) { if(i<0) SetSignOne(); @@ -483,7 +483,7 @@ public: /*! constructor for converting an uint to this class */ - Int(int i) + Int(sint i) { operator=(i); } @@ -540,11 +540,11 @@ public: 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) + will hold in an sint type or not (the rest value from table must be zero or -1) */ - int ToInt() const + sint ToInt() const { - return int( UInt::table[0] ); + return sint( UInt::table[0] ); } @@ -676,10 +676,10 @@ public: bool operator<(const Int & l) const { - int i=value_size-1; + sint i=value_size-1; - int a1 = int(UInt::table[i]); - int a2 = int(l.table[i]); + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 < a2; @@ -703,11 +703,11 @@ public: bool operator>(const Int & l) const { - int i=value_size-1; + sint i=value_size-1; - int a1 = int(UInt::table[i]); - int a2 = int(l.table[i]); + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 > a2; @@ -730,11 +730,11 @@ public: bool operator<=(const Int & l) const { - int i=value_size-1; + sint i=value_size-1; - int a1 = int(UInt::table[i]); - int a2 = int(l.table[i]); + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 < a2; @@ -757,11 +757,11 @@ public: bool operator>=(const Int & l) const { - int i=value_size-1; + sint i=value_size-1; - int a1 = int(UInt::table[i]); - int a2 = int(l.table[i]); + sint a1 = sint(UInt::table[i]); + sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 > a2; diff --git a/ttmath/ttmathparser.h b/ttmath/ttmathparser.h index ebf2cce..c7f93af 100644 --- a/ttmath/ttmathparser.h +++ b/ttmath/ttmathparser.h @@ -1373,9 +1373,14 @@ int index; // 'index' will be greater than zero // 'amount_of_parameters' can be zero + if( amount_of_parameters==0 && !stack[index-1].function ) Error( err_unexpected_final_bracket ); + + bool was_sign = stack[index-1].sign; + + if( stack[index-1].function ) { // the result of a function will be on 'stack[index-1]' @@ -1402,11 +1407,10 @@ int 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].sign = false; + + if( was_sign ) stack[index-1].value.ChangeSign(); - stack[index-1].sign = false; - } stack[index-1].type = Item::numerical_value; @@ -1676,7 +1680,7 @@ ErrorCode Parse(const char * str) stack.resize( default_stack_size ); -// char buf_temp[] = "1111"; +// char buf_temp[] = "-(1)"; // pstring = buf_temp; try diff --git a/ttmath/ttmathtypes.h b/ttmath/ttmathtypes.h index 24b3a9f..327f5e7 100644 --- a/ttmath/ttmathtypes.h +++ b/ttmath/ttmathtypes.h @@ -61,7 +61,7 @@ */ #define TTMATH_MAJOR_VER 0 #define TTMATH_MINOR_VER 6 -#define TTMATH_REVISION_VER 3 +#define TTMATH_REVISION_VER 4 /*! @@ -86,34 +86,71 @@ #endif +/* +VC doesn't have these macros +#if !defined(__i386__) && !defined(__amd64__) +#error "This code is designed only for x86/amd64 platforms (amd64 is very experimental now)" +#endif +*/ + + namespace ttmath { /*! - 32 bit integer value without a sign - (on 64bit platforms will be 32bit as well) + on 32bit platforms one word will be equal 32bits + on 64bit platforms one word will be 64bits */ + +#if !defined _M_X64 && !defined __x86_64__ + typedef unsigned int uint; + typedef signed int sint; + + /*! + how many bits there are in the uint type + */ + #define TTMATH_BITS_PER_UINT 32u + + /*! + the mask for the highest bit in the unsigned 32bit word (2^31) + */ + #define TTMATH_UINT_HIGHEST_BIT 2147483648u + + + /*! + the max value of the unsigned 32bit word (2^32 - 1) + (all bits equal one) + */ + #define TTMATH_UINT_MAX_VALUE 4294967295u + + +#else + + typedef unsigned long uint; + typedef signed long sint; + + /*! + how many bits there are in the uint type + */ + #define TTMATH_BITS_PER_UINT 64ul + + /*! + the mask for the highest bit in the unsigned 64bit word (2^63) + */ + #define TTMATH_UINT_HIGHEST_BIT 9223372036854775808ul + + + /*! + the max value of the unsigned 64bit word (2^64 - 1) + (all bits equal one) + */ + #define TTMATH_UINT_MAX_VALUE 18446744073709551615ul + + +#endif } -/*! - how many bits there are in the uint type -*/ -#define TTMATH_BITS_PER_UINT 32u - - -/*! - the mask for the highest bit in the unsigned 32bit word (2^31) -*/ -#define TTMATH_UINT_HIGHEST_BIT 2147483648u - - -/*! - the max value of the unsigned 32bit word (2^32 - 1) - (all bits equal one) -*/ -#define TTMATH_UINT_MAX_VALUE 4294967295u - /*! characters which represent the comma operator @@ -304,19 +341,23 @@ namespace ttmath #ifdef TTMATH_DEBUG - #ifdef __GNUC__ - #define TTMATH_REFERENCE_ASSERT(expression) \ - if( &(expression) == this ) throw ReferenceError(__FILE__, __LINE__); - #define TTMATH_ASSERT(expression) \ - if( !(expression) ) throw RuntimeError(__FILE__, __LINE__); - #else - #define TTMATH_REFERENCE_ASSERT(expression) \ - if( &(expression) == this ) throw ReferenceError(); + #define TTMATH_REFERENCE_ASSERT(expression) \ + if( &(expression) == this ) throw ttmath::ReferenceError(__FILE__, __LINE__); - #define TTMATH_ASSERT(expression) \ - if( !(expression) ) throw RuntimeError(); - #endif + #define TTMATH_ASSERT(expression) \ + if( !(expression) ) throw ttmath::RuntimeError(__FILE__, __LINE__); + + /* + if your compiler doesn't support macros __FILE__ and __LINE__ + you can above asserts change to: + + #define TTMATH_REFERENCE_ASSERT(expression) \ + if( &(expression) == this ) throw ReferenceError(); + + #define TTMATH_ASSERT(expression) \ + if( !(expression) ) throw RuntimeError(); + */ #else #define TTMATH_REFERENCE_ASSERT(expression) #define TTMATH_ASSERT(expression) diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h index aee561c..f234537 100644 --- a/ttmath/ttmathuint.h +++ b/ttmath/ttmathuint.h @@ -48,14 +48,13 @@ #include "ttmathtypes.h" -#define TTMATH_UINT_GUARD 1234567891 namespace ttmath { /*! - \brief it implements the big integer value without the sign + \brief it implements the big integer value without a sign value_size - how many bytes specify our value (value_size = 1 -> 4 bytes -> 32 bits) value_size = 1,2,3,4,5,6.... @@ -65,15 +64,12 @@ 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 @@ -126,15 +122,15 @@ public: /*! - this method copys value stored in an another table - (warning: first values in temp_table are the highest words -- it's differently - than our table) + this method copies the value stored in an another table + (warning: first values in temp_table are the highest words -- it's different + from our table) we copy as many words as it is possible if temp_table_len is bigger than value_size we'll try to round the lowest word from table depending on the last not used bit in temp_table - (this rounding isn't a perfect rounding -- look on a description below) + (this rounding isn't a perfect rounding -- look at the description below) and if temp_table_len is smaller than value_size we'll clear the rest words int table @@ -142,7 +138,7 @@ public: void SetFromTable(const uint * temp_table, uint temp_table_len) { uint temp_table_index = 0; - int i; // i with a sign + sint i; // 'i' with a sign for(i=value_size-1 ; i>=0 && temp_table_index=0 ; --i) table[i] = 0; } @@ -180,6 +176,8 @@ public: * */ +#if !defined _M_X64 && !defined __x86_64__ + /*! this method adding ss2 to the this and adding carry if it's defined @@ -190,15 +188,15 @@ public: */ uint Add(const UInt & ss2, uint c=0) { - register int b = value_size; + register uint 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 - */ + + // this part might be compiled with for example visual c + __asm { push eax @@ -244,9 +242,9 @@ public: #ifdef __GNUC__ - /* - this part should be compiled with gcc - */ + + // this part should be compiled with gcc + __asm__ __volatile__( "push %%ebx \n" @@ -283,20 +281,131 @@ public: : "=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 - + : "%eax", "cc", "memory" ); #endif + + return c; + } + + + /*! + this method adds one word (at a specific position) + and returns a carry (if it was) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + AddInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 + 2; + table[2] = 5; + + of course if there was a carry from table[3] it would be returned + */ + uint AddInt(uint value, uint index = 0) + { + register uint 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, [value] + + clc + p: + mov eax, [ebx] + adc eax, edx + mov [ebx], eax + + jnc end + mov edx, 0 + + inc ebx + inc ebx + inc ebx + inc ebx + + 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 %4, %%edx \n" + "clc \n" + "1: \n" + + "movl (%%ebx), %%eax \n" + "adcl %%edx, %%eax \n" + "movl %%eax, (%%ebx) \n" + + "jnc 2f \n" + + "movl $0, %%edx \n" + + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \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), "q" (value) + : "cc", "memory" ); + + #endif return c; @@ -304,10 +413,8 @@ public: - - /*! - this method addes only two unsigned words to the existing value + this method adds only two unsigned words to the existing value and these words begin on the 'index' position (it's used in the multiplication algorithm 2) @@ -336,9 +443,9 @@ public: (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) + uint AddTwoInts(uint index, uint x2, uint x1) { - register int b = value_size; + register uint b = value_size; register uint * p1 = table; register uint c; @@ -475,22 +582,16 @@ public: /*! - this method subtracting ss2 from the this and subtracting carry if it's defined + this method's subtracting ss2 from the 'this' and subtracting + carry if it has been defined (this = this - ss2 - c) c must be zero or one (might be a bigger value than 1) function returns carry (1) (if it was) */ - uint Sub(const UInt & ss2, uint c=0, int last_index = -1) + uint Sub(const UInt & ss2, uint c=0) { - register int b; - - if( last_index == -1 ) - b = value_size; - else - b = last_index + 1; - - + register uint b = value_size; register uint * p1 = table; register uint * p2 = const_cast(ss2.table); @@ -578,7 +679,7 @@ public: : "=S" (c) : "0" (c), "c" (b), "b" (p1), "d" (p2) - : "eax", "cc", "memory" ); + : "%eax", "cc", "memory" ); #endif @@ -587,16 +688,136 @@ public: } + /*! + this method subtracts one word (at a specific position) + and returns a carry (if it was) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + SubInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 - 2; + table[2] = 5; + + of course if there was a carry from table[3] it would be returned + */ + uint SubInt(uint value, uint index = 0) + { + register uint 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, [value] + + clc + p: + mov eax, [ebx] + sbb eax, edx + mov [ebx], eax + + jnc end + mov edx, 0 + + inc ebx + inc ebx + inc ebx + inc ebx + + 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 %4, %%edx \n" + "clc \n" + "1: \n" + + "movl (%%ebx), %%eax \n" + "sbbl %%edx, %%eax \n" + "movl %%eax, (%%ebx) \n" + + "jnc 2f \n" + + "movl $0, %%edx \n" + + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \n" + "inc %%ebx \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), "q" (value) + : "cc", "memory" ); + + #endif + + + return c; + } + +#endif + + /*! this method adds one to the existing value */ uint AddOne() { - UInt temp; - - temp.SetOne(); - - return Add(temp); + return AddInt(1); } @@ -605,14 +826,13 @@ public: */ uint SubOne() { - UInt temp; - - temp.SetOne(); - - return Sub(temp); + return SubInt(1); } +#if !defined _M_X64 && !defined __x86_64__ + + /*! this method moving once all bits into the left side return value <- this <- C @@ -622,7 +842,7 @@ public: */ uint Rcl(uint c=0) { - register int b = value_size; + register sint b = value_size; register uint * p1 = table; @@ -667,7 +887,7 @@ public: "push %%ecx \n" "movl $0,%%eax \n" - "sub %%edx,%%eax \n" + "subl %%edx,%%eax \n" "1: \n" "rcll $1,(%%ebx) \n" @@ -679,15 +899,15 @@ public: "loop 1b \n" - "mov $0, %%edx \n" - "adc %%edx,%%edx \n" + "movl $0, %%edx \n" + "adcl %%edx,%%edx \n" "pop %%ecx \n" "pop %%ebx \n" : "=d" (c) : "0" (c), "c" (b), "b" (p1) - : "eax", "cc", "memory" ); + : "%eax", "cc", "memory" ); #endif @@ -705,7 +925,7 @@ public: */ uint Rcr(uint c=0) { - register int b = value_size; + register sint b = value_size; register uint * p1 = table; @@ -716,16 +936,11 @@ public: push ebx push ecx - mov ecx,[b] - - add ecx,ecx - add ecx,ecx - mov ebx,[p1] - add ebx,ecx - mov ecx,[b] + lea ebx,[ebx+4*ecx] + mov eax,0 sub eax,[c] @@ -756,15 +971,10 @@ public: "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" + "leal (%%ebx,%%ecx,4),%%ebx \n" "movl $0, %%eax \n" - "subl %%edx, %% eax \n" + "subl %%edx, %%eax \n" "1: \n" "dec %%ebx \n" @@ -776,15 +986,15 @@ public: "loop 1b \n" - "mov $0, %%edx \n" - "adc %%edx,%%edx \n" + "movl $0, %%edx \n" + "adcl %%edx,%%edx \n" "pop %%ecx \n" "pop %%ebx \n" : "=d" (c) : "0" (c), "c" (b), "b" (p1) - : "eax", "cc", "memory" ); + : "%eax", "cc", "memory" ); #endif @@ -792,6 +1002,7 @@ public: return c; } +#endif /*! this method moving all bits into the left side 'bits' times @@ -805,14 +1016,14 @@ public: */ uint Rcl(uint bits, uint c) { - int first; - int second; - int last_c = 0; + sint first; + sint second; + uint last_c = 0; if( bits > value_size*TTMATH_BITS_PER_UINT ) bits = value_size*TTMATH_BITS_PER_UINT; - int all_words = int(bits) / int(TTMATH_BITS_PER_UINT); + sint all_words = sint(bits) / sint(TTMATH_BITS_PER_UINT); if( all_words > 0 ) { @@ -829,7 +1040,7 @@ public: table[first] = mask; } - int rest_bits = int(bits) % int(TTMATH_BITS_PER_UINT); + sint rest_bits = sint(bits) % sint(TTMATH_BITS_PER_UINT); for( ; rest_bits > 0 ; --rest_bits ) last_c = Rcl(c); @@ -849,19 +1060,19 @@ public: */ uint Rcr(uint bits, uint c) { - int first; - int second; - int last_c = 0; + sint first; + sint second; + sint last_c = 0; if( bits > value_size*TTMATH_BITS_PER_UINT ) bits = value_size*TTMATH_BITS_PER_UINT; - int all_words = int(bits) / int(TTMATH_BITS_PER_UINT); + sint all_words = sint(bits) / sint(TTMATH_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); @@ -893,7 +1104,7 @@ public: uint moving = 0; // a - index a last word which is different from zero - int a; + sint a; for(a=value_size-1 ; a>=0 && table[a]==0 ; --a); if( a < 0 ) @@ -907,8 +1118,8 @@ public: moving += ( value_size-1 - a ) * TTMATH_BITS_PER_UINT; // moving all words - int i; - for(i=value_size-1 ; i>=0 && a>=0; --i, --a) + sint i; + for(i=value_size-1 ; a>=0 ; --i, --a) table[i] = table[a]; // setting the rest word to zero @@ -926,14 +1137,15 @@ public: return moving; } +#if !defined _M_X64 && !defined __x86_64__ /* 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) + static sint FindLeadingBitInWord(uint x) { - register int result; + register sint result; #ifndef __GNUC__ __asm @@ -956,7 +1168,7 @@ public: "bsrl %1, %0 \n" "jnz 1f \n" - "mov $-1, %0 \n" + "movl $-1, %0 \n" "1: \n" : "=q" (result) @@ -969,6 +1181,7 @@ public: return result; } +#endif /*! this method looks for the highest set bit @@ -996,12 +1209,59 @@ public: } // table[table_id] != 0 - index = FindLeadingBit32( table[table_id] ); + index = FindLeadingBitInWord( table[table_id] ); return true; } +#if !defined _M_X64 && !defined __x86_64__ + + /*! + this method sets a special bit in the 'value' + and returns the result + + bit is from <0,31> + + e.g. + SetBitInWord(0,0) = 1 + SetBitInWord(0,2) = 4 + SetBitInWord(10, 8) = 266 + */ + static uint SetBitInWord(uint value, uint bit) + { + #ifndef __GNUC__ + __asm + { + push ebx + push eax + mov eax, value + mov ebx, bit + bts eax, ebx + mov value, eax + pop eax + pop ebx + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "btsl %%ebx,%%eax \n" + + : "=a" (value) + : "0" (value), "b" (bit) + : "cc" ); + + #endif + + return value; + } + +#endif + + /*! it sets the bit bit_index @@ -1014,12 +1274,8 @@ public: return; bit_index %= TTMATH_BITS_PER_UINT; - uint result = 1; - if( bit_index > 0 ) - result <<= bit_index; - - table[index] |= result; + table[index] = SetBitInWord(table[index], bit_index); } @@ -1032,16 +1288,19 @@ public: public: +#if !defined _M_X64 && !defined __x86_64__ + + /*! multiplication: result2:result1 = a * b result2 - higher word result1 - lower word of the result - this methos never returns a carry + this method never returns a carry it is an auxiliary method for version two of the multiplication algorithm */ - static void Mul64(uint a, uint b, uint * result2, uint * result1) + static void MulTwoWords(uint a, uint b, uint * result2, uint * result1) { /* we must use these temporary variables in order to inform the compilator @@ -1080,7 +1339,7 @@ public: "mull %%edx \n" : "=a" (result1_), "=d" (result2_) - : "a" (a), "d" (b) + : "0" (a), "1" (b) : "cc" ); #endif @@ -1090,11 +1349,12 @@ public: *result2 = result2_; } +#endif /*! multiplication: this = this * ss2 - it returns carry if it has been + it returns a carry if it has been */ uint MulInt(uint ss2) { @@ -1105,11 +1365,12 @@ public: for(uint x1=0 ; x1 & ss2, uint algorithm = 2) { @@ -1142,6 +1400,7 @@ public: case 1: return Mul1(ss2); + case 2: default: return Mul2(ss2); } @@ -1149,7 +1408,10 @@ public: /*! + the multiplication 'result' = 'this' * ss2 + since the 'result' is twice bigger than 'this' and 'ss2' + this method never returns a carry */ void MulBig(const UInt & ss2, UInt & result, @@ -1160,6 +1422,7 @@ public: case 1: return Mul1Big(ss2, result); + case 2: default: return Mul2Big(ss2, result); } @@ -1175,9 +1438,6 @@ public: 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 Mul1(const UInt & ss2) { @@ -1288,9 +1548,9 @@ public: { for(uint x2=x2start ; x2 dividend(*this); SetZero(); - int i; // i must be with a sign + sint i; // i must be with a sign uint r = 0; // we're looking for the last word in ss1 for(i=value_size-1 ; i>0 && dividend.table[i]==0 ; --i); for( ; i>=0 ; --i) - Div64(r, dividend.table[i], divisor, &table[i], &r); + DivTwoWords(r, dividend.table[i], divisor, &table[i], &r); if( remainder ) *remainder = r; @@ -1414,30 +1678,10 @@ public: 1 - division by zero 'this' will be the quotient 'remainder' - remainder - -// !!!!!!!!!!! -it needs a new description - - 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) + uint algorithm = 3) { switch( algorithm ) { @@ -1505,7 +1749,6 @@ private: /*! - return values: 0 - ok 'm' - is the index (from 0) of last non-zero word in table ('this') @@ -1580,8 +1823,8 @@ private: { TTMATH_REFERENCE_ASSERT( divisor ) - int loop; - int c; + sint loop; + sint c; rest.SetZero(); loop = value_size * TTMATH_BITS_PER_UINT; @@ -1707,7 +1950,7 @@ private: --bits_diff; } - Sub(divisor_copy, 0, table_id); + Sub(divisor_copy, 0); return 2; } @@ -1832,7 +2075,7 @@ public: /*! the third division algorithm - this algorithm is described in the following book + this algorithm is described in the following book: "The art of computer programming 2" (4.3.1 page 272) Donald E. Knuth */ @@ -2029,7 +2272,7 @@ private: { UInt<2> temp1, temp2; - UInt<2>::Mul64(u_temp.table[0], v0, temp1.table+1, temp1.table); + UInt<2>::MulTwoWords(u_temp.table[0], v0, temp1.table+1, temp1.table); temp2.table[1] = rp; temp2.table[0] = u0; @@ -2043,15 +2286,10 @@ private: { 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 function returns -1 c=A, base=16 -> function returns 10 */ - static int CharToDigit(uint c, uint base) + static sint CharToDigit(uint c, uint base) { if( c>='0' && c<='9' ) c=c-'0'; @@ -2217,7 +2455,7 @@ public: return -1; - return int(c); + return sint(c); } @@ -2242,7 +2480,7 @@ public: /*! - this method convert an UInt type to this class + this method converts an UInt type to this class this operation has mainly sense if the value from p is equal or smaller than that one which is returned from UInt::SetMaxValue() @@ -2291,7 +2529,7 @@ public: } /*! - the default assignment operator + the assignment operator */ UInt & operator=(const UInt & p) { @@ -2313,37 +2551,28 @@ public: /*! - constructor for converting an uint to this class + a 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) + a 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) + a 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() ); } @@ -2355,40 +2584,31 @@ public: */ UInt() { - guard1 = TTMATH_UINT_GUARD; - guard2 = TTMATH_UINT_GUARD; } /*! - the copying constructor + the copy constructor */ UInt(const UInt & u) { - guard1 = TTMATH_UINT_GUARD; - guard2 = TTMATH_UINT_GUARD; - FromUInt(u); } /*! - template for producting constructors for copying from another types + a 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 + the destructor */ virtual ~UInt() { @@ -2400,7 +2620,7 @@ public: 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) + will hold in an uint type or not (the rest value from the table must be zero) */ uint ToUInt() const { @@ -2445,6 +2665,7 @@ public: ++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 @@ -2460,7 +2681,7 @@ public: { UInt base( b ); UInt temp; - int z; + sint z; SetZero(); temp.SetZero(); @@ -2526,11 +2747,11 @@ public: */ - bool CmpSmaller(const UInt & l, int index = -1) const + bool CmpSmaller(const UInt & l, sint index = -1) const { - int i; + sint i; - if( index==-1 || index>=int(value_size) ) + if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; @@ -2548,11 +2769,11 @@ public: - bool CmpBigger(const UInt & l, int index = -1) const + bool CmpBigger(const UInt & l, sint index = -1) const { - int i; + sint i; - if( index==-1 || index>=int(value_size) ) + if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; @@ -2569,11 +2790,11 @@ public: } - bool CmpEqual(const UInt & l, int index = -1) const + bool CmpEqual(const UInt & l, sint index = -1) const { - int i; + sint i; - if( index==-1 || index>=int(value_size) ) + if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; @@ -2586,11 +2807,11 @@ public: return true; } - bool CmpSmallerEqual(const UInt & l, int index=-1) const + bool CmpSmallerEqual(const UInt & l, sint index=-1) const { - int i; + sint i; - if( index==-1 || index>=int(value_size) ) + if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; @@ -2606,11 +2827,11 @@ public: return true; } - bool CmpBiggerEqual(const UInt & l, int index=-1) const + bool CmpBiggerEqual(const UInt & l, sint index=-1) const { - int i; + sint i; - if( index==-1 || index>=int(value_size) ) + if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; @@ -2631,38 +2852,20 @@ public: 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; + return CmpSmaller(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 false; + return CmpBigger(l); } bool operator==(const UInt & l) const { - for(uint i=0 ; i & 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; + return CmpSmallerEqual(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; + return CmpBiggerEqual(l); } @@ -2843,6 +3032,8 @@ public: /*! * * input/output operators for standard streams + * + * (they are very simple, in the future they should be changed) * */ @@ -2885,12 +3076,31 @@ public: } +#if defined _M_X64 || defined __x86_64__ + + // these methods for 64bit processors are defined in 'ttmathuint64.h' + + uint Add(const UInt & ss2, uint c=0); + uint AddInt(uint value, uint index = 0); + uint AddTwoInts(uint index, uint x2, uint x1); + uint Sub(const UInt & ss2, uint c=0); + uint SubInt(uint value, uint index = 0); + uint Rcl(uint c=0); + uint Rcr(uint c=0); + static sint FindLeadingBitInWord(uint x); + static uint SetBitInWord(uint value, uint bit); + static void MulTwoWords(uint a, uint b, uint * result2, uint * result1); + static void DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest); + +#endif + }; } //namespace +#include "ttmathuint64.h" #endif diff --git a/ttmath/ttmathuint64.h b/ttmath/ttmathuint64.h new file mode 100644 index 0000000..d66e7f9 --- /dev/null +++ b/ttmath/ttmathuint64.h @@ -0,0 +1,855 @@ +/* + * This file is a 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. + */ + + + +/*! + \file ttmathuint.h + \brief template class UInt for 64bit processors +*/ + + +namespace ttmath +{ + + /*! + * + * basic mathematic functions + * + */ + +#if defined _M_X64 || defined __x86_64__ + + /*! + this method adding ss2 to the this and adding carry if it's defined + (this = this + ss2 + c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Add(const UInt & ss2, uint c) + { + register uint b = value_size; + register uint * p1 = table; + register uint * p2 = const_cast(ss2.table); + + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + /* + this part might be compiled with for example visual c + */ + __asm + { + } + #endif + + + #ifdef __GNUC__ + /* + this part should be compiled with gcc + */ + __asm__ __volatile__( + + "push %%rbx \n" + "push %%rcx \n" + "push %%rdx \n" + + "movq $0, %%rax \n" + "subq %%rsi, %%rax \n" + + "1: \n" + "movq (%%rbx),%%rax \n" + "adcq (%%rdx),%%rax \n" + "movq %%rax,(%%rbx) \n" + + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + + "loop 1b \n" + + "movq $0, %%rax \n" + "adcq %%rax,%%rax \n" + "movq %%rax, %%rsi \n" + + "pop %%rdx \n" + "pop %%rcx \n" + "pop %%rbx \n" + + : "=S" (c) + : "0" (c), "c" (b), "b" (p1), "d" (p2) + : "%rax", "cc", "memory" ); + + #endif + + + + return c; + } + + + + /*! + this method adds one word (at a specific position) + and returns a carry (if it was) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + AddInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 + 2; + table[2] = 5; + + of course if there was a carry from table[3] it would be returned + */ + template + uint UInt::AddInt(uint value, uint index) + { + register uint b = value_size; + register uint * p1 = table; + register uint c; + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + "push %%rbx \n" + "push %%rcx \n" + "push %%rdx \n" + + "subq %%rdx, %%rcx \n" + + "leaq (%%rbx,%%rdx,8), %%rbx \n" + + "movq %4, %%rdx \n" + "clc \n" + "1: \n" + + "movq (%%rbx), %%rax \n" + "adcq %%rdx, %%rax \n" + "movq %%rax, (%%rbx) \n" + + "jnc 2f \n" + + "movq $0, %%rdx \n" + + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "loop 1b \n" + + "2: \n" + + "movq $0, %%rax \n" + "adcq %%rax,%%rax \n" + + "pop %%rdx \n" + "pop %%rcx \n" + "pop %%rbx \n" + + : "=a" (c) + : "c" (b), "d" (index), "b" (p1), "q" (value) + : "cc", "memory" ); + + #endif + + + return c; + } + + + + /*! + this method adds only two unsigned words to the existing value + and these words begin on the 'index' position + (it's used in the multiplication algorithm 2) + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + for example if we've got value_size equal 4 and: + table[0] = 3 + table[1] = 4 + table[2] = 5 + table[3] = 6 + then let + x1 = 10 + x2 = 20 + and + index = 1 + + the result of this method will be: + table[0] = 3 + table[1] = 4 + x1 = 14 + table[2] = 5 + x2 = 25 + table[3] = 6 + + and no carry at the end of table[3] + + (of course if there was a carry in table[2](5+20) then + this carry would be passed to the table[3] etc.) + */ + template + uint UInt::AddTwoInts(uint index, uint x2, uint x1) + { + register uint b = value_size; + register uint * p1 = table; + register uint c; + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%rbx \n" + "push %%rcx \n" + "push %%rdx \n" + + "subq %%rdx, %%rcx \n" + + "leaq (%%rbx,%%rdx,8), %%rbx \n" + + "movq $0, %%rdx \n" + + "movq (%%rbx), %%rax \n" + "addq %4, %%rax \n" + "movq %%rax, (%%rbx) \n" + + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "movq (%%rbx), %%rax \n" + "adcq %5, %%rax \n" + "movq %%rax, (%%rbx) \n" + "jnc 2f \n" + + "dec %%rcx \n" + "dec %%rcx \n" + "jz 2f \n" + + "1: \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "movq (%%rbx), %%rax \n" + "adcq %%rdx, %%rax \n" + "movq %%rax, (%%rbx) \n" + + "jnc 2f \n" + + "loop 1b \n" + + "2: \n" + + "movq $0, %%rax \n" + "adcq %%rax,%%rax \n" + + "pop %%rdx \n" + "pop %%rcx \n" + "pop %%rbx \n" + + : "=a" (c) + : "c" (b), "d" (index), "b" (p1), "q" (x1), "q" (x2) + : "cc", "memory" ); + + #endif + + + return c; + } + + + + + + /*! + this method's subtracting ss2 from the 'this' and subtracting + carry if it has been defined + (this = this - ss2 - c) + + c must be zero or one (might be a bigger value than 1) + function returns carry (1) (if it was) + */ + template + uint UInt::Sub(const UInt & ss2, uint c) + { + register uint b = value_size; + register uint * p1 = table; + register uint * p2 = const_cast(ss2.table); + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%rbx \n" + "push %%rcx \n" + "push %%rdx \n" + + "movq $0, %%rax \n" + "subq %%rsi, %%rax \n" + + "1: \n" + "movq (%%rbx),%%rax \n" + "sbbq (%%rdx),%%rax \n" + "movq %%rax,(%%rbx) \n" + + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + "inc %%rdx \n" + + "loop 1b \n" + + "movq $0, %%rax \n" + "adcq %%rax,%%rax \n" + "movq %%rax, %%rsi \n" + + "pop %%rdx \n" + "pop %%rcx \n" + "pop %%rbx \n" + + : "=S" (c) + : "0" (c), "c" (b), "b" (p1), "d" (p2) + : "%rax", "cc", "memory" ); + + #endif + + + return c; + } + + + /*! + this method subtracts one word (at a specific position) + and returns a carry (if it was) + + e.g. + + if we've got (value_size=3): + table[0] = 10; + table[1] = 30; + table[2] = 5; + and we call: + SubInt(2,1) + then it'll be: + table[0] = 10; + table[1] = 30 - 2; + table[2] = 5; + + of course if there was a carry from table[3] it would be returned + */ + template + uint UInt::SubInt(uint value, uint index) + { + register uint b = value_size; + register uint * p1 = table; + register uint c; + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%rbx \n" + "push %%rcx \n" + "push %%rdx \n" + + "subq %%rdx, %%rcx \n" + + "leaq (%%rbx,%%rdx,8), %%rbx \n" + + "movq %4, %%rdx \n" + "clc \n" + "1: \n" + + "movq (%%rbx), %%rax \n" + "sbbq %%rdx, %%rax \n" + "movq %%rax, (%%rbx) \n" + + "jnc 2f \n" + + "movq $0, %%rdx \n" + + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "loop 1b \n" + + "2: \n" + + "movq $0, %%rax \n" + "adcq %%rax,%%rax \n" + + "pop %%rdx \n" + "pop %%rcx \n" + "pop %%rbx \n" + + : "=a" (c) + : "c" (b), "d" (index), "b" (p1), "q" (value) + : "cc", "memory" ); + + #endif + + + return c; + } + + + /*! + 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 + */ + template + uint UInt::Rcl(uint c) + { + register sint b = value_size; + register uint * p1 = table; + + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%rbx \n" + "push %%rcx \n" + + "movq $0,%%rax \n" + "subq %%rdx,%%rax \n" + + "1: \n" + "rclq $1,(%%rbx) \n" + + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + "inc %%rbx \n" + + "loop 1b \n" + + "movq $0, %%rdx \n" + "adcq %%rdx,%%rdx \n" + + "pop %%rcx \n" + "pop %%rbx \n" + + : "=d" (c) + : "0" (c), "c" (b), "b" (p1) + : "%rax", "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 + */ + template + uint UInt::Rcr(uint c) + { + register sint b = value_size; + register uint * p1 = table; + + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "push %%rbx \n" + "push %%rcx \n" + + "leaq (%%rbx,%%rcx,8),%%rbx \n" + + "movq $0, %%rax \n" + "subq %%rdx, %%rax \n" + + "1: \n" + "dec %%rbx \n" + "dec %%rbx \n" + "dec %%rbx \n" + "dec %%rbx \n" + "dec %%rbx \n" + "dec %%rbx \n" + "dec %%rbx \n" + "dec %%rbx \n" + + "rcrq $1,(%%rbx) \n" + + "loop 1b \n" + + "movq $0, %%rdx \n" + "adcq %%rdx,%%rdx \n" + + "pop %%rcx \n" + "pop %%rbx \n" + + : "=d" (c) + : "0" (c), "c" (b), "b" (p1) + : "%rax", "cc", "memory" ); + + #endif + + + return c; + } + + + /* + this method returns the number of the highest set bit in one 32-bit word + if the 'x' is zero this method returns '-1' + */ + template + sint UInt::FindLeadingBitInWord(uint x) + { + register sint result; + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + + "bsrq %%rbx, %%rax \n" + "jnz 1f \n" + "movq $-1, %%rax \n" + "1: \n" + + : "=a" (result) + : "b" (x) + : "cc" ); + + #endif + + + return result; + } + + + /*! + this method sets a special bit in the 'value' + and returns the result + + bit is from <0,31> + + e.g. + SetBitInWord(0,0) = 1 + SetBitInWord(0,2) = 4 + SetBitInWord(10, 8) = 266 + */ + template + uint UInt::SetBitInWord(uint value, uint bit) + { + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + __asm__ __volatile__( + + "btsq %%rbx,%%rax \n" + + : "=a" (value) + : "0" (value), "b" (bit) + : "cc" ); + + #endif + + return value; + } + + + /*! + * + * Multiplication + * + * + */ + + + /*! + multiplication: result2:result1 = a * b + result2 - higher word + result1 - lower word of the result + + this methos never returns a carry + + it is an auxiliary method for version two of the multiplication algorithm + */ + template + void UInt::MulTwoWords(uint a, uint b, uint * result2, uint * result1) + { + /* + we must use these temporary variables in order to inform the compilator + that value pointed with result1 and result2 has changed + + this has no effect in visual studio but it's usefull when + using gcc and options like -O + */ + register uint result1_; + register uint result2_; + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + + #endif + + + #ifdef __GNUC__ + + asm __volatile__( + + "mulq %%rdx \n" + + : "=a" (result1_), "=d" (result2_) + : "0" (a), "1" (b) + : "cc" ); + + #endif + + + *result1 = result1_; + *result2 = result2_; + } + + + + + /*! + * + * Division + * + * + */ + + + /*! + this method calculates 64bits word a:b / 32bits c (a higher, b lower word) + r = a:b / c and rest - remainder + + * + * WARNING: + * if r (one word) is too small for the result or c is equal zero + * there'll be a hardware interruption (0) + * and probably the end of your program + * + */ + template + void UInt::DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest) + { + register uint r_; + register uint rest_; + /* + these variables have similar meaning like those in + the multiplication algorithm MulTwoWords + */ + + #ifndef __GNUC__ + + #error "another compiler than GCC is currently not supported in 64bit mode" + + __asm + { + } + #endif + + + #ifdef __GNUC__ + + __asm__ __volatile__( + + "divq %%rcx \n" + + : "=a" (r_), "=d" (rest_) + : "d" (a), "a" (b), "c" (c) + : "cc" ); + + #endif + + + *r = r_; + *rest = rest_; + } + +#endif + +} //namespace +