/* * 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 headerfilettmathuint #define headerfilettmathuint /*! \file ttmathuint.h \brief template class UInt */ #include #include #include "ttmathtypes.h" /*! \brief a namespace for the TTMath library */ namespace ttmath { /*! \brief UInt implements a big integer value without 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 UInt { public: /*! buffer for the integer value table[0] - the lowest word of the value */ uint table[value_size]; /*! this method is only for debugging purposes or when we want to make a table of a variable (constant) in ttmathbig.h it prints the table in a nice form of several columns */ void PrintTable(std::ostream & output) const { // how many columns there'll be const int columns = 8; int c = 1; for(int i=value_size-1 ; i>=0 ; --i) { output << "0x" << std::setfill('0'); #ifdef TTMATH_PLATFORM32 output << std::setw(8); #else output << std::setw(16); #endif output << std::hex << table[i]; if( i>0 ) { output << ", "; if( ++c > columns ) { output << std::endl; c = 1; } } } output << std::dec << std::endl; } /*! this method returns the size of the table */ uint Size() const { return value_size; } /*! this method sets zero */ void SetZero() { // in the future here can be 'memset' for(uint i=0 ; i=0 && temp_table_index=0 ; --i) table[i] = 0; } /*! * * basic mathematic functions * */ /*! adding ss2 to the this and adding carry if it's defined (this = this + ss2 + c) c must be zero or one (might be a bigger value than 1) function returns carry (1) (if it has been) */ uint Add(const UInt & ss2, uint c=0) { register uint b = value_size; 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__ // this part might be compiled with for example visual c __asm { push eax push ebx push ecx push edx push esi mov ecx,[b] mov ebx,[p1] mov esi,[p2] xor eax,eax // eax=0 mov edx,eax // edx=0 sub eax,[c] // CF=c p: mov eax,[esi+edx*4] adc [ebx+edx*4],eax inc edx dec ecx jnz p setc al movzx edx, al mov [c], edx pop esi pop edx pop ecx pop ebx pop eax } #endif #ifdef __GNUC__ // this part should be compiled with gcc __asm__ __volatile__( "push %%ecx \n" "xorl %%eax, %%eax \n" "movl %%eax, %%edx \n" "subl %%edi, %%eax \n" "1: \n" "movl (%%esi,%%edx,4),%%eax \n" "adcl %%eax, (%%ebx,%%edx,4) \n" "incl %%edx \n" "decl %%ecx \n" "jnz 1b \n" "setc %%al \n" "movzx %%al,%%edx \n" "pop %%ecx \n" : "=d" (c) : "D" (c), "c" (b), "b" (p1), "S" (p2) : "%eax", "cc", "memory" ); #endif return c; } /*! adding one word (at a specific position) and returning a carry (if it has been) e.g. if we've got (value_size=3): table[0] = 10; table[1] = 30; table[2] = 5; and we call: AddInt(2,1) then it'll be: table[0] = 10; table[1] = 30 + 2; table[2] = 5; of course if there was a carry from table[2] it would be returned */ uint AddInt(uint value, uint index = 0) { register uint b = value_size; register uint * p1 = table; register uint c; TTMATH_ASSERT( index < value_size ) #ifndef __GNUC__ __asm { push eax push ebx push ecx push edx mov ecx, [b] sub ecx, [index] mov edx, [index] mov ebx, [p1] mov eax, [value] p: add [ebx+edx*4], eax jnc end mov eax, 1 inc edx dec ecx jnz p end: setc al movzx edx, al mov [c], edx pop edx pop ecx pop ebx pop eax } #endif #ifdef __GNUC__ __asm__ __volatile__( "push %%eax \n" "push %%ecx \n" "subl %%edx, %%ecx \n" "1: \n" "addl %%eax, (%%ebx,%%edx,4) \n" "jnc 2f \n" "movl $1, %%eax \n" "incl %%edx \n" "decl %%ecx \n" "jnz 1b \n" "2: \n" "setc %%al \n" "movzx %%al, %%edx \n" "pop %%ecx \n" "pop %%eax \n" : "=d" (c) : "a" (value), "c" (b), "0" (index), "b" (p1) : "cc", "memory" ); #endif return c; } /*! adding only two unsigned words to the existing value and these words begin on the 'index' position (it's used in the multiplication algorithm 2) index should be equal or smaller than value_size-2 (index <= value_size-2) x1 - lower word, x2 - higher word for example if we've got value_size equal 4 and: table[0] = 3 table[1] = 4 table[2] = 5 table[3] = 6 then let x1 = 10 x2 = 20 and index = 1 the result of this method will be: table[0] = 3 table[1] = 4 + x1 = 14 table[2] = 5 + x2 = 25 table[3] = 6 and no carry at the end of table[3] (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 x2, uint x1, uint index) { register uint b = value_size; register uint * p1 = table; register uint c; TTMATH_ASSERT( index < value_size - 1 ) #ifndef __GNUC__ __asm { push eax push ebx push ecx push edx mov ecx, [b] sub ecx, [index] mov ebx, [p1] mov edx, [index] mov eax, [x1] add [ebx+edx*4], eax inc edx dec ecx mov eax, [x2] p: adc [ebx+edx*4], eax jnc end mov eax, 0 inc edx dec ecx jnz p end: setc al movzx edx, al mov [c], edx pop edx pop ecx pop ebx pop eax } #endif #ifdef __GNUC__ __asm__ __volatile__( "push %%ecx \n" "push %%edx \n" "subl %%edx, %%ecx \n" "addl %%esi, (%%ebx,%%edx,4) \n" "incl %%edx \n" "decl %%ecx \n" "1: \n" "adcl %%eax, (%%ebx,%%edx,4) \n" "jnc 2f \n" "mov $0, %%eax \n" "incl %%edx \n" "decl %%ecx \n" "jnz 1b \n" "2: \n" "setc %%al \n" "movzx %%al, %%eax \n" "pop %%edx \n" "pop %%ecx \n" : "=a" (c) : "c" (b), "d" (index), "b" (p1), "S" (x1), "0" (x2) : "cc", "memory" ); #endif return c; } /*! subtracting ss2 from the 'this' and subtracting carry if it has been defined (this = this - ss2 - c) c must be zero or one (might be a bigger value than 1) function returns carry (1) (if it has been) */ uint Sub(const UInt & ss2, uint c=0) { register uint b = value_size; 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__ __asm { push eax push ebx push ecx push edx push esi mov ecx,[b] mov ebx,[p1] mov esi,[p2] xor eax, eax mov edx, eax sub eax, [c] p: mov eax, [esi+edx*4] sbb [ebx+edx*4], eax inc edx dec ecx jnz p setc al movzx edx, al mov [c], edx pop esi pop edx pop ecx pop ebx pop eax } #endif #ifdef __GNUC__ __asm__ __volatile__( "push %%ecx \n" "xorl %%eax, %%eax \n" "movl %%eax, %%edx \n" "subl %%edi, %%eax \n" "1: \n" "movl (%%esi,%%edx,4),%%eax \n" "sbbl %%eax, (%%ebx,%%edx,4) \n" "incl %%edx \n" "decl %%ecx \n" "jnz 1b \n" "setc %%al \n" "movzx %%al,%%edx \n" "pop %%ecx \n" : "=d" (c) : "D" (c), "c" (b), "b" (p1), "S" (p2) : "%eax", "cc", "memory" ); #endif return c; } /*! this method subtracts one word (at a specific position) and returns a carry (if it was) e.g. if we've got (value_size=3): table[0] = 10; table[1] = 30; table[2] = 5; and we call: SubInt(2,1) then it'll be: table[0] = 10; table[1] = 30 - 2; table[2] = 5; of course if there was a carry from table[3] it would be returned */ uint SubInt(uint value, uint index = 0) { register uint b = value_size; register uint * p1 = table; register uint c; TTMATH_ASSERT( index < value_size ) #ifndef __GNUC__ __asm { push eax push ebx push ecx push edx mov ecx, [b] sub ecx, [index] mov edx, [index] mov ebx, [p1] mov eax, [value] p: sub [ebx+edx*4], eax jnc end mov eax, 1 inc edx dec ecx jnz p end: setc al movzx edx, al mov [c], edx pop edx pop ecx pop ebx pop eax } #endif #ifdef __GNUC__ __asm__ __volatile__( "push %%eax \n" "push %%ecx \n" "subl %%edx, %%ecx \n" "1: \n" "subl %%eax, (%%ebx,%%edx,4) \n" "jnc 2f \n" "movl $1, %%eax \n" "incl %%edx \n" "decl %%ecx \n" "jnz 1b \n" "2: \n" "setc %%al \n" "movzx %%al, %%edx \n" "pop %%ecx \n" "pop %%eax \n" : "=d" (c) : "a" (value), "c" (b), "0" (index), "b" (p1) : "cc", "memory" ); #endif return c; } #endif /*! this method adds one to the existing value */ uint AddOne() { return AddInt(1); } /*! this method subtracts one from the existing value */ uint SubOne() { return SubInt(1); } private: #ifdef TTMATH_PLATFORM32 /*! this method moves all bits into the left hand side return value <- this <- c the lowest *bit* will be held the 'c' and the state of one additional bit (on the left hand side) will be returned for example: let this is 001010000 after Rcl2_one(1) there'll be 010100001 and Rcl2_one returns 0 */ uint Rcl2_one(uint c) { register sint b = value_size; register uint * p1 = table; #ifndef __GNUC__ __asm { push ebx push ecx push edx mov ebx, [p1] xor edx, edx mov ecx, edx sub ecx, [c] mov ecx, [b] p: rcl dword ptr [ebx+edx*4], 1 inc edx dec ecx jnz p setc dl movzx edx, dl mov [c], edx pop edx pop ecx pop ebx } #endif #ifdef __GNUC__ __asm__ __volatile__( "push %%edx \n" "push %%ecx \n" "xorl %%edx, %%edx \n" // edx=0 "neg %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 "1: \n" "rcll $1, (%%ebx, %%edx, 4) \n" "incl %%edx \n" "decl %%ecx \n" "jnz 1b \n" "setc %%al \n" "movzx %%al, %%eax \n" "pop %%ecx \n" "pop %%edx \n" : "=a" (c) : "0" (c), "c" (b), "b" (p1) : "cc", "memory" ); #endif return c; } /*! this method moves all bits into the right hand side c -> this -> return value the highest *bit* will be held the 'c' and the state of one additional bit (on the right hand side) will be returned for example: let this is 000000010 after Rcr2_one(1) there'll be 100000001 and Rcr2_one returns 0 */ uint Rcr2_one(uint c) { register sint b = value_size; register uint * p1 = table; #ifndef __GNUC__ __asm { push ebx push ecx mov ebx, [p1] xor ecx, ecx sub ecx, [c] mov ecx, [b] p: rcr dword ptr [ebx+ecx*4-4], 1 dec ecx jnz p setc cl movzx ecx, cl mov [c], ecx pop ecx pop ebx } #endif #ifdef __GNUC__ __asm__ __volatile__( "push %%ecx \n" "neg %%eax \n" // CF=1 if eax!=0 , CF=0 if eax==0 "1: \n" "rcrl $1, -4(%%ebx, %%ecx, 4) \n" "decl %%ecx \n" "jnz 1b \n" "setc %%al \n" "movzx %%al, %%eax \n" "pop %%ecx \n" : "=a" (c) : "0" (c), "c" (b), "b" (p1) : "cc", "memory" ); #endif return c; } /*! this method moves all bits into the left hand side return value <- this <- c the lowest *bits* will be held the 'c' and the state of one additional bit (on the left hand side) will be returned for example: let this is 001010000 after Rcl2(3, 1) there'll be 010000111 and Rcl2 returns 1 */ uint Rcl2(uint bits, uint c) { TTMATH_ASSERT( bits>0 && bits this -> return value the highest *bits* will be held the 'c' and the state of one additional bit (on the right hand side) will be returned for example: let this is 000000010 after Rcr2(2, 1) there'll be 110000000 and Rcr2 returns 1 */ uint Rcr2(uint bits, uint c) { TTMATH_ASSERT( bits>0 && bits= value_size ) { if( all_words == value_size && rest_bits == 0 ) last_c = table[0] & 1; // else: last_c is default set to 0 // clearing for(uint i = 0 ; i 0 ) { // 0 < all_words < value_size sint first, second; last_c = table[value_size - all_words] & 1; // all_words is greater than 0 // copying the first part of the value for(first = value_size-1, second=first-all_words ; second>=0 ; --first, --second) table[first] = table[second]; // setting the rest to 'c' for( ; first>=0 ; --first ) table[first] = mask; } } public: /*! moving all bits into the left side 'bits' times return value <- this <- C bits is from a range of <0, man * TTMATH_BITS_PER_UINT> or it can be even bigger then all bits will be set to 'c' the value c will be set into the lowest bits and the method returns state of the last moved bit */ uint Rcl(uint bits, uint c=0) { uint last_c = 0; uint rest_bits = bits; if( bits == 0 ) return 0; if( bits >= TTMATH_BITS_PER_UINT ) RclMoveAllWords(rest_bits, last_c, bits, c); if( rest_bits == 0 ) return last_c; // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now if( rest_bits == 1 ) { last_c = Rcl2_one(c); } else if( rest_bits == 2 ) { // performance tests showed that for rest_bits==2 it's better to use Rcl2_one twice instead of Rcl2(2,c) Rcl2_one(c); last_c = Rcl2_one(c); } else { last_c = Rcl2(rest_bits, c); } return last_c; } private: /*! an auxiliary method for moving bits into the right hand side this method moves only words */ void RcrMoveAllWords(uint & rest_bits, uint & last_c, uint bits, uint c) { rest_bits = bits % TTMATH_BITS_PER_UINT; uint all_words = bits / TTMATH_BITS_PER_UINT; uint mask = ( c ) ? TTMATH_UINT_MAX_VALUE : 0; if( all_words >= value_size ) { if( all_words == value_size && rest_bits == 0 ) last_c = (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; // else: last_c is default set to 0 // clearing for(uint i = 0 ; i 0 ) { // 0 < all_words < value_size uint first, second; last_c = (table[all_words - 1] & TTMATH_UINT_HIGHEST_BIT) ? 1 : 0; // all_words is > 0 // copying the first part of the value for(first=0, second=all_words ; second this -> return value bits is from a range of <0, man * TTMATH_BITS_PER_UINT> or it can be even bigger then all bits will be set to 'c' the value c will be set into the highest bits and the method returns state of the last moved bit */ uint Rcr(uint bits, uint c=0) { uint last_c = 0; uint rest_bits = bits; if( bits == 0 ) return 0; if( bits >= TTMATH_BITS_PER_UINT ) RcrMoveAllWords(rest_bits, last_c, bits, c); if( rest_bits == 0 ) return last_c; // rest_bits is from 1 to TTMATH_BITS_PER_UINT-1 now if( rest_bits == 1 ) { last_c = Rcr2_one(c); } else if( rest_bits == 2 ) { // performance tests showed that for rest_bits==2 it's better to use Rcr2_one twice instead of Rcr2(2,c) Rcr2_one(c); last_c = Rcr2_one(c); } else { last_c = Rcr2(rest_bits, c); } return last_c; } /*! this method moves all bits into the left side (it returns value how many bits have been moved) */ uint CompensationToLeft() { uint moving = 0; // a - index a last word which is different from zero sint a; for(a=value_size-1 ; a>=0 && table[a]==0 ; --a); if( a < 0 ) { // there's a value zero return moving; } if( a != value_size-1 ) { moving += ( value_size-1 - a ) * TTMATH_BITS_PER_UINT; // moving all words sint i; for(i=value_size-1 ; a>=0 ; --i, --a) table[i] = table[a]; // setting the rest word to zero for(; i>=0 ; --i) table[i] = 0; } uint moving2 = FindLeadingBitInWord( table[value_size-1] ); // moving2 is different from -1 because the value table[value_size-1] // is not zero moving2 = TTMATH_BITS_PER_UINT - moving2 - 1; Rcl(moving2); return moving + moving2; } #ifdef TTMATH_PLATFORM32 /* this method returns the number of the highest set bit in one 32-bit word if the 'x' is zero this method returns '-1' */ static sint FindLeadingBitInWord(uint x) { register sint result; #ifndef __GNUC__ __asm { push eax push edx mov edx,-1 bsr eax,[x] cmovz eax,edx mov [result], eax pop edx pop eax } #endif #ifdef __GNUC__ __asm__ __volatile__( "bsrl %1, %0 \n" "jnz 1f \n" "movl $-1, %0 \n" "1: \n" : "=R" (result) : "R" (x) : "cc" ); #endif return result; } #endif /*! this method looks for the highest set bit result: if 'this' is not zero: return value - true 'table_id' - the index of a word <0..value_size-1> 'index' - the index of this set bit in the word <0..31> if 'this' is zero: return value - false both 'table_id' and 'index' are zero */ bool FindLeadingBit(uint & table_id, uint & index) const { for(table_id=value_size-1 ; table_id!=0 && table[table_id]==0 ; --table_id); if( table_id==0 && table[table_id]==0 ) { // is zero index = 0; return false; } // table[table_id] != 0 index = FindLeadingBitInWord( table[table_id] ); return true; } #ifdef TTMATH_PLATFORM32 /*! this method sets a special bit in the 'value' and returns the last state of the bit (zero or one) bit is from <0,31> e.g. uint x = 100; uint bit = SetBitInWord(x, 3); now: x = 108 and bit = 0 */ 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, [v] mov ebx, [bit] bts eax, ebx mov [v], eax setc bl movzx ebx, bl mov [old_bit], ebx pop eax pop ebx } #endif #ifdef __GNUC__ __asm__ __volatile__( "btsl %%ebx, %%eax \n" "setc %%bl \n" "movzx %%bl, %%ebx \n" : "=a" (v), "=b" (old_bit) : "0" (v), "1" (bit) : "cc" ); #endif value = v; return old_bit; } #endif /*! setting the 'bit_index' bit bit_index bigger or equal zero */ uint GetBit(uint bit_index) const { 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; uint temp = table[index]; return SetBitInWord(temp, bit); } /*! 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); } /*! this method performs a bitwise operation AND */ void BitAnd(const UInt & ss2) { for(uint x=0 ; x & ss2) { for(uint x=0 ; x & ss2) { for(uint x=0 ; x for example: BitNot2(8) = BitNot2( 1000(bin) ) = 111(bin) = 7 */ void BitNot2() { uint table_id, index; if( FindLeadingBit(table_id, index) ) { for(uint x=0 ; x>= shift; table[table_id] ^= mask; } else table[0] = 1; } /*! * * Multiplication * * */ public: #ifdef TTMATH_PLATFORM32 /*! multiplication: result2:result1 = a * b result2 - higher word result1 - lower word of the result this method never returns a carry it is an auxiliary method for second version of the multiplication algorithm */ static void MulTwoWords(uint a, uint b, uint * result2, uint * result1) { /* we must use these temporary variables in order to inform the compilator that value pointed with result1 and result2 has changed this has no effect in visual studio but it's useful when using gcc and options like -Ox */ register uint result1_; register uint result2_; #ifndef __GNUC__ __asm { push eax push edx mov eax, [a] mul dword ptr [b] mov [result2_], edx mov [result1_], eax pop edx pop eax } #endif #ifdef __GNUC__ __asm__ __volatile__( "mull %%edx \n" : "=a" (result1_), "=d" (result2_) : "0" (a), "1" (b) : "cc" ); #endif *result1 = result1_; *result2 = result2_; } #endif /*! multiplication: this = this * ss2 it returns a carry if it has been */ uint MulInt(uint ss2) { uint r2,r1; UInt u( *this ); SetZero(); for(uint x1=0 ; x1 uint MulInt(uint ss2, UInt & result) { uint r2,r1; uint x1size=value_size; uint x1start=0; if( value_size >= result_size ) return 1; result.SetZero(); if( value_size > 2 ) { // if the value_size is smaller than or equal to 2 // there is no sense to set x1size and x1start to another values for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); if( x1size==0 ) return 0; for(x1start=0 ; x1start & ss2, uint algorithm = 2) { switch( algorithm ) { case 1: return Mul1(ss2); case 2: default: return Mul2(ss2); } } /*! the multiplication 'result' = 'this' * ss2 since the 'result' is twice bigger than 'this' and 'ss2' this method never returns a carry */ void MulBig(const UInt & ss2, UInt & result, uint algorithm = 2) { switch( algorithm ) { case 1: return Mul1Big(ss2, result); case 2: default: return Mul2Big(ss2, result); } } /*! the first version of the multiplication algorithm */ /*! multiplication: this = this * ss2 it returns carry if it has been */ uint Mul1(const UInt & ss2) { TTMATH_REFERENCE_ASSERT( ss2 ) UInt ss1( *this ); SetZero(); for(uint i=0; i < value_size*TTMATH_BITS_PER_UINT ; ++i) { if( Add(*this) ) return 1; if( ss1.Rcl(1) ) if( Add(ss2) ) return 1; } return 0; } /*! multiplication: result = this * ss2 result is twice bigger than 'this' and 'ss2' this method never returns carry */ void Mul1Big(const UInt & ss2_, UInt & result) { UInt ss2; uint i; // copying *this into result and ss2_ into ss2 for(i=0 ; i & ss2) { UInt result; uint i; Mul2Big(ss2, result); // copying result for(i=0 ; i & ss2, UInt & result) { uint r2,r1; uint x1size=value_size, x2size=value_size; uint x1start=0, x2start=0; result.SetZero(); if( value_size > 2 ) { // if the value_size is smaller than or equal to 2 // there is no sense to set x1size (and others) to another values for(x1size=value_size ; x1size>0 && table[x1size-1]==0 ; --x1size); for(x2size=value_size ; x2size>0 && ss2.table[x2size-1]==0 ; --x2size); if( x1size==0 || x2size==0 ) return; for(x1start=0 ; x1start dividend(*this); SetZero(); sint i; // i must be with a sign uint r = 0; // we're looking for the last word in ss1 for(i=value_size-1 ; i>0 && dividend.table[i]==0 ; --i); for( ; i>=0 ; --i) DivTwoWords(r, dividend.table[i], divisor, &table[i], &r); if( remainder ) *remainder = r; return 0; } uint DivInt(uint divisor, uint & remainder) { return DivInt(divisor, &remainder); } /*! division this = this / ss2 return values: 0 - ok 1 - division by zero 'this' will be the quotient 'remainder' - remainder */ uint Div( const UInt & divisor, UInt * remainder = 0, uint algorithm = 3) { switch( algorithm ) { case 1: return Div1(divisor, remainder); case 2: return Div2(divisor, remainder); case 3: default: return Div3(divisor, remainder); } } uint Div(const UInt & divisor, UInt & remainder, uint algorithm = 3) { return Div(divisor, &remainder, algorithm); } private: /*! return values: 0 - none has to be done 1 - division by zero 2 - division should be made */ uint Div_StandardTest( const UInt & v, uint & m, uint & n, UInt * remainder = 0) { switch( Div_CalculatingSize(v, m, n) ) { case 4: // 'this' is equal v if( remainder ) remainder->SetZero(); SetOne(); return 0; case 3: // 'this' is smaller than v if( remainder ) *remainder = *this; SetZero(); return 0; case 2: // 'this' is zero if( remainder ) remainder->SetZero(); SetZero(); return 0; case 1: // v is zero return 1; } return 2; } /*! return values: 0 - ok 'm' - is the index (from 0) of last non-zero word in table ('this') 'n' - is the index (from 0) of last non-zero word in v.table 1 - v is zero 2 - 'this' is zero 3 - 'this' is smaller than v 4 - 'this' is equal v if the return value is different than zero the 'm' and 'n' are undefined */ uint Div_CalculatingSize(const UInt & v, uint & m, uint & n) { for(n = value_size-1 ; n!=0 && v.table[n]==0 ; --n); if( n==0 && v.table[n]==0 ) return 1; for(m = value_size-1 ; m!=0 && table[m]==0 ; --m); if( m==0 && table[m]==0 ) return 2; if( m < n ) return 3; else if( m == n ) { uint i; for(i = n ; i!=0 && table[i]==v.table[i] ; --i); if( table[i] < v.table[i] ) return 3; else if (table[i] == v.table[i] ) return 4; } return 0; } public: /*! the first division's algorithm radix 2 */ uint Div1(const UInt & divisor, UInt * remainder = 0) { uint m,n, test; test = Div_StandardTest(divisor, m, n, remainder); if( test < 2 ) return test; if( !remainder ) { UInt rem; return Div1_Calculate(divisor, rem); } return Div1_Calculate(divisor, *remainder); } private: uint Div1_Calculate(const UInt & divisor, UInt & rest) { TTMATH_REFERENCE_ASSERT( divisor ) sint loop; sint c; rest.SetZero(); loop = value_size * TTMATH_BITS_PER_UINT; c = 0; div_a: c = Rcl(1, c); c = rest.Add(rest,c); c = rest.Sub(divisor,c); c = !c; if(!c) goto div_d; div_b: --loop; if(loop) goto div_a; c = Rcl(1, c); return 0; div_c: c = Rcl(1, c); c = rest.Add(rest,c); c = rest.Add(divisor); if(c) goto div_b; div_d: --loop; if(loop) goto div_c; c = Rcl(1, c); c = rest.Add(divisor); return 0; } public: /*! the second division algorithm return values: 0 - ok 1 - division by zero */ uint Div2(const UInt & divisor, UInt * remainder = 0) { TTMATH_REFERENCE_ASSERT( divisor ) uint bits_diff; uint status = Div2_Calculate(divisor, remainder, bits_diff); if( status < 2 ) return status; if( CmpBiggerEqual(divisor) ) { Div2(divisor, remainder); SetBit(bits_diff); } else { if( remainder ) *remainder = *this; SetZero(); SetBit(bits_diff); } return 0; } uint Div2(const UInt & divisor, UInt & remainder) { return Div2(divisor, &remainder); } private: /*! return values: 0 - we've calculated the division 1 - division by zero 2 - we have to still calculate */ uint Div2_Calculate(const UInt & divisor, UInt * remainder, uint & bits_diff) { uint table_id, index; uint divisor_table_id, divisor_index; uint status = Div2_FindLeadingBitsAndCheck( divisor, remainder, table_id, index, divisor_table_id, divisor_index); if( status < 2 ) return status; // here we know that 'this' is greater than divisor // then 'index' is greater or equal 'divisor_index' bits_diff = index - divisor_index; UInt divisor_copy(divisor); divisor_copy.Rcl(bits_diff, 0); if( CmpSmaller(divisor_copy, table_id) ) { divisor_copy.Rcr(1); --bits_diff; } Sub(divisor_copy, 0); return 2; } /*! return values: 0 - we've calculated the division 1 - division by zero 2 - we have to still calculate */ uint Div2_FindLeadingBitsAndCheck( const UInt & divisor, UInt * remainder, uint & table_id, uint & index, uint & divisor_table_id, uint & divisor_index) { if( !divisor.FindLeadingBit(divisor_table_id, divisor_index) ) // division by zero return 1; if( !FindLeadingBit(table_id, index) ) { // zero is divided by something SetZero(); if( remainder ) remainder->SetZero(); return 0; } divisor_index += divisor_table_id * TTMATH_BITS_PER_UINT; index += table_id * TTMATH_BITS_PER_UINT; if( divisor_table_id == 0 ) { // dividor has only one 32-bit word uint r; DivInt(divisor.table[0], &r); if( remainder ) { remainder->SetZero(); remainder->table[0] = r; } return 0; } if( Div2_DivisorGreaterOrEqual( divisor, remainder, table_id, index, divisor_table_id, divisor_index) ) return 0; return 2; } /*! return values: true if divisor is equal or greater than 'this' */ bool Div2_DivisorGreaterOrEqual( const UInt & divisor, UInt * remainder, uint table_id, uint index, uint divisor_table_id, uint divisor_index ) { if( divisor_index > index ) { // divisor is greater than this if( remainder ) *remainder = *this; SetZero(); return true; } if( divisor_index == index ) { // table_id == divisor_table_id as well uint i; for(i = table_id ; i!=0 && table[i]==divisor.table[i] ; --i); if( table[i] < divisor.table[i] ) { // divisor is greater than 'this' if( remainder ) *remainder = *this; SetZero(); return true; } else if( table[i] == divisor.table[i] ) { // divisor is equal 'this' if( remainder ) remainder->SetZero(); SetOne(); return true; } } return false; } public: /*! the third division algorithm this algorithm is described in the following book: "The art of computer programming 2" (4.3.1 page 272) Donald E. Knuth */ uint Div3(const UInt & v, UInt * remainder = 0) { TTMATH_REFERENCE_ASSERT( v ) uint m,n, test; test = Div_StandardTest(v, m, n, remainder); if( test < 2 ) return test; if( n == 0 ) { uint r; DivInt( v.table[0], &r ); if( remainder ) { remainder->SetZero(); remainder->table[0] = r; } return 0; } // we can only use the third division algorithm when // the divisor is greater or equal 2^32 (has more than one 32-bit word) ++m; ++n; m = m - n; Div3_Division(v, remainder, m, n); return 0; } private: void Div3_Division(UInt v, UInt * remainder, uint m, uint n) { TTMATH_ASSERT( n>=2 ) UInt uu, vv; UInt q; uint d, u_value_size, u0, u1, u2, v1, v0, j=m; u_value_size = Div3_Normalize(v, n, d); if( j+n == value_size ) u2 = u_value_size; else u2 = table[j+n]; Div3_MakeBiggerV(v, vv); for(uint i = j+1 ; i & uu, uint j, uint n, uint u_max) { uint i; for(i=0 ; i so and 'i' is from <0..value_size> // then table[i] is always correct (look at the declaration of 'uu') uu.table[i] = u_max; for( ++i ; i & uu, uint j, uint n) { uint i; for(i=0 ; i & v, UInt & vv) { for(uint i=0 ; i & v, uint n, uint & d) { // v.table[n-1] is != 0 uint bit = (uint)FindLeadingBitInWord(v.table[n-1]); uint move = (TTMATH_BITS_PER_UINT - bit - 1); uint res = table[value_size-1]; d = move; if( move > 0 ) { v.Rcl(move, 0); Rcl(move, 0); res = res >> (bit + 1); } else { res = 0; } return res; } void Div3_Unnormalize(UInt * remainder, uint n, uint d) { for(uint i=n ; i u_temp; uint rp; bool next_test; u_temp.table[1] = u2; u_temp.table[0] = u1; u_temp.DivInt(v1, &rp); TTMATH_ASSERT( u_temp.table[1]==0 || u_temp.table[1]==1 ) do { bool decrease = false; if( u_temp.table[1] == 1 ) decrease = true; else { UInt<2> temp1, temp2; UInt<2>::MulTwoWords(u_temp.table[0], v0, temp1.table+1, temp1.table); temp2.table[1] = rp; temp2.table[0] = u0; if( temp1 > temp2 ) decrease = true; } next_test = false; if( decrease ) { u_temp.SubOne(); rp += v1; if( rp >= v1 ) // it means that there wasn't a carry (r & uu, const UInt & vv, uint & qp) { UInt vv_temp(vv); vv_temp.MulInt(qp); if( uu.Sub(vv_temp) ) { // there was a carry // // !!! this part of code was not tested // --qp; uu.Add(vv); } } 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 For example: let n=2 then if there's a value 111 (bin) there'll be '100' (bin) */ void ClearFirstBits(uint n) { if( n >= value_size*TTMATH_BITS_PER_UINT ) { SetZero(); return; } uint * p = table; // first we're clearing the whole words while( n >= TTMATH_BITS_PER_UINT ) { *p++ = 0; n -= TTMATH_BITS_PER_UINT; } if( n == 0 ) return; // and then we're clearing one word which has left // mask -- all bits are set to one uint mask = TTMATH_UINT_MAX_VALUE; mask = mask << n; (*p) &= mask; } /*! this method returns true if the highest bit of the value is set */ bool IsTheHighestBitSet() const { return (table[value_size-1] & TTMATH_UINT_HIGHEST_BIT) != 0; } /*! this method returns true if the lowest bit of the value is set */ bool IsTheLowestBitSet() const { return (*table & 1) != 0; } /*! this method returns true if the value is equal zero */ bool IsZero() const { for(uint i=0 ; i 1 8 -> 8 A -> 10 f -> 15 this method don't check whether c is correct or not */ static uint CharToDigit(uint c) { if(c>='0' && c<='9') return c-'0'; if(c>='a' && c<='z') return c-'a'+10; return c-'A'+10; } /*! this method changes a character 'c' into its value (if there can't be a correct value it returns -1) for example: c=2, base=10 -> function returns 2 c=A, base=10 -> function returns -1 c=A, base=16 -> function returns 10 */ static sint CharToDigit(uint c, uint base) { if( c>='0' && c<='9' ) c=c-'0'; else if( c>='a' && c<='z' ) c=c-'a'+10; else if( c>='A' && c<='Z' ) c=c-'A'+10; else return -1; if( c >= base ) return -1; return sint(c); } /*! this method converts a digit into a char digit should be from <0,F> (we don't have to get a base) for example: 1 -> 1 8 -> 8 10 -> A 15 -> F */ static uint DigitToChar(uint digit) { if( digit < 10 ) return digit + '0'; return digit - 10 + 'A'; } /*! this method converts an UInt type to this class this operation has mainly sense if the value from p is equal or smaller than that one which is returned from UInt::SetMax() it returns a carry if the value 'p' is too big */ template uint FromUInt(const UInt & p) { uint min_size = (value_size < argument_size)? value_size : argument_size; uint i; for(i=0 ; i argument_size ) { // 'this' is longer than 'p' for( ; i type to this class it doesn't return a carry */ template UInt & operator=(const UInt & p) { FromUInt(p); return *this; } /*! the assignment operator */ UInt & operator=(const UInt & p) { FromUInt(p); return *this; } /*! this method converts the uint type to this class */ UInt & operator=(uint i) { FromUInt(i); return *this; } /*! a constructor for converting the uint to this class */ UInt(uint i) { FromUInt(i); } /*! this method converts the sint type to this class we provide operator(sint) and the constructor(sint) in order to allow the programmer do that: UInt<..> type = 10; this constant 10 has the int type (signed int), if we don't give such operators and constructors the compiler will not compile the program, because it has to make a conversion and doesn't know into which type (the UInt class has operator=(const char*), operator=(uint) etc.) */ UInt & operator=(sint i) { FromUInt(uint(i)); return *this; } /*! a constructor for converting the sint to this class look at the description of UInt::operator=(sint) */ UInt(sint i) { FromUInt(uint(i)); } /*! a constructor for converting a string to this class (with the base=10) */ UInt(const char * s) { FromString(s); } /*! a constructor for converting a string to this class (with the base=10) */ UInt(const std::string & s) { FromString( s.c_str() ); } /*! a default constructor we don't clear table etc. */ UInt() { } /*! a copy constructor */ UInt(const UInt & u) { FromUInt(u); } /*! a template for producting constructors for copying from another types */ template UInt(const UInt & u) { // look that 'size' we still set as 'value_size' and not as u.value_size FromUInt(u); } /*! a destructor */ ~UInt() { } /*! this method returns the lowest value from table we must be sure when we using this method whether the value will hold in an uint type or not (the rest value from the table must be zero) */ uint ToUInt() const { return table[0]; } /*! this method converts the value to a string with a base equal 'b' */ void ToString(std::string & result, uint b = 10) const { UInt temp( *this ); char character; uint rem; result.clear(); if( b<2 || b>16 ) return; do { temp.DivInt(b, &rem); character = DigitToChar( rem ); result.insert(result.begin(), character); } while( !temp.IsZero() ); return; } /* this method's ommiting any white characters from the string */ static void SkipWhiteCharacters(const char * & c) { while( (*c==' ' ) || (*c=='\t') || (*c==13 ) || (*c=='\n') ) ++c; } /*! 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 if the value from s is too large the rest digits will be skipped */ uint FromString(const char * s, uint b = 10, const char ** after_source = 0) { UInt base( b ); UInt temp; sint z; uint c = 0; SetZero(); temp.SetZero(); SkipWhiteCharacters(s); if( after_source ) *after_source = s; if( b<2 || b>16 ) return 1; for( ; (z=CharToDigit(*s, b)) != -1 ; ++s) { if( c == 0 ) { temp.table[0] = z; c += Mul(base); c += Add(temp); } } if( after_source ) *after_source = s; return (c==0)? 0 : 1; } /*! 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(), b ); } /*! this operator converts a string into its value (with base = 10) */ UInt & operator=(const char * s) { FromString(s); return *this; } /*! this operator converts a string into its value (with base = 10) */ UInt & operator=(const std::string & s) { FromString( s.c_str() ); return *this; } /*! * * methods for comparing * */ /*! this method returns true if 'this' is smaller than 'l' 'index' is an index of the first word from will be the comparison performed (note: we start the comparison from back - from the last word, when index is -1 /default/ it is automatically set into the last word) I introduced it for some kind of optimization made in the second division algorithm (Div2) */ bool CmpSmaller(const UInt & l, sint index = -1) const { sint i; if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; for( ; i>=0 ; --i) { if( table[i] != l.table[i] ) return table[i] < l.table[i]; } // they're equal return false; } /*! this method returns true if 'this' is bigger than 'l' 'index' is an index of the first word from will be the comparison performed (note: we start the comparison from back - from the last word, when index is -1 /default/ it is automatically set into the last word) I introduced it for some kind of optimization made in the second division algorithm (Div2) */ bool CmpBigger(const UInt & l, sint index = -1) const { sint i; if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; for( ; i>=0 ; --i) { if( table[i] != l.table[i] ) return table[i] > l.table[i]; } // they're equal return false; } /*! this method returns true if 'this' is equal 'l' 'index' is an index of the first word from will be the comparison performed (note: we start the comparison from back - from the last word, when index is -1 /default/ it is automatically set into the last word) */ bool CmpEqual(const UInt & l, sint index = -1) const { sint i; if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; for( ; i>=0 ; --i) if( table[i] != l.table[i] ) return false; return true; } /*! this method returns true if 'this' is smaller than or equal 'l' 'index' is an index of the first word from will be the comparison performed (note: we start the comparison from back - from the last word, when index is -1 /default/ it is automatically set into the last word) */ bool CmpSmallerEqual(const UInt & l, sint index=-1) const { sint i; if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; for( ; i>=0 ; --i) { if( table[i] != l.table[i] ) return table[i] < l.table[i]; } // they're equal return true; } /*! this method returns true if 'this' is bigger than or equal 'l' 'index' is an index of the first word from will be the comparison performed (note: we start the comparison from back - from the last word, when index is -1 /default/ it is automatically set into the last word) */ bool CmpBiggerEqual(const UInt & l, sint index=-1) const { sint i; if( index==-1 || index>=sint(value_size) ) i = value_size - 1; else i = index; for( ; i>=0 ; --i) { if( table[i] != l.table[i] ) return table[i] > l.table[i]; } // they're equal return true; } /* operators for comparising */ bool operator<(const UInt & l) const { return CmpSmaller(l); } bool operator>(const UInt & l) const { return CmpBigger(l); } bool operator==(const UInt & l) const { return CmpEqual(l); } bool operator!=(const UInt & l) const { return !operator==(l); } bool operator<=(const UInt & l) const { return CmpSmallerEqual(l); } bool operator>=(const UInt & l) const { return CmpBiggerEqual(l); } /*! * * standard mathematical operators * */ UInt operator-(const UInt & p2) const { UInt temp(*this); temp.Sub(p2); return temp; } UInt & operator-=(const UInt & p2) { Sub(p2); return *this; } UInt operator+(const UInt & p2) const { UInt temp(*this); temp.Add(p2); return temp; } UInt & operator+=(const UInt & p2) { Add(p2); return *this; } UInt operator*(const UInt & p2) const { UInt temp(*this); temp.Mul(p2); return temp; } UInt & operator*=(const UInt & p2) { Mul(p2); return *this; } UInt operator/(const UInt & p2) const { UInt temp(*this); temp.Div(p2); return temp; } UInt & operator/=(const UInt & p2) { Div(p2); return *this; } UInt operator%(const UInt & p2) const { UInt temp(*this); UInt remainder; temp.Div( p2, remainder ); return remainder; } UInt & operator%=(const UInt & p2) { UInt temp(*this); UInt 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 * * (they are very simple, in the future they should be changed) * */ friend std::ostream & operator<<(std::ostream & s, const UInt & l) { std::string ss; l.ToString(ss); s << ss; return s; } friend std::istream & operator>>(std::istream & s, UInt & l) { std::string ss; // char for operator>> unsigned char z; // operator>> omits white characters if they're set for ommiting s >> z; // we're reading only digits (base=10) while( s.good() && 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; } #ifdef TTMATH_PLATFORM64 private: uint Rcl2_one(uint c); uint Rcr2_one(uint c); uint Rcl2(uint bits, uint c); uint Rcr2(uint bits, uint c); public: // these methods are for 64bit processors and are defined in 'ttmathuint64.h' UInt & operator=(unsigned int i); UInt(unsigned int i); UInt & operator=(signed int i); UInt(signed int i); void SetFromTable(const unsigned int * temp_table, uint temp_table_len); uint Add(const UInt & ss2, uint c=0); uint AddInt(uint value, uint index = 0); uint AddTwoInts(uint x2, uint x1, uint index); 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 void MulTwoWords(uint a, uint b, uint * result2, uint * result1); static void DivTwoWords(uint a,uint b, uint c, uint * r, uint * rest); #endif }; } //namespace #include "ttmathuint64.h" #endif