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
This commit is contained in:
Tomasz Sowa 2007-01-29 17:58:18 +00:00
parent 1dabd725cb
commit b59de36095
8 changed files with 1525 additions and 371 deletions

View File

@ -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

View File

@ -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 );

View File

@ -52,7 +52,7 @@ namespace ttmath
/*!
\brief it implements the big value
*/
template <int exp,int man>
template <uint exp,uint man>
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> exp_offset( exponent );
Int<exp> 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*2> 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<exp, man> & pow)'
there should be 'sint Pow(const Big<exp, man> & 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<exp, man> & pow)
uint Pow(const Big<exp, man> & pow)
#else
int Pow(const Big<exp, man> pow)
uint Pow(const Big<exp, man> pow)
#endif
{
TTMATH_REFERENCE_ASSERT( pow )
@ -869,7 +870,7 @@ public:
// m will be the value of the mantissa in range (-1,1)
Big<exp,man> 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<exp,man> m(x);
m.exponent = -int(man*TTMATH_BITS_PER_UINT - 1);
m.exponent = -sint(man*TTMATH_BITS_PER_UINT - 1);
LnSurrounding1(m);
Big<exp,man> 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<man> 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<int_size>' type (it's too big)
return 1;
@ -1185,7 +1186,7 @@ public:
return 0;
UInt<man> 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<exp, man> & operator=(int value)
Big<exp, man> & 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<int_size>' 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<exp,man> 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<exp,man> log_history[15] = { 0l,0l,0l,0l,0l,0l,0l,0l,0l,0l,
// 0l,0l,0l,0l,0l };
static Big<exp,man> log_history[15] = { 0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0 };
Big<exp,man> * 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<exp+1> & 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<TTMATH_BITS_PER_UINT ; ++bit )
for( uint bit=0 ; bit<TTMATH_BITS_PER_UINT ; ++bit )
{
if( (value & TTMATH_UINT_HIGHEST_BIT) != 0 )
new_man += '1';
@ -1776,7 +1804,7 @@ private:
if( new_man.empty() )
return;
int i = int( new_man.length() ) - 1;
sint i = sint( new_man.length() ) - 1;
bool was_carry = true;
for( ; i>=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<exp+1> & new_exp,
uint ToString_SetCommaAndExponent( std::string & new_man, uint base, Int<exp+1> & 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<exp+1>' instead of 'Int<exp>'
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<exp+1> & new_exp, int max_digit_after_comma) const
Int<exp+1> & 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<exp+1> & new_exp, int max_digit_after_comma) const
uint base, Int<exp+1> & 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<exp+1> & 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<exp, man> temp;
Big<exp, man> 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<exp, man> 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<exp, man> new_exponent, temp;
bool was_sign = false;
@ -2291,7 +2321,7 @@ private:
*/
uint FromString_ReadPartScientific_ReadExponent( const char * & source, Big<exp, man> & new_exponent )
{
int character;
sint character;
Big<exp, man> base, temp;
UInt<man>::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

View File

@ -465,9 +465,9 @@ public:
/*!
this method convert an int type to this class
this method convert an sint type to this class
*/
Int<value_size> & operator=(int i)
Int<value_size> & 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<value_size>::table[0] );
return sint( UInt<value_size>::table[0] );
}
@ -676,10 +676,10 @@ public:
bool operator<(const Int<value_size> & l) const
{
int i=value_size-1;
sint i=value_size-1;
int a1 = int(UInt<value_size>::table[i]);
int a2 = int(l.table[i]);
sint a1 = sint(UInt<value_size>::table[i]);
sint a2 = sint(l.table[i]);
if( a1 != a2 )
return a1 < a2;
@ -703,11 +703,11 @@ public:
bool operator>(const Int<value_size> & l) const
{
int i=value_size-1;
sint i=value_size-1;
int a1 = int(UInt<value_size>::table[i]);
int a2 = int(l.table[i]);
sint a1 = sint(UInt<value_size>::table[i]);
sint a2 = sint(l.table[i]);
if( a1 != a2 )
return a1 > a2;
@ -730,11 +730,11 @@ public:
bool operator<=(const Int<value_size> & l) const
{
int i=value_size-1;
sint i=value_size-1;
int a1 = int(UInt<value_size>::table[i]);
int a2 = int(l.table[i]);
sint a1 = sint(UInt<value_size>::table[i]);
sint a2 = sint(l.table[i]);
if( a1 != a2 )
return a1 < a2;
@ -757,11 +757,11 @@ public:
bool operator>=(const Int<value_size> & l) const
{
int i=value_size-1;
sint i=value_size-1;
int a1 = int(UInt<value_size>::table[i]);
int a2 = int(l.table[i]);
sint a1 = sint(UInt<value_size>::table[i]);
sint a2 = sint(l.table[i]);
if( a1 != a2 )
return a1 > a2;

View File

@ -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

View File

@ -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)

File diff suppressed because it is too large Load Diff

855
ttmath/ttmathuint64.h Normal file
View File

@ -0,0 +1,855 @@
/*
* This file is a part of TTMath Mathematical Library
* and is distributed under the (new) BSD licence.
* Author: Tomasz Sowa <t.sowa@slimaczek.pl>
*/
/*
* 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<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 value_size>
uint UInt<value_size>::Add(const UInt<value_size> & ss2, uint c)
{
register uint b = value_size;
register uint * p1 = table;
register uint * p2 = const_cast<uint*>(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 value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::Sub(const UInt<value_size> & ss2, uint c)
{
register uint b = value_size;
register uint * p1 = table;
register uint * p2 = const_cast<uint*>(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 value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::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 value_size>
uint UInt<value_size>::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<uint value_size>
sint UInt<value_size>::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 value_size>
uint UInt<value_size>::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<uint value_size>
void UInt<value_size>::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<uint value_size>
void UInt<value_size>::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