diff --git a/samples/Makefile b/samples/Makefile new file mode 100644 index 0000000..72ef525 --- /dev/null +++ b/samples/Makefile @@ -0,0 +1,30 @@ +CC = g++ +CFLAGS = -Wall -pedantic -s -O2 -I.. + + +.SUFFIXES: .cpp .o + +.cpp.o: + $(CC) -c $(CFLAGS) $< + + +all: uint int + + +uint: uint.o + $(CC) -o uint $(CFLAGS) uint.o + +int: int.o + $(CC) -o int $(CFLAGS) int.o + + +uint.o: uint.cpp +int.o: int.cpp + + +clean: + rm -f *.o + rm -f *.s + rm -f uint + rm -f int + rm -f *.exe diff --git a/samples/int.cpp b/samples/int.cpp new file mode 100644 index 0000000..735f26b --- /dev/null +++ b/samples/int.cpp @@ -0,0 +1,90 @@ +#include +#include + + +void SimpleCalculating(const ttmath::Int<2> & a, const ttmath::Int<2> & b) +{ + std::cout << "Simple calculating" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "a + b = " << a+b << std::endl; + std::cout << "a - b = " << a-b << std::endl; + std::cout << "a * b = " << a*b << std::endl; + std::cout << "a / b = " << a/b << std::endl; +} + + +void CalculatingWithCarry(const ttmath::Int<2> & a, const ttmath::Int<2> & b) +{ +ttmath::Int<2> atemp; + + std::cout << "Calculating with carry" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + atemp = a; + if( !atemp.Add(b) ) + std::cout << "a + b = " << atemp << std::endl; + else + std::cout << "a + b = (carry: the result is too big) " << atemp << std::endl; + + atemp = a; + if( !atemp.Sub(b) ) + std::cout << "a - b = " << atemp << std::endl; + else + std::cout << "a - b = (carry: 'a' was smaller than 'b') " << atemp << std::endl; + + atemp = a; + if( !atemp.Mul(b) ) + std::cout << "a * b = " << atemp << std::endl; + else + std::cout << "a * b = (carry: the result is too big) " << std::endl; + // it have no sense to print 'atemp' (it's undefined) + + atemp = a; + if( !atemp.Div(b) ) + std::cout << "a / b = " << atemp << std::endl; + else + std::cout << "a / b = (division by zero) " << std::endl; + +} + +int main() +{ +// on 32bit platforms: 'a' and 'b' have 2-words (two 32bit words) +// in other words a,b are from <-2^63, 2^63 - 1> +ttmath::Int<2> a,b; + + // conversion from 'const char *' + a = "123456"; + b = "98767878"; + + SimpleCalculating(a,b); + + // 'a' will have the max value which can be held in this type + a.SetMaxValue(); + + // conversion from 'int' + b = 10; + + CalculatingWithCarry(a,b); +} + +/* +the result: + +Simple calculating +a = 123456 +b = 98767878 +a + b = 98891334 +a - b = -98644422 +a * b = 12193487146368 +a / b = 0 +Calculating with carry +a = 9223372036854775807 +b = 10 +a + b = (carry: the result is too big) -9223372036854775799 +a - b = 9223372036854775797 +a * b = (carry: the result is too big) +a / b = 922337203685477580 +*/ diff --git a/samples/uint.cpp b/samples/uint.cpp new file mode 100644 index 0000000..0104f9e --- /dev/null +++ b/samples/uint.cpp @@ -0,0 +1,91 @@ +#include +#include + + +void SimpleCalculating(const ttmath::UInt<2> & a, const ttmath::UInt<2> & b) +{ + std::cout << "Simple calculating" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + std::cout << "a + b = " << a+b << std::endl; + std::cout << "a - b = " << a-b << std::endl; + std::cout << "a * b = " << a*b << std::endl; + std::cout << "a / b = " << a/b << std::endl; +} + + +void CalculatingWithCarry(const ttmath::UInt<2> & a, const ttmath::UInt<2> & b) +{ +ttmath::UInt<2> atemp; + + std::cout << "Calculating with carry" << std::endl; + std::cout << "a = " << a << std::endl; + std::cout << "b = " << b << std::endl; + + atemp = a; + if( !atemp.Add(b) ) + std::cout << "a + b = " << atemp << std::endl; + else + // if there was a carry then atemp.Add(...) would have returned 1 + std::cout << "a + b = (carry: the result is too big) " << atemp << std::endl; + + atemp = a; + if( !atemp.Sub(b) ) + std::cout << "a - b = " << atemp << std::endl; + else + std::cout << "a - b = (carry: 'a' was smaller than 'b') " << atemp << std::endl; + + atemp = a; + if( !atemp.Mul(b) ) + std::cout << "a * b = " << atemp << std::endl; + else + std::cout << "a * b = (carry: the result is too big) " << std::endl; + // it have no sense to print 'atemp' (it's undefined) + + atemp = a; + if( !atemp.Div(b) ) + std::cout << "a / b = " << atemp << std::endl; + else + std::cout << "a / b = (division by zero) " << std::endl; + +} + +int main() +{ +// on 32bit platforms: 'a' and 'b' have 2-words (two 32bit words) +// in other words a,b are from <0, 2^64 - 1> +ttmath::UInt<2> a,b; + + // conversion from 'const char *' + a = "123456"; + b = "9876"; + + SimpleCalculating(a,b); + + // 'a' will have the max value which can be held in this type + a.SetMaxValue(); + + // conversion from 'int' + b = 5; + + CalculatingWithCarry(a,b); +} + +/* +the result: + +Simple calculating +a = 123456 +b = 9876 +a + b = 133332 +a - b = 113580 +a * b = 1219251456 +a / b = 12 +Calculating with carry +a = 18446744073709551615 +b = 5 +a + b = (carry: the result is too big) 4 +a - b = 18446744073709551610 +a * b = (carry: the result is too big) +a / b = 3689348814741910323 +*/ diff --git a/ttmath/ttmathint.h b/ttmath/ttmathint.h index 07363fc..c250d27 100644 --- a/ttmath/ttmathint.h +++ b/ttmath/ttmathint.h @@ -52,9 +52,11 @@ namespace ttmath /*! - \brief it implements the big integer value with the sign + \brief it implements a big integer value with a sign - value_size - how many bytes specify our value (value_size = 1 -> 4 bytes -> 32 bits) + value_size - how many bytes specify our value + on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits + on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits value_size = 1,2,3,4,5,6.... */ template @@ -161,7 +163,7 @@ public: /*! - it returns the absolute value + it sets an absolute value it can return carry (1) (look on ChangeSign() for details) */ @@ -182,8 +184,30 @@ public: * */ +private: + + uint CorrectCarryAfterAdding(bool p1_is_sign, bool p2_is_sign) + { + if( !p1_is_sign && !p2_is_sign ) + { + if( UInt::IsTheHighestBitSet() ) + return 1; + } + + if( p1_is_sign && p2_is_sign ) + { + if( ! UInt::IsTheHighestBitSet() ) + return 1; + } + + return 0; + } + + +public: + /*! - this method adds two value with sign and returns carry + this method adds two value with a sign and returns carry we're using methods from the base class because values are stored with U2 we must only make the carry correction @@ -202,13 +226,55 @@ public: UInt::Add(ss2); - if( !p1_is_sign && !p2_is_sign ) + return CorrectCarryAfterAdding(p1_is_sign, p2_is_sign); + } + + + /*! + this method adds one *unsigned* word (at a specific position) + and returns a carry (if it was) + + look at a description in UInt<>::AddInt(...) + */ + uint AddInt(uint value, uint index = 0) + { + bool p1_is_sign = IsSign(); + + UInt::AddInt(value, index); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + + + /*! + this method adds two *unsigned* words to the existing value + and these words begin on the 'index' position + + index should be equal or smaller than value_size-2 (index <= value_size-2) + x1 - lower word, x2 - higher word + + look at a description in UInt<>::AddTwoInts(...) + */ + uint AddTwoInts(uint x2, uint x1, uint index) + { + bool p1_is_sign = IsSign(); + + UInt::AddTwoInts(x2, x1, index); + + return CorrectCarryAfterAdding(p1_is_sign, false); + } + +private: + + uint CorrectCarryAfterSubtracting(bool p1_is_sign, bool p2_is_sign) + { + if( !p1_is_sign && p2_is_sign ) { if( UInt::IsTheHighestBitSet() ) return 1; } - if( p1_is_sign && p2_is_sign ) + if( p1_is_sign && !p2_is_sign ) { if( ! UInt::IsTheHighestBitSet() ) return 1; @@ -217,9 +283,10 @@ public: return 0; } +public: /*! - this method subtracts two values with the sign + this method subtracts two values with a sign we don't use the previous Add because the method ChangeSign can sometimes return carry @@ -238,19 +305,21 @@ public: UInt::Sub(ss2); - if( !p1_is_sign && p2_is_sign ) - { - if( UInt::IsTheHighestBitSet() ) - return 1; - } + return CorrectCarryAfterSubtracting(p1_is_sign, p2_is_sign); + } - if( p1_is_sign && !p2_is_sign ) - { - if( ! UInt::IsTheHighestBitSet() ) - return 1; - } - return 0; + /*! + this method subtracts one *unsigned* word (at a specific position) + and returns a carry (if it was) + */ + uint SubInt(uint value, uint index = 0) + { + bool p1_is_sign = IsSign(); + + UInt::SubInt(value, index); + + return CorrectCarryAfterSubtracting(p1_is_sign, false); } @@ -259,11 +328,11 @@ public: */ uint AddOne() { - Int temp; + bool p1_is_sign = IsSign(); - temp.SetOne(); + UInt::AddOne(); - return Add(temp); + return CorrectCarryAfterAdding(p1_is_sign, false); } @@ -272,11 +341,11 @@ public: */ uint SubOne() { - Int temp; + bool p1_is_sign = IsSign(); - temp.SetOne(); + UInt::SubOne(); - return Sub(temp); + return CorrectCarryAfterSubtracting(p1_is_sign, false); } @@ -308,11 +377,11 @@ public: /* - we have to examine the sign of result now + we have to examine the sign of the result now but if the result is with the sign then: 1. if the signs were the same that means the result is too big (the result must be without a sign) - 2. if the signs were diffrent that means if the result + 2. if the signs were different that means if the result is different from that one which has been returned from SetMinValue() that is carry (result too big) but if the result is equal SetMinValue() there'll be ok (and the next SetSign will has no effect because @@ -324,7 +393,7 @@ public: /* there can be one case where signs are different and the result will be equal the value from SetMinValue() - (there is ok situation) + (this situation is ok) */ if( ss1_is_sign != ss2_is_sign ) { @@ -356,20 +425,21 @@ public: /*! division this = this / ss2 - function returns the remainder + returned values: + 0 - ok + 1 - division by zero - for example: (result means this) + for example: (result means 'this') 20 / 3 --> result: 6 remainder: 2 -20 / 3 --> result: -6 remainder: -2 20 / -3 --> result: -6 remainder: 2 -20 / -3 --> result: 6 remainder: -2 - in other words: this(old) = result * this(new) + remainder + in other words: this(old) = ss2 * this(new)(result) + remainder */ - Int Div(Int ss2) + uint Div(Int ss2, Int * remainder = 0) { bool ss1_is_sign, ss2_is_sign; - Int remainder; ss1_is_sign = IsSign(); ss2_is_sign = ss2.IsSign(); @@ -380,17 +450,21 @@ public: Abs(); ss2.Abs(); - remainder = UInt::Div(ss2); + uint c = UInt::Div(ss2, remainder); if( ss1_is_sign != ss2_is_sign ) SetSign(); - if( ss1_is_sign ) - remainder.SetSign(); + if( ss1_is_sign && remainder ) + remainder->SetSign(); - return remainder; + return c; } + uint Div(const Int & ss2, Int & remainder) + { + return Div(ss2, &remainder); + } @@ -465,7 +539,7 @@ public: /*! - this method convert an sint type to this class + this method converts an sint type to this class */ Int & operator=(sint i) { @@ -481,7 +555,7 @@ public: /*! - constructor for converting an uint to this class + a constructor for converting an uint to this class */ Int(sint i) { @@ -490,7 +564,7 @@ public: /*! - constructor for converting string to this class (with base=10) + a constructor for converting string to this class (with base=10) */ Int(const char * s) { @@ -499,7 +573,7 @@ public: /*! - constructor for converting string to this class (with base=10) + a constructor for converting string to this class (with base=10) */ Int(const std::string & s) { @@ -508,7 +582,7 @@ public: /*! - default constructor + a default constructor we don't clear table etc. */ @@ -518,7 +592,7 @@ public: /*! - the copying constructor + a copy constructor */ template Int(const Int & u) : UInt::size(value_size) @@ -537,7 +611,7 @@ public: } /*! - this method returns the lowest value from table with the sign + this method returns the lowest value from table with a sign we must be sure when we using this method whether the value will hold in an sint type or not (the rest value from table must be zero or -1) @@ -685,10 +759,6 @@ public: return a1 < a2; -// comparison as int -// if( int(UInt::table[i]) != int(l.table[i]) ) -// return int(UInt::table[i]) < int(l.table[i]); - for(--i ; i>=0 ; --i) { if( UInt::table[i] != l.table[i] ) @@ -704,7 +774,6 @@ public: bool operator>(const Int & l) const { sint i=value_size-1; - sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); @@ -712,9 +781,6 @@ public: if( a1 != a2 ) return a1 > a2; - // comparison as int -// if( int(UInt::table[i]) != int(l.table[i]) ) -// return int(UInt::table[i]) > int(l.table[i]); for(--i ; i>=0 ; --i) { @@ -731,7 +797,6 @@ public: bool operator<=(const Int & l) const { sint i=value_size-1; - sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); @@ -739,9 +804,6 @@ public: if( a1 != a2 ) return a1 < a2; - // comparison as int -// if( int(UInt::table[i]) != int(l.table[i]) ) -// return int(UInt::table[i]) < int(l.table[i]); for(--i ; i>=0 ; --i) { @@ -758,7 +820,6 @@ public: bool operator>=(const Int & l) const { sint i=value_size-1; - sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); @@ -766,9 +827,6 @@ public: if( a1 != a2 ) return a1 > a2; - // comparison as int -// if( int(UInt::table[i]) != int(l.table[i]) ) -// return int(UInt::table[i]) > int(l.table[i]); for(--i ; i>=0 ; --i) { @@ -880,7 +938,9 @@ public: Int operator%(const Int & p2) const { Int temp(*this); - Int remainder = temp.Div( p2 ); + Int remainder; + + temp.Div(p2, remainder); return remainder; } @@ -889,7 +949,9 @@ public: Int & operator%=(const Int & p2) { Int temp(*this); - Int remainder = temp.Div( p2 ); + Int remainder; + + temp.Div(p2, remainder); operator=(remainder); @@ -898,7 +960,7 @@ public: /*! - Prefix operator e.g ++variable + Prefix operator e.g. ++variable */ UInt & operator++() { @@ -907,8 +969,9 @@ public: return *this; } + /*! - Postfix operator e.g variable++ + Postfix operator e.g. variable++ */ UInt operator++(int) { @@ -922,7 +985,7 @@ public: UInt & operator--() { - AddOne(); + SubOne(); return *this; } diff --git a/ttmath/ttmathuint.h b/ttmath/ttmathuint.h index f234537..ab75fe0 100644 --- a/ttmath/ttmathuint.h +++ b/ttmath/ttmathuint.h @@ -54,9 +54,11 @@ namespace ttmath { /*! - \brief it implements the big integer value without a sign + \brief it implements a big integer value without a sign - value_size - how many bytes specify our value (value_size = 1 -> 4 bytes -> 32 bits) + value_size - how many bytes specify our value + on 32bit platforms: value_size=1 -> 4 bytes -> 32 bits + on 64bit platforms: value_size=1 -> 8 bytes -> 64 bits value_size = 1,2,3,4,5,6.... */ template @@ -443,7 +445,7 @@ 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 AddTwoInts(uint index, uint x2, uint x1) + uint AddTwoInts(uint x2, uint x1, uint index) { register uint b = value_size; register uint * p1 = table; @@ -1370,7 +1372,7 @@ public: if( x1 <= value_size - 2 ) { - if( AddTwoInts(x1,r2,r1) ) + if( AddTwoInts(r2,r1,x1) ) return 1; } else @@ -1549,7 +1551,7 @@ public: for(uint x2=x2start ; x2 & u) { @@ -2608,7 +2610,7 @@ public: /*! - the destructor + a destructor */ virtual ~UInt() { @@ -3010,7 +3012,7 @@ public: UInt & operator--() { - AddOne(); + SubOne(); return *this; } @@ -3082,7 +3084,7 @@ public: uint Add(const UInt & ss2, uint c=0); uint AddInt(uint value, uint index = 0); - uint AddTwoInts(uint index, uint x2, uint x1); + uint AddTwoInts(uint x2, uint x1, uint index); uint Sub(const UInt & ss2, uint c=0); uint SubInt(uint value, uint index = 0); uint Rcl(uint c=0); diff --git a/ttmath/ttmathuint64.h b/ttmath/ttmathuint64.h index d66e7f9..664ed9f 100644 --- a/ttmath/ttmathuint64.h +++ b/ttmath/ttmathuint64.h @@ -262,7 +262,7 @@ namespace ttmath this carry would be passed to the table[3] etc.) */ template - uint UInt::AddTwoInts(uint index, uint x2, uint x1) + uint UInt::AddTwoInts(uint x2, uint x1, uint index) { register uint b = value_size; register uint * p1 = table;