added: bool UInt::IsOnlyTheHighestBitSet()

bool UInt::IsOnlyTheLowestBitSet()
         returning true if only the highest/lowest bit is set
added:   uint Int::MulInt(sint ss2)       
added:   void UInt::Swap(UInt<value_size> & ss2)       
         void Big::Swap(UInt<value_size> & ss2)
         method for swapping this for an argument
changed: small optimization in Big::Sub()
changed: now asm version is available only on x86 and amd64
         (and only for GCC and MS VC compilers)
removed: macro TTMATH_RELEASE
         for debug version define TTMATH_DEBUG macro
         TTMATH_DEBUG is also automatically defined when DEBUG or _DEBUG is set



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@304 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2010-09-05 18:21:58 +00:00
parent 69f065245e
commit a1c41c02db
5 changed files with 256 additions and 125 deletions

View File

@ -1,7 +1,39 @@
Version 0.9.2 prerelease (2009.03.01):
Version 0.9.2 prerelease (2010.09.05):
* fixed: Big::Add() sometimes incorrectly rounded the last bit from its mantissa
* fixed: Big::BigAnd() Big::BigOr() Big::BigXor() should have set NaN
when the argument was negative (they only returned 2)
* fixed: recurrence calling in Big::FromString(const std::string &, uint, const wchar_t **, bool *)
it should have the signature: Big::FromString(const std::string &, uint, const char **, bool *)
* added: some missing operators
UInt::operator~() /* bitwise neg */
UInt::operator&() /* bitwise and */
UInt::operator&=()
UInt::operator|() /* bitwise or */
UInt::operator|=()
UInt::operator^() /* bitwise xor */
UInt::operator^=()
Big::operator&()
Big::operator&=()
Big::operator|()
Big::operator|=()
Big::operator^()
Big::operator^=()
for Big<> we do not define bitwise neg
* added: macro TTMATH_DONT_USE_WCHAR
if defined then the library does not use wide characters
(wchar_t, std::wstring, ...) this is a workaround for some compilers
* added: bool UInt::IsOnlyTheHighestBitSet()
bool UInt::IsOnlyTheLowestBitSet()
returning true if only the highest/lowest bit is set
* added: uint Int::MulInt(sint ss2)
* added: void UInt::Swap(UInt<value_size> & ss2)
void Big::Swap(UInt<value_size> & ss2)
method for swapping this for an argument
* changed: now asm version is available only on x86 and amd64
(and only for GCC and MS VC compilers)
* removed: macro TTMATH_RELEASE
for debug version define TTMATH_DEBUG macro
TTMATH_DEBUG is also automatically defined when DEBUG or _DEBUG is set
Version 0.9.1 (2010.02.07):

View File

