/* * This file is a part of TTMath Bignum Library * and is distributed under the (new) BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2006-2009, 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. */ #ifndef headerfilettmathint #define headerfilettmathint /*! \file ttmathint.h \brief template class Int */ #include "ttmathuint.h" namespace ttmath { /*! \brief Int implements a big integer value with a sign 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 class Int : public UInt { public: /*! this method sets the max value which this class can hold (all bits will be one besides the last one) */ void SetMax() { UInt::SetMax(); UInt::table[value_size-1] = ~ TTMATH_UINT_HIGHEST_BIT; } /*! this method sets the min value which this class can hold (all bits will be zero besides the last one which is one) */ void SetMin() { UInt::SetZero(); UInt::table[value_size-1] = TTMATH_UINT_HIGHEST_BIT; } /*! this method sets -1 as the value (-1 is equal the max value in an unsigned type) */ void SetSignOne() { UInt::SetMax(); } /*! we change the sign of the value if it isn't possible to change the sign this method returns 1 else return 0 and changing the sign */ uint ChangeSign() { Int 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) 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 we don't change the value and we're using this fact somewhere in some methods (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) ) return 1; temp.SetZero(); temp.UInt::Sub(*this); operator=(temp); return 0; } /*! this method sets the sign e.g. 1 -> -1 -2 -> -2 from a positive value we make a negative value, if the value is negative we do nothing */ void SetSign() { if( IsSign() ) return; ChangeSign(); } /*! this method returns true if there's the sign (the highest bit will be converted to the bool) */ bool IsSign() const { return UInt::IsTheHighestBitSet(); } /*! it sets an absolute value it can return carry (1) (look on ChangeSign() for details) */ uint Abs() { if( !IsSign() ) return 0; return ChangeSign(); } /*! * * basic mathematic functions * */ 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 a sign and returns a carry we're using methods from the base class because values are stored with U2 we must only make the carry correction this = p1(=this) + p2 when p1>=0 i p2>=0 carry is set when the highest bit of value is set when p1<0 i p2<0 carry is set when the highest bit of value is clear when p1>=0 i p2<0 carry will never be set when p1<0 i p2>=0 carry will never be set */ uint Add(const Int & ss2) { bool p1_is_sign = IsSign(); bool p2_is_sign = ss2.IsSign(); UInt::Add(ss2); 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( ! UInt::IsTheHighestBitSet() ) return 1; } return 0; } public: /*! this method subtracts two values with a sign we don't use the previous Add because the method ChangeSign can sometimes return carry this = p1(=this) - p2 when p1>=0 i p2>=0 carry will never be set when p1<0 i p2<0 carry will never be set when p1>=0 i p2<0 carry is set when the highest bit of value is set when p1<0 i p2>=0 carry is set when the highest bit of value is clear */ uint Sub(const Int & ss2) { bool p1_is_sign = IsSign(); bool p2_is_sign = ss2.IsSign(); UInt::Sub(ss2); return CorrectCarryAfterSubtracting(p1_is_sign, p2_is_sign); } /*! 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); } /*! this method adds one to the value and returns carry */ uint AddOne() { bool p1_is_sign = IsSign(); UInt::AddOne(); return CorrectCarryAfterAdding(p1_is_sign, false); } /*! this method subtracts one from the value and returns carry */ uint SubOne() { bool p1_is_sign = IsSign(); UInt::SubOne(); return CorrectCarryAfterSubtracting(p1_is_sign, false); } /*! 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 ss2) { 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::Mul(ss2) ) return 1; /* 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 different that means if the result is different from that one which has been returned from SetMin() that is carry (result too big) but if the result is equal SetMin() there'll be ok (and the next SetSign will has no effect because the value is actually negative -- look at description of that case in ChangeSign()) */ 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 temp; temp.SetMin(); if( operator!=(temp) ) /* the result is too big */ return 1; } else { /* the result is too big */ return 1; } } if( ss1_is_sign != ss2_is_sign ) SetSign(); return 0; } /*! division this = this / ss2 returned values: 0 - ok 1 - division by zero 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) = ss2 * this(new)(result) + remainder */ uint Div(Int ss2, Int * remainder = 0) { bool ss1_is_sign, ss2_is_sign; ss1_is_sign = IsSign(); ss2_is_sign = ss2.IsSign(); /* we don't have to test the carry from Abs as well as in Mul */ Abs(); ss2.Abs(); uint c = UInt::Div(ss2, remainder); if( ss1_is_sign != ss2_is_sign ) SetSign(); if( ss1_is_sign && remainder ) remainder->SetSign(); return c; } uint Div(const Int & ss2, Int & remainder) { return Div(ss2, &remainder); } 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; } /*! * * convertion methods * */ private: /*! an auxiliary method for converting both from UInt and Int */ template uint FromUIntOrInt(const UInt & p, bool UInt_type) { uint min_size = (value_size < argument_size)? value_size : argument_size; uint i; for(i=0 ; i::table[i] = p.table[i]; if( value_size > argument_size ) { uint fill; if( UInt_type ) fill = 0; else fill = (p.table[argument_size-1] & TTMATH_UINT_HIGHEST_BIT)? TTMATH_UINT_MAX_VALUE : 0; // 'this' is longer than 'p' for( ; i::table[i] = fill; } else { uint test = (UInt::table[value_size-1] & TTMATH_UINT_HIGHEST_BIT)? TTMATH_UINT_MAX_VALUE : 0; if( UInt_type && test!=0 ) return 1; for( ; i type into this class this operation has mainly sense if the value from p can be held in this type it returns a carry if the value 'p' is too big */ template uint FromInt(const Int & p) { return FromUIntOrInt(p, false); } /*! this method converts the sint type into this class */ uint FromInt(sint value) { uint fill = ( value<0 ) ? TTMATH_UINT_MAX_VALUE : 0; for(uint i=1 ; i::table[i] = fill; UInt::table[0] = uint(value); // there'll never be a carry here return 0; } /*! this method converts UInt into this class */ template uint FromUInt(const UInt & p) { return FromUIntOrInt(p, true); } /*! this method converts the uint type into this class */ uint FromUInt(uint value) { for(uint i=1 ; i::table[i] = 0; UInt::table[0] = value; // there can be a carry here when the size of this value is equal one word // and the 'value' has the highest bit set if( value_size==1 && (value & TTMATH_UINT_HIGHEST_BIT)!=0 ) return 1; return 0; } // converting from Int /*! the default assignment operator */ Int & operator=(const Int & p) { FromInt(p); return *this; } /*! this operator converts an Int type to this class it doesn't return a carry */ template Int & operator=(const Int & p) { FromInt(p); return *this; } /*! this method converts the sint type to this class */ Int & operator=(sint i) { FromInt(i); return *this; } /*! a constructor for converting the uint to this class */ Int(sint i) { FromInt(i); } /*! a copy constructor */ Int(const Int & u) { FromInt(u); } /*! a constructor for copying from another types */ template Int(const Int & u) { // look that 'size' we still set as 'value_size' and not as u.value_size FromInt(u); } // converting from UInt /*! this operator converts an UInt type to this class it doesn't return a carry */ template Int & operator=(const UInt & p) { FromUInt(p); return *this; } /*! this method converts the Uint type to this class */ Int & operator=(uint i) { FromUInt(i); return *this; } /*! a constructor for converting the uint to this class */ Int(uint i) { FromUInt(i); } /*! a constructor for copying from another types */ template Int(const UInt & u) { // look that 'size' we still set as 'value_size' and not as u.value_size FromUInt(u); } // #ifdef TTMATH_PLATFORM64 /*! this method converts the signed int type to this class ***this operator is created only on a 64bit platform*** it takes one argument of 32bit */ Int & operator=(signed int i) { FromInt(sint(i)); return *this; } /*! a constructor for converting the signed int to this class ***this constructor is created only on a 64bit platform*** it takes one argument of 32bit */ Int(signed int i) { FromInt(sint(i)); } /*! this method converts the unsigned int type to this class ***this operator is created only on a 64bit platform*** it takes one argument of 32bit */ Int & operator=(unsigned int i) { FromUInt(uint(i)); return *this; } /*! a constructor for converting the unsigned int to this class ***this constructor is created only on a 64bit platform*** it takes one argument of 32bit */ Int(unsigned int i) { FromUInt(uint(i)); } #endif /*! a constructor for converting string to this class (with the base=10) */ Int(const char * s) { FromString(s); } /*! a constructor for converting a string to this class (with the base=10) */ Int(const std::string & s) { FromString( s.c_str() ); } /*! a default constructor we don't clear table etc. */ Int() { } /*! the destructor */ ~Int() { } /*! 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) */ sint ToInt() const { return sint( UInt::table[0] ); } /*! this method converts the value to a string with a base equal 'b' */ void ToString(std::string & result, uint b = 10) const { if( IsSign() ) { Int temp(*this); temp.Abs(); temp.UInt::ToString(result, b); result.insert(result.begin(), '-'); } else { UInt::ToString(result, b); } } /*! this method converts a string into its value it returns carry=1 if the value will be too big or an incorrect base 'b' is given string is ended with a non-digit value, for example: "-12" will be translated to -12 as well as: "- 12foo" will be translated to 12 too existing first white characters will be ommited (between '-' and a first digit can be white characters too) */ uint FromString(const char * s, uint b = 10) { bool is_sign = false; UInt::SkipWhiteCharacters(s); if( *s == '-' ) { is_sign = true; UInt::SkipWhiteCharacters(++s); } else if( *s == '+' ) { UInt::SkipWhiteCharacters(++s); } if( UInt::FromString(s,b) ) return 1; if( is_sign ) { Int mmin; mmin.SetMin(); /* the reference to mmin will be automatically converted to the reference to a UInt type (this value can be equal mmin -- look at a description in ChangeSign()) */ if( UInt::operator>( mmin ) ) return 1; ChangeSign(); } else { Int mmax; mmax.SetMax(); if( UInt::operator>( mmax ) ) return 1; } return 0; } /*! this method converts a string into its value it returns carry=1 if the value will be too big or an incorrect base 'b' is given */ uint FromString(const std::string & s, uint b = 10) { return FromString( s.c_str() ); } /*! this operator converts a string into its value (with base = 10) */ Int & operator=(const char * s) { FromString(s); return *this; } /*! this operator converts a string into its value (with base = 10) */ Int & operator=(const std::string & s) { FromString( s.c_str() ); return *this; } /*! * * methods for comparing * * */ bool operator==(const Int & l) const { return UInt::operator==(l); } bool operator!=(const Int & l) const { return UInt::operator!=(l); } bool operator<(const Int & l) const { sint i=value_size-1; sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 < a2; for(--i ; i>=0 ; --i) { if( UInt::table[i] != l.table[i] ) // comparison as unsigned int return UInt::table[i] < l.table[i]; } // they're equal return false; } bool operator>(const Int & l) const { sint i=value_size-1; sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 > a2; for(--i ; i>=0 ; --i) { if( UInt::table[i] != l.table[i] ) // comparison as unsigned int return UInt::table[i] > l.table[i]; } // they're equal return false; } bool operator<=(const Int & l) const { sint i=value_size-1; sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 < a2; for(--i ; i>=0 ; --i) { if( UInt::table[i] != l.table[i] ) // comparison as unsigned int return UInt::table[i] < l.table[i]; } // they're equal return true; } bool operator>=(const Int & l) const { sint i=value_size-1; sint a1 = sint(UInt::table[i]); sint a2 = sint(l.table[i]); if( a1 != a2 ) return a1 > a2; for(--i ; i>=0 ; --i) { if( UInt::table[i] != l.table[i] ) // comparison as unsigned int return UInt::table[i] > l.table[i]; } // they're equal return true; } /*! * * standard mathematical operators * */ /*! an operator for changing the sign it's not changing 'this' but the changed value will be returned */ Int operator-() const { Int temp(*this); temp.ChangeSign(); return temp; } Int operator-(const Int & p2) const { Int temp(*this); temp.Sub(p2); return temp; } Int & operator-=(const Int & p2) { Sub(p2); return *this; } Int operator+(const Int & p2) const { Int temp(*this); temp.Add(p2); return temp; } Int & operator+=(const Int & p2) { Add(p2); return *this; } Int operator*(const Int & p2) const { Int temp(*this); temp.Mul(p2); return temp; } Int & operator*=(const Int & p2) { Mul(p2); return *this; } Int operator/(const Int & p2) const { Int temp(*this); temp.Div(p2); return temp; } Int & operator/=(const Int & p2) { Div(p2); return *this; } Int operator%(const Int & p2) const { Int temp(*this); Int remainder; temp.Div(p2, remainder); return remainder; } Int & operator%=(const Int & p2) { Int temp(*this); Int remainder; temp.Div(p2, remainder); operator=(remainder); return *this; } /*! Prefix operator e.g. ++variable */ UInt & operator++() { AddOne(); return *this; } /*! Postfix operator e.g. variable++ */ UInt operator++(int) { UInt temp( *this ); AddOne(); return temp; } UInt & operator--() { SubOne(); return *this; } UInt operator--(int) { UInt temp( *this ); SubOne(); return temp; } /*! * * input/output operators for standard streams * */ friend std::ostream & operator<<(std::ostream & s, const Int & l) { std::string ss; l.ToString(ss); s << ss; return s; } friend std::istream & operator>>(std::istream & s, Int & l) { std::string ss; // char for operator>> unsigned char z; // operator>> omits white characters if they're set for ommiting s >> z; if( z=='-' || z=='+' ) { ss += z; s >> z; // we're reading a next character (white characters can be ommited) } // we're reading only digits (base=10) while( s.good() && UInt::CharToDigit(z, 10)>=0 ) { ss += z; z = s.get(); } // we're leaving the last readed character // (it's not belonging to the value) s.unget(); l.FromString(ss); return s; } }; } // namespace #endif