fixed: there was a TTMATH_REREFENCE_ASSERT error in Big::PowUInt() caused by: start.Mul(start)

fixed:   Big::Add incorrectly rounded 'this' when both exponents were equal
         it caused that sometimes when adding a zero the result has changed
         this had impact among other things on FromString() method
         "0,8" had different binary representation from "0,80"
changed: renamed: Big::PowUInt(UInt<pow_size> pow) -> Big::Pow(UInt<pow_size> pow)
         it returns 2 when there is: 0^0
changed: renamed: Big::PowInt(Int<pow_size> pow) -> Big::Pow(Int<pow_size> pow)
         it returns 2 when there is: 0^0 or 0^(-something)
changed: renamed: Big::PowBUInt() -> PowUInt(), Big::PowBInt() -> Big::PowInt()
         they return 2 when the arguments are incorrect (like above)
changed: UInt::SetBitInWord(uint & value, uint bit) is taking the first argument by a reference now,
         the specific bit is set in the 'value' and the method returns the last state of the bit (zero or one)
added:   UInt::GetBit(uint bit_index) - returning the state of the specific bit
changed: UInt::SetBit(uint bit_index) - it's using TTMATH_ASSERT now
changed: Big::Mod2() - it's using mantissa.GetBit() now
added:   Big::operator=(double) and Big::Big(double)
added:   TTMATH_ASSERT somewhere in ttmathuint64.h
added:   UInt::Pow(UInt<value_size> pow) and Int::Pow(Int<value_size> pow)