@ -294,6 +294,20 @@ public:
}
/*!
this method swappes this for an argument
*/
void Swap(Big<exp, man> & ss2)
{
unsigned char info_temp = info;
info = ss2.info;
ss2.info = info_temp;
exponent.Swap(ss2.exponent);
mantissa.Swap(ss2.mantissa);
}
private:
/*!
@ -862,7 +876,7 @@ public:
it returns carry if the sum is too big
*/
uint Add(Big<exp, man> ss2, bool round = true)
uint Add(Big<exp, man> ss2, bool round = true, bool adding = true)
{
bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up;
Int<exp> exp_offset( exponent );
@ -871,18 +885,15 @@ public:
if( IsNan() || ss2.IsNan() )
return CheckCarry(1);
if( !adding )
ss2.ChangeSign(); // subtracting
exp_offset.Sub( ss2.exponent );
exp_offset.Abs();
// (1) abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
{
// !! use Swap here (not implemented yet)
Big<exp, man> temp(ss2);
ss2 = *this;
*this = temp;
}
Swap(ss2);
if( ss2.IsZero() )
return 0;
@ -908,17 +919,14 @@ public:
}
/*!
Subtraction this = this - ss2
it returns carry if the result is too big
*/
uint Sub(Big<exp, man> ss2, bool round = true)
uint Sub(const Big<exp, man> & ss2, bool round = true)
{
ss2.ChangeSign();
return Add(ss2, round);
return Add(ss2, round, false);
}
@ -961,12 +969,7 @@ public:
// abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
{
Big<exp, man> temp(ss2);
ss2 = *this;
*this = temp;
}
Swap(ss2);
if( exp_offset >= mantissa_size_in_bits )
{
@ -1024,12 +1027,7 @@ public:
// abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
{
Big<exp, man> temp(ss2);
ss2 = *this;
*this = temp;
}
Swap(ss2);
if( exp_offset >= mantissa_size_in_bits )
// the second value is too small
@ -1084,12 +1082,7 @@ public:
// abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
{
Big<exp, man> temp(ss2);
ss2 = *this;
*this = temp;
}
Swap(ss2);
if( exp_offset >= mantissa_size_in_bits )
// the second value is too small

View File

@ -104,13 +104,10 @@ public:
*/
uint ChangeSign()
{
Int<value_size> temp;
temp.SetMin();
/*
if the value is equal that one which has been returned from SetMin
that means we can't change sign because the value is too big (bigger about one)
(only the highest bit is set) that means we can't change sign
because the value is too big (bigger about one)
e.g. when value_size = 1 and value is -2147483648 we can't change it to the
2147483648 because the max value which can be held is 2147483647
@ -119,13 +116,12 @@ public:
(if we look on our value without the sign we get the correct value
eg. -2147483648 in Int<1> will be 2147483648 on the UInt<1> type)
*/
if( operator==(temp) )
if( UInt<value_size>::IsOnlyTheHighestBitSet() )
return 1;
temp.SetZero();
temp.UInt<value_size>::Sub(*this);
operator=(temp);
UInt<value_size> temp(*this);
UInt<value_size>::SetZero();
UInt<value_size>::Sub(temp);
return 0;
}
@ -350,33 +346,11 @@ public:
}
private:
/*!
multiplication this = this * ss2
it returns carry if the result is too big
(we're using the method from the base class but we have to make
one correction in account of signs)
*/
uint Mul(Int<value_size> ss2)
uint CheckMinCarry(bool ss1_is_sign, bool ss2_is_sign)
{
bool ss1_is_sign, ss2_is_sign;
ss1_is_sign = IsSign();
ss2_is_sign = ss2.IsSign();
/*
we don't have to check the carry from Abs (values will be correct
because next we're using the method Mul from the base class UInt
which is without a sign)
*/
Abs();
ss2.Abs();
if( UInt<value_size>::Mul(ss2) )
return 1;
/*
we have to examine the sign of the result now
but if the result is with the sign then:
@ -391,36 +365,100 @@ public:
*/
if( IsSign() )
{
/*
there can be one case where signs are different and
the result will be equal the value from SetMin()
(this situation is ok)
*/
if( ss1_is_sign != ss2_is_sign )
{
Int<value_size> temp;
temp.SetMin();
if( operator!=(temp) )
/*
the result is too big
*/
/*
there can be one case where signs are different and
the result will be equal the value from SetMin() (only the highest bit is set)
(this situation is ok)
*/
if( !UInt<value_size>::IsOnlyTheHighestBitSet() )
return 1;
}
else
{
/*
the result is too big
*/
// signs were the same
return 1;
}
}
return 0;
}
public:
/*!
multiplication: this = this * ss2
it can return a carry
*/
uint MulInt(sint ss2)
{
bool ss1_is_sign, ss2_is_sign;
uint c;
ss1_is_sign = IsSign();
/*
we don't have to check the carry from Abs (values will be correct
because next we're using the method MulInt from the base class UInt
which is without a sign)
*/
Abs();
if( ss2 < 0 )
{
ss2 = -ss2;
ss2_is_sign = true;
}
else
{
ss2_is_sign = false;
}
c = UInt<value_size>::MulInt((uint)ss2);
c += CheckMinCarry(ss1_is_sign, ss2_is_sign);
if( ss1_is_sign != ss2_is_sign )
SetSign();
return c;
}
return 0;
/*!
multiplication this = this * ss2
it returns carry if the result is too big
(we're using the method from the base class but we have to make
one correction in account of signs)
*/
uint Mul(Int<value_size> ss2)
{
bool ss1_is_sign, ss2_is_sign;
uint c;
ss1_is_sign = IsSign();
ss2_is_sign = ss2.IsSign();
/*
we don't have to check the carry from Abs (values will be correct
because next we're using the method Mul from the base class UInt
which is without a sign)
*/
Abs();
ss2.Abs();
c = UInt<value_size>::Mul(ss2);
c += CheckMinCarry(ss1_is_sign, ss2_is_sign);
if( ss1_is_sign != ss2_is_sign )
SetSign();
return c;
}

View File

