From 978815f12d0359ed57dd459797d65222d9072768 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Wed, 11 Mar 2009 19:05:13 +0000 Subject: [PATCH] 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) -> Big::Pow(UInt pow) it returns 2 when there is: 0^0 changed: renamed: Big::PowInt(Int pow) -> Big::Pow(Int 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 pow) and Int::Pow(Int pow) git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@104 e52654a7-88a9-db11-a3e9-0013d4bc506e --- tests/main.cpp | 49 +++++++++++++- tests/uinttest.cpp | 2 +- tests/uinttest.h | 2 +- ttmath/ttmathbig.h | 145 ++++++++++++++++++++++++++---------------- ttmath/ttmathint.h | 66 ++++++++++++++++++- ttmath/ttmathtypes.h | 4 +- ttmath/ttmathuint.h | 118 ++++++++++++++++++++++++++-------- ttmath/ttmathuint64.h | 58 +++++++++++------ 8 files changed, 337 insertions(+), 107 deletions(-) diff --git a/tests/main.cpp b/tests/main.cpp index 3fda820..1993dbd 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -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(); diff --git a/tests/uinttest.cpp b/tests/uinttest.cpp index caf9e7b..8f45a0f 100644 --- a/tests/uinttest.cpp +++ b/tests/uinttest.cpp @@ -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 diff --git a/tests/uinttest.h b/tests/uinttest.h index b8fe3ef..b912e90 100644 --- a/tests/uinttest.h +++ b/tests/uinttest.h @@ -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 diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index c87bb90..5a63886 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -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 PowUInt(UInt pow) + uint Pow(UInt pow) { if(pow.IsZero() && IsZero()) // we don't define zero^zero - return 1; + return 2; - Big start(*this); + Big start(*this), start_temp; Big 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 PowInt(Int pow) + uint Pow(Int pow) { if( !pow.IsSign() ) - return PowUInt(pow); - + return Pow( UInt(pow) ); if( IsZero() ) // if 'p' is negative then // 'this' must be different from zero - return 1; + return 2; if( pow.ChangeSign() ) return 1; Big t(*this); - if( t.PowUInt(pow) ) - return 1; + uint c_temp = t.Pow( UInt(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 pow) + uint PowUInt(Big 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 & pow) + uint PowInt(const Big & 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 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 & 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 & 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; diff --git a/ttmath/ttmathint.h b/ttmath/ttmathint.h index 27a4b2b..7c2fa4b 100644 --- a/ttmath/ttmathint.h +++ b/ttmath/ttmathint.h @@ -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 & pow) + { + bool was_sign = IsSign(); + uint c = 0; + + if( was_sign ) + c += Abs(); + + uint c_temp = UInt::Pow(pow); + if( c_temp > 0 ) + return c_temp; // c_temp can be: 0, 1 or 2 + + if( was_sign && (pow.table[0] & 1) == 1 ) + // negative value to the power of odd number is negative + c += ChangeSign(); + + return (c==0)? 0 : 1; + } + + +public: + + + /*! + power this = this ^ pow + + return values: + 0 - ok + 1 - carry + 2 - incorrect arguments 0^0 or 0^(-something) + */ + uint Pow(Int pow) + { + if( !pow.IsSign() ) + return Pow2(pow); + + if( UInt::IsZero() ) + // if 'p' is negative then + // 'this' must be different from zero + return 2; + + if( pow.ChangeSign() ) + return 1; + + Int t(*this); + uint c_temp = t.Pow2(pow); + if( c_temp > 0 ) + return c_temp; + + UInt::SetOne(); + if( Div(t) ) + return 1; + + return 0; + } + /*! * diff --git a/ttmath/ttmathtypes.h b/ttmath/ttmathtypes.h index 941549a..a3120a2 100644 --- a/ttmath/ttmathtypes.h +++ b/ttmath/ttmathtypes.h @@ -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 /*! diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h index 7642060..3c51a4b 100644 --- a/ttmath/ttmathuint.h +++ b/ttmath/ttmathuint.h @@ -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 && bits0 && bits - 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 pow) + { + if(pow.IsZero() && IsZero()) + // we don't define zero^zero + return 2; + + UInt start(*this), start_temp; + UInt 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 & 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); diff --git a/ttmath/ttmathuint64.h b/ttmath/ttmathuint64.h index d2d42ff..d3a191f 100644 --- a/ttmath/ttmathuint64.h +++ b/ttmath/ttmathuint64.h @@ -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(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(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 UInt::Rcl2(uint bits, uint c) { - if( bits == 0 ) - return 0; - TTMATH_ASSERT( bits>0 && bits uint UInt::Rcr2(uint bits, uint c) { - if( bits == 0 ) - return 0; - TTMATH_ASSERT( bits>0 && bits + 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 UInt::SetBitInWord(uint value, uint bit) + uint UInt::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; }