git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@104 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2009-03-11 19:05:13 +00:00
parent 404727f3de
commit 978815f12d
8 changed files with 337 additions and 107 deletions

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -59,7 +59,52 @@ void test_uint()
int main()
{
using namespace ttmath;
/*
Int<300> uu, oo;
uu = -2;
oo = 5;
uint ccc = uu.Pow(oo);
if( ccc )
std::cout << "carry: " << ccc << std::endl;
else
std::cout << uu << std::endl;
return 0;
*/
/*
UInt<2> w = 100;
w.GetBit(64);
std::cout << w << std::endl;
return 0;
*/
/*
uint q = 100;
uint last = UInt<3>::SetBitInWord(q, 3);
std::cout << "nowa wartosc: " << q << ", wczesniejszy bit: " << last << std::endl;
return 0;
*/
/*
Big<1, 3> a = -26;
Int<3> b = -8;
uint c = a.Pow(b);
if ( c )
std::cout << "carry: " << c << std::endl;
else
std::cout << a << std::endl;
return 0;
*/
test_uint();

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -561,9 +561,9 @@ public:
}
if( exp_offset > mantissa_size_in_bits )
if( exp_offset >= mantissa_size_in_bits )
{
// the second value is too short for taking into consideration in the sum
// the second value is too small for taking into consideration in the sum
return 0;
}
else
@ -572,13 +572,6 @@ public:
// (2) moving 'exp_offset' times
ss2.mantissa.Rcr( exp_offset.ToInt(), 0 );
}
else
{
// (3)
// exp_offset == mantissa_size_in_bits
// we're rounding 'this' about one (up or down depending on a ss2 sign)
ss2.mantissa.SetOne();
}
if( IsSign() == ss2.IsSign() )
@ -594,8 +587,8 @@ public:
{
// values have different signs
// there shouldn't be a carry here because
// (1) (2) and (3) guarantee that the mantissa of this
// is greater than the mantissa of the ss2
// (1) (2) guarantee that the mantissa of this
// is greater than or equal to the mantissa of the ss2
uint c_temp = mantissa.Sub(ss2.mantissa);
TTMATH_ASSERT( c_temp == 0 )
@ -653,7 +646,7 @@ public:
if( exp_offset >= mantissa_size_in_bits )
{
// the second value is too short
// the second value is too small
SetZero();
return 0;
}
@ -700,7 +693,7 @@ public:
}
if( exp_offset >= mantissa_size_in_bits )
// the second value is too short
// the second value is too small
return 0;
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
@ -745,7 +738,7 @@ public:
}
if( exp_offset >= mantissa_size_in_bits )
// the second value is too short
// the second value is too small
return 0;
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
@ -966,18 +959,23 @@ public:
/*!
power this = this ^ pow
pow without a sign
(pow without a sign)
binary algorithm (r-to-l)
return values:
0 - ok
1 - carry
2 - incorrect arguments (0^0)
*/
template<uint pow_size>
uint PowUInt(UInt<pow_size> pow)
uint Pow(UInt<pow_size> pow)
{
if(pow.IsZero() && IsZero())
// we don't define zero^zero
return 1;
return 2;
Big<exp, man> start(*this);
Big<exp, man> start(*this), start_temp;
Big<exp, man> result;
result.SetOne();
@ -987,7 +985,8 @@ public:
if( result.Mul(start) )
return 1;
if( start.Mul(start) )
start_temp = start;
if( start.Mul(start_temp) )
return 1;
pow.Rcr(1);
@ -1001,27 +1000,31 @@ public:
/*!
power this = this ^ pow
p can be with a sign
p can be negative
return values:
0 - ok
1 - carry
2 - incorrect arguments 0^0 or 0^(-something)
*/
template<uint pow_size>
uint PowInt(Int<pow_size> pow)
uint Pow(Int<pow_size> pow)
{
if( !pow.IsSign() )
return PowUInt(pow);
return Pow( UInt<pow_size>(pow) );
if( IsZero() )
// if 'p' is negative then
// 'this' must be different from zero
return 1;
return 2;
if( pow.ChangeSign() )
return 1;
Big<exp, man> t(*this);
if( t.PowUInt(pow) )
return 1;
uint c_temp = t.Pow( UInt<pow_size>(pow) );
if( c_temp > 0 )
return c_temp;
SetOne();
if( Div(t) )
@ -1032,33 +1035,40 @@ public:
/*!
this method returns true if 'this' mod 2 is equal one
this method returns: 'this' mod 2
(either zero or one)
this method is much faster than using Mod( object_with_value_two )
*/
bool Mod2() const
uint Mod2() const
{
if( exponent>sint(0) || exponent<=-sint(man*TTMATH_BITS_PER_UINT) )
return false;
return 0;
sint exp_int = exponent.ToInt();
// 'exp_int' is negative (or zero), we set its as positive
// 'exp_int' is negative (or zero), we set it as positive
exp_int = -exp_int;
// !!! 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);
return mantissa.GetBit(exp_int);
}
/*!
power this = this ^ abs([pow])
pow without a sign and without a fraction
pow is treated as a value without a sign and without a fraction
if pow has a sign then the method pow.Abs() is used
if pow has a fraction the fraction is skipped (not used in calculation)
return values:
0 - ok
1 - carry
2 - incorrect arguments (0^0)
*/
uint PowBUInt(Big<exp, man> pow)
uint PowUInt(Big<exp, man> pow)
{
if( pow.IsZero() && IsZero() )
return 1;
return 2;
if( pow.IsSign() )
pow.Abs();
@ -1070,7 +1080,7 @@ public:
e_one.SetOne();
one.SetOne();
result.SetOne();
result = one;
while( pow >= one )
{
@ -1093,24 +1103,30 @@ public:
/*!
power this = this ^ [pow]
pow without a fraction
pow is treated as a value without a fraction
pow can be negative
return values:
0 - ok
1 - carry
2 - incorrect arguments 0^0 or 0^(-something)
*/
uint PowBInt(const Big<exp, man> & pow)
uint PowInt(const Big<exp, man> & pow)
{
TTMATH_REFERENCE_ASSERT( pow )
if( !pow.IsSign() )
return PowBUInt(pow);
return PowUInt(pow);
if( IsZero() )
// if 'pow' is negative then
// 'this' must be different from zero
return 1;
return 2;
Big<exp, man> temp(*this);
if( temp.PowBUInt(pow) )
return 1;
uint c_temp = temp.PowUInt(pow);
if( c_temp > 0 )
return c_temp;
SetOne();
if( Div(temp) )
@ -1122,13 +1138,13 @@ public:
/*!
power this = this ^ pow
this *must* be greater than zero (this > 0)
this must be greater than zero (this > 0)
pow can be negative and with fraction
return values:
0 - ok
1 - carry
2 - incorrect argument ('this')
2 - incorrect argument ('this' <= 0)
*/
uint PowFrac(const Big<exp, man> & pow)
{
@ -1147,6 +1163,7 @@ public:
}
/*!
power this = this ^ pow
pow can be negative and with fraction
@ -1175,7 +1192,7 @@ public:
pow_frac.RemainFraction();
if( pow_frac.IsZero() )
return PowBInt( pow );
return PowInt( pow );
// pow is with fraction (not integer)
// result = e^(pow * ln(this) ) where 'this' must be greater than 0
@ -1318,7 +1335,7 @@ public:
else
{
ExpSurrounding0(m);
c += PowBUInt(e_);
c += PowUInt(e_);
}
return (c==0)? 0 : 1;
@ -1793,7 +1810,7 @@ public:
// where "1.F" is intended to represent the binary number
// created by prefixing F with an implicit leading 1 and a binary point.
FromDouble_SetExpAndMan(bool(temp.u[1] & 0x80000000u),
FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0,
e - 1023 - man*TTMATH_BITS_PER_UINT + 1, 0x80000000u,
m1, m2);
@ -1815,7 +1832,7 @@ public:
m.table[0] = m2;
uint moved = m.CompensationToLeft();
FromDouble_SetExpAndMan(bool(temp.u[1] & 0x80000000u),
FromDouble_SetExpAndMan((temp.u[1] & 0x80000000u) != 0,
e - 1022 - man*TTMATH_BITS_PER_UINT + 1 - moved, 0,
m.table[1], m.table[2]);
}
@ -1906,7 +1923,7 @@ public:
// where "1.F" is intended to represent the binary number
// created by prefixing F with an implicit leading 1 and a binary point.
FromDouble_SetExpAndMan(bool(temp.u & 0x8000000000000000ul),
FromDouble_SetExpAndMan((temp.u & 0x8000000000000000ul) != 0,
e - 1023 - man*TTMATH_BITS_PER_UINT + 1,
0x8000000000000000ul, m);
@ -2118,6 +2135,17 @@ public:
}
/*!
an operator= for converting 'double' to this class
*/
Big<exp, man> & operator=(double value)
{
FromDouble(value);
return *this;
}
/*!
a constructor for converting 'sint' to this class
*/
@ -2135,6 +2163,15 @@ public:
}
/*!
a constructor for converting 'double' to this class
*/
Big(double value)
{
FromDouble(value);
}
#ifdef TTMATH_PLATFORM64
/*!
@ -3324,7 +3361,7 @@ private:
new_exponent.ChangeSign();
temp = 10;
c += temp.PowBInt( new_exponent );
c += temp.PowInt( new_exponent );
c += Mul(temp);
return (c==0)? 0 : 1;

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -469,6 +469,70 @@ public:
private:
/*!
power this = this ^ pow
this can be negative
pow is >= 0
*/
uint Pow2(const Int<value_size> & pow)
{
bool was_sign = IsSign();
uint c = 0;
if( was_sign )
c += Abs();
uint c_temp = UInt<value_size>::Pow(pow);
if( c_temp > 0 )
return c_temp; // c_temp can be: 0, 1 or 2
if( was_sign && (pow.table[0] & 1) == 1 )
// negative value to the power of odd number is negative
c += ChangeSign();
return (c==0)? 0 : 1;
}
public:
/*!
power this = this ^ pow
return values:
0 - ok
1 - carry
2 - incorrect arguments 0^0 or 0^(-something)
*/
uint Pow(Int<value_size> pow)
{
if( !pow.IsSign() )
return Pow2(pow);
if( UInt<value_size>::IsZero() )
// if 'p' is negative then
// 'this' must be different from zero
return 2;
if( pow.ChangeSign() )
return 1;
Int<value_size> t(*this);
uint c_temp = t.Pow2(pow);
if( c_temp > 0 )
return c_temp;
UInt<value_size>::SetOne();
if( Div(t) )
return 1;
return 0;
}
/*!
*

View File

@ -64,8 +64,8 @@
*/
#define TTMATH_MAJOR_VER 0
#define TTMATH_MINOR_VER 8
#define TTMATH_REVISION_VER 2
#define TTMATH_PRERELEASE_VER 0
#define TTMATH_REVISION_VER 3
#define TTMATH_PRERELEASE_VER 1
/*!

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -950,9 +950,6 @@ private:
*/
uint Rcl2(uint bits, uint c)
{
if( bits == 0 )
return 0;
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
register sint b = value_size;
@ -1078,9 +1075,6 @@ private:
*/
uint Rcr2(uint bits, uint c)
{
if( bits == 0 )
return 0;
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
register sint b = value_size;
@ -1503,30 +1497,40 @@ public:
#ifdef TTMATH_PLATFORM32
/*!
this method sets a special bit in the 'value'
and returns the result
and returns the last state of the bit (zero or one)
bit is from <0,31>
e.g.
SetBitInWord(0,0) = 1
SetBitInWord(0,2) = 4
SetBitInWord(10, 8) = 266
uint x = 100;
uint bit = SetBitInWord(x, 3);
now: x = 108 and bit = 0
*/
static uint SetBitInWord(uint value, uint bit)
static uint SetBitInWord(uint & value, uint bit)
{
TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT )
uint old_bit;
uint v = value;
#ifndef __GNUC__
__asm
{
push ebx
push eax
mov eax, [value]
mov eax, [v]
mov ebx, [bit]
bts eax, ebx
mov [value], eax
mov [v], eax
setc bl
movzx ebx, bl
mov [old_bit], ebx
pop eax
pop ebx
}
@ -1536,15 +1540,20 @@ public:
#ifdef __GNUC__
__asm__ __volatile__(
"btsl %2,%0 \n"
"btsl %%ebx, %%eax \n"
: "=R" (value)
: "0" (value), "R" (bit)
"setc %%bl \n"
"movzx %%bl, %%ebx \n"
: "=a" (v), "=b" (old_bit)
: "0" (v), "1" (bit)
: "cc" );
#endif
return value;
value = v;
return old_bit;
}
#endif
@ -1555,15 +1564,33 @@ public:
bit_index bigger or equal zero
*/
void SetBit(uint bit_index)
uint GetBit(uint bit_index) const
{
TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT )
uint index = bit_index / TTMATH_BITS_PER_UINT;
if( index >= value_size )
return;
uint bit = bit_index % TTMATH_BITS_PER_UINT;
bit_index %= TTMATH_BITS_PER_UINT;
uint temp = table[index];
return SetBitInWord(temp, bit);
}
table[index] = SetBitInWord(table[index], bit_index);
/*!
setting the 'bit_index' bit
and returning the last state of the bit
bit_index bigger or equal zero
*/
uint SetBit(uint bit_index)
{
TTMATH_ASSERT( bit_index < value_size * TTMATH_BITS_PER_UINT )
uint index = bit_index / TTMATH_BITS_PER_UINT;
uint bit = bit_index % TTMATH_BITS_PER_UINT;
return SetBitInWord(table[index], bit);
}
@ -2736,6 +2763,47 @@ private:
public:
/*!
power this = this ^ pow
binary algorithm (r-to-l)
return values:
0 - ok
1 - carry or
2 - incorrect argument (0^0)
*/
uint Pow(UInt<value_size> pow)
{
if(pow.IsZero() && IsZero())
// we don't define zero^zero
return 2;
UInt<value_size> start(*this), start_temp;
UInt<value_size> result;
result.SetOne();
while( !pow.IsZero() )
{
if( pow.table[0] & 1 )
if( result.Mul(start) )
return 1;
start_temp = start;
// in the second Mul algorithm we can use start.Mul(start) directly (there is no TTMATH_ASSERT_REFERENCE there)
if( start.Mul(start_temp) )
return 1;
pow.Rcr2_one(0);
}
*this = result;
return 0;
}
/*!
this method sets n first bits to value zero
@ -3607,7 +3675,7 @@ public:
uint Sub(const UInt<value_size> & ss2, uint c=0);
uint SubInt(uint value, uint index = 0);
static sint FindLeadingBitInWord(uint x);
static uint SetBitInWord(uint value, uint bit);
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);

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2008, Tomasz Sowa
* Copyright (c) 2006-2009, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -210,10 +210,12 @@ namespace ttmath
register uint * p2 = const_cast<uint*>(ss2.table);
// we don't have to use TTMATH_REFERENCE_ASSERT here
// this algorithm doesn't require it
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
#ifdef __GNUC__
/*
@ -281,6 +283,8 @@ namespace ttmath
register uint * p1 = table;
register uint c;
TTMATH_ASSERT( index < value_size )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
@ -361,6 +365,8 @@ namespace ttmath
register uint * p1 = table;
register uint c;
TTMATH_ASSERT( index < value_size - 1 )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
@ -424,6 +430,9 @@ namespace ttmath
register uint * p1 = table;
register uint * p2 = const_cast<uint*>(ss2.table);
// we don't have to use TTMATH_REFERENCE_ASSERT here
// this algorithm doesn't require it
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
@ -489,6 +498,8 @@ namespace ttmath
register uint * p1 = table;
register uint c;
TTMATH_ASSERT( index < value_size )
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
@ -559,8 +570,8 @@ namespace ttmath
"push %%rdx \n"
"push %%rcx \n"
"xorq %%rdx, %%rdx \n" // edx=0
"neg %%rax \n" // CF=1 if eax!=0 , CF=0 if eax==0
"xorq %%rdx, %%rdx \n" // rdx=0
"neg %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0
"1: \n"
"rclq $1, (%%rbx, %%rdx, 8) \n"
@ -616,7 +627,7 @@ namespace ttmath
"push %%rcx \n"
"neg %%rax \n" // CF=1 if eax!=0 , CF=0 if eax==0
"neg %%rax \n" // CF=1 if rax!=0 , CF=0 if rax==0
"1: \n"
"rcrq $1, -8(%%rbx, %%rcx, 8) \n"
@ -658,9 +669,6 @@ namespace ttmath
template<uint value_size>
uint UInt<value_size>::Rcl2(uint bits, uint c)
{
if( bits == 0 )
return 0;
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
register sint b = value_size;
@ -739,9 +747,6 @@ namespace ttmath
template<uint value_size>
uint UInt<value_size>::Rcr2(uint bits, uint c)
{
if( bits == 0 )
return 0;
TTMATH_ASSERT( bits>0 && bits<TTMATH_BITS_PER_UINT )
register sint b = value_size;
@ -843,20 +848,26 @@ namespace ttmath
/*!
this method sets a special bit in the 'value'
and returns the result
and returns the last state of the bit (zero or one)
***this method is created only on a 64bit platform***
bit is from <0,31>
bit is from <0,63>
e.g.
SetBitInWord(0,0) = 1
SetBitInWord(0,2) = 4
SetBitInWord(10, 8) = 266
uint x = 100;
uint bit = SetBitInWord(x, 3);
now: x = 108 and bit = 0
*/
template<uint value_size>
uint UInt<value_size>::SetBitInWord(uint value, uint bit)
uint UInt<value_size>::SetBitInWord(uint & value, uint bit)
{
TTMATH_ASSERT( bit < TTMATH_BITS_PER_UINT )
uint old_bit;
uint v = value;
#ifndef __GNUC__
#error "another compiler than GCC is currently not supported in 64bit mode"
#endif
@ -864,15 +875,20 @@ namespace ttmath
#ifdef __GNUC__
__asm__ __volatile__(
"btsq %%rbx,%%rax \n"
"btsq %%rbx, %%rax \n"
: "=a" (value)
: "0" (value), "b" (bit)
"setc %%bl \n"
"movzx %%bl, %%rbx \n"
: "=a" (v), "=b" (old_bit)
: "0" (v), "1" (bit)
: "cc" );
#endif
return value;
value = v;
return old_bit;
}