@ -56,11 +56,13 @@
#include <sstream>
#include <vector>
/*!
the version of the library
TTMATH_PRERELEASE_VER is either zero or one
if zero that means this is the release version of the library
(one means something like beta)
*/
#define TTMATH_MAJOR_VER 0
#define TTMATH_MINOR_VER 9
@ -68,58 +70,66 @@
#define TTMATH_PRERELEASE_VER 1
/*!
TTMATH_DEBUG
this macro enables further testing during writing your code
you don't have to define it in a release mode
if this macro is set then macros TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT
are set as well and these macros can throw an exception if a condition in it
is not fulfilled (look at the definition of TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT)
TTMATH_RELEASE
if you are confident that your code is perfect you can define TTMATH_RELEASE
macro for example by using -D option in gcc
gcc -DTTMATH_RELEASE -o myprogram myprogram.cpp
or by defining this macro in your code before using any header files of this library
#if !defined TTMATH_PLATFORM32 && !defined TTMATH_PLATFORM64
#if !defined _M_X64 && !defined __x86_64__
/*
other platforms than x86 and amd64 are not recognized at the moment
so you should set TTMATH_PLATFORMxx manually
*/
/*!
we're using a 32bit platform
*/
#define TTMATH_PLATFORM32
#else
/*!
we're using a 64bit platform
*/
#define TTMATH_PLATFORM64
#endif
if TTMATH_RELEASE is not set then TTMATH_DEBUG is set automatically
*/
#ifndef TTMATH_RELEASE
#define TTMATH_DEBUG
#endif
#if !defined __i386__ && !defined _X86_ && !defined _M_IX86 && !defined __x86_64__ && !defined _M_X64
/*!
x86 architecture:
__i386__ defined by GNU C
_X86_ defined by MinGW32
_M_IX86 defined by Visual Studio, Intel C/C++, Digital Mars and Watcom C/C++
amd64 architecture:
__x86_64__ defined by GNU C and Sun Studio
_M_X64 defined by Visual Studio
asm version is available only for x86 or amd64 platforms
*/
#define TTMATH_NOASM
#endif
#if !defined _MSC_VER && !defined __GNUC__
/*!
another compilers than MS VC or GCC by default use no asm version (TTMATH_NOASM)
*/
#define TTMATH_NOASM
#endif
namespace ttmath
{
#if !defined _M_X64 && !defined __x86_64__
/*!
we're using a 32bit platform
*/
#define TTMATH_PLATFORM32
#else
/*!
we're using a 64bit platform
*/
#define TTMATH_PLATFORM64
#endif
/*!
another compilers than MS VC or GCC by default use no asm version (TTMATH_NOASM)
*/
#if !defined _MSC_VER && !defined __GNUC__
#define TTMATH_NOASM
#endif
#ifdef TTMATH_PLATFORM32
@ -596,8 +606,21 @@ namespace ttmath
/*!
look at the description of macros TTMATH_RELEASE and TTMATH_DEBUG
TTMATH_DEBUG
this macro enables further testing during writing your code
you don't have to define it in a release mode
if this macro is set then macros TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT
are set as well and these macros can throw an exception if a condition in it
is not fulfilled (look at the definition of TTMATH_ASSERT and TTMATH_REFERENCE_ASSERT)
TTMATH_DEBUG is set automatically if DEBUG or _DEBUG are defined
*/
#if defined DEBUG || defined _DEBUG
#define TTMATH_DEBUG
#endif
#ifdef TTMATH_DEBUG
#if defined(__FILE__) && defined(__LINE__)

View File

@ -233,6 +233,19 @@ public:
}
/*!
this method swappes this for an argument
*/
void Swap(UInt<value_size> & ss2)
{
for(uint i=0 ; i<value_size ; ++i)
{
uint temp = table[i];
table[i] = ss2.table[i];
ss2.table[i] = temp;
}
}
#ifdef TTMATH_PLATFORM32
@ -2391,6 +2404,38 @@ public:
}
/*!
returning true if only the highest bit is set
*/
bool IsOnlyTheHighestBitSet() const
{
for(uint i=0 ; i<value_size-1 ; ++i)
if( table[i] != 0 )
return false;
if( table[value_size-1] != TTMATH_UINT_HIGHEST_BIT )
return false;
return true;
}
/*!
returning true if only the lowest bit is set
*/
bool IsOnlyTheLowestBitSet() const
{
if( table[0] != 1 )
return false;
for(uint i=1 ; i<value_size ; ++i)
if( table[i] != 0 )
return false;
return true;
}
/*!
this method returns true if the value is equal zero
*/