// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_BIGINT_KERNEL_1_CPp_ #define DLIB_BIGINT_KERNEL_1_CPp_ #include "bigint_kernel_1.h" #include namespace dlib { // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // member/friend function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- bigint_kernel_1:: bigint_kernel_1 ( ) : slack(25), data(new data_record(slack)) {} // ---------------------------------------------------------------------------------------- bigint_kernel_1:: bigint_kernel_1 ( uint32 value ) : slack(25), data(new data_record(slack)) { *(data->number) = static_cast(value&0xFFFF); *(data->number+1) = static_cast((value>>16)&0xFFFF); if (*(data->number+1) != 0) data->digits_used = 2; } // ---------------------------------------------------------------------------------------- bigint_kernel_1:: bigint_kernel_1 ( const bigint_kernel_1& item ) : slack(25), data(item.data) { data->references += 1; } // ---------------------------------------------------------------------------------------- bigint_kernel_1:: ~bigint_kernel_1 ( ) { if (data->references == 1) { delete data; } else { data->references -= 1; } } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator+ ( const bigint_kernel_1& rhs ) const { data_record* temp = new data_record ( std::max(rhs.data->digits_used,data->digits_used) + slack ); long_add(data,rhs.data,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator+= ( const bigint_kernel_1& rhs ) { // if there are other references to our data if (data->references != 1) { data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); data->references -= 1; long_add(data,rhs.data,temp); data = temp; } // if data is not big enough for the result else if (data->size <= std::max(data->digits_used,rhs.data->digits_used)) { data_record* temp = new data_record(std::max(data->digits_used,rhs.data->digits_used)+slack); long_add(data,rhs.data,temp); delete data; data = temp; } // there is enough size and no references else { long_add(data,rhs.data,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator- ( const bigint_kernel_1& rhs ) const { data_record* temp = new data_record ( data->digits_used + slack ); long_sub(data,rhs.data,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator-= ( const bigint_kernel_1& rhs ) { // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; long_sub(data,rhs.data,temp); data = temp; } else { long_sub(data,rhs.data,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator* ( const bigint_kernel_1& rhs ) const { data_record* temp = new data_record ( data->digits_used + rhs.data->digits_used + slack ); long_mul(data,rhs.data,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator*= ( const bigint_kernel_1& rhs ) { // create a data_record to store the result of the multiplication in data_record* temp = new data_record(rhs.data->digits_used+data->digits_used+slack); long_mul(data,rhs.data,temp); // if there are other references to data if (data->references != 1) { data->references -= 1; } else { delete data; } data = temp; return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator/ ( const bigint_kernel_1& rhs ) const { data_record* temp = new data_record(data->digits_used+slack); data_record* remainder; try { remainder = new data_record(data->digits_used+slack); } catch (...) { delete temp; throw; } long_div(data,rhs.data,temp,remainder); delete remainder; return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator/= ( const bigint_kernel_1& rhs ) { data_record* temp = new data_record(data->digits_used+slack); data_record* remainder; try { remainder = new data_record(data->digits_used+slack); } catch (...) { delete temp; throw; } long_div(data,rhs.data,temp,remainder); // check if there are other references to data if (data->references != 1) { data->references -= 1; } // if there are no references to data then it must be deleted else { delete data; } data = temp; delete remainder; return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator% ( const bigint_kernel_1& rhs ) const { data_record* temp = new data_record(data->digits_used+slack); data_record* remainder; try { remainder = new data_record(data->digits_used+slack); } catch (...) { delete temp; throw; } long_div(data,rhs.data,temp,remainder); delete temp; return bigint_kernel_1(remainder,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator%= ( const bigint_kernel_1& rhs ) { data_record* temp = new data_record(data->digits_used+slack); data_record* remainder; try { remainder = new data_record(data->digits_used+slack); } catch (...) { delete temp; throw; } long_div(data,rhs.data,temp,remainder); // check if there are other references to data if (data->references != 1) { data->references -= 1; } // if there are no references to data then it must be deleted else { delete data; } data = remainder; delete temp; return *this; } // ---------------------------------------------------------------------------------------- bool bigint_kernel_1:: operator < ( const bigint_kernel_1& rhs ) const { return is_less_than(data,rhs.data); } // ---------------------------------------------------------------------------------------- bool bigint_kernel_1:: operator == ( const bigint_kernel_1& rhs ) const { return is_equal_to(data,rhs.data); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator= ( const bigint_kernel_1& rhs ) { if (this == &rhs) return *this; // if we have the only reference to our data then delete it if (data->references == 1) { delete data; data = rhs.data; data->references += 1; } else { data->references -= 1; data = rhs.data; data->references += 1; } return *this; } // ---------------------------------------------------------------------------------------- std::ostream& operator<< ( std::ostream& out_, const bigint_kernel_1& rhs ) { std::ostream out(out_.rdbuf()); typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record(*rhs.data,0); // get a char array big enough to hold the number in ascii format char* str; try { str = new char[(rhs.data->digits_used)*5+10]; } catch (...) { delete temp; throw; } char* str_start = str; str += (rhs.data->digits_used)*5+9; *str = 0; --str; uint16 remainder; rhs.short_div(temp,10000,temp,remainder); // pull the digits out of remainder char a = remainder % 10 + '0'; remainder /= 10; char b = remainder % 10 + '0'; remainder /= 10; char c = remainder % 10 + '0'; remainder /= 10; char d = remainder % 10 + '0'; remainder /= 10; *str = a; --str; *str = b; --str; *str = c; --str; *str = d; --str; // keep looping until temp represents zero while (temp->digits_used != 1 || *(temp->number) != 0) { rhs.short_div(temp,10000,temp,remainder); // pull the digits out of remainder char a = remainder % 10 + '0'; remainder /= 10; char b = remainder % 10 + '0'; remainder /= 10; char c = remainder % 10 + '0'; remainder /= 10; char d = remainder % 10 + '0'; remainder /= 10; *str = a; --str; *str = b; --str; *str = c; --str; *str = d; --str; } // throw away and extra leading zeros ++str; if (*str == '0') ++str; if (*str == '0') ++str; if (*str == '0') ++str; out << str; delete [] str_start; delete temp; return out_; } // ---------------------------------------------------------------------------------------- std::istream& operator>> ( std::istream& in_, bigint_kernel_1& rhs ) { std::istream in(in_.rdbuf()); // ignore any leading whitespaces while (in.peek() == ' ' || in.peek() == '\t' || in.peek() == '\n') { in.get(); } // if the first digit is not an integer then this is an error if ( !(in.peek() >= '0' && in.peek() <= '9')) { in_.clear(std::ios::failbit); return in_; } int num_read; bigint_kernel_1 temp; do { // try to get 4 chars from in num_read = 1; char a = 0; char b = 0; char c = 0; char d = 0; if (in.peek() >= '0' && in.peek() <= '9') { num_read *= 10; a = in.get(); } if (in.peek() >= '0' && in.peek() <= '9') { num_read *= 10; b = in.get(); } if (in.peek() >= '0' && in.peek() <= '9') { num_read *= 10; c = in.get(); } if (in.peek() >= '0' && in.peek() <= '9') { num_read *= 10; d = in.get(); } // merge the for digits into an uint16 uint16 num = 0; if (a != 0) { num = a - '0'; } if (b != 0) { num *= 10; num += b - '0'; } if (c != 0) { num *= 10; num += c - '0'; } if (d != 0) { num *= 10; num += d - '0'; } if (num_read != 1) { // shift the digits in temp left by the number of new digits we just read temp *= num_read; // add in new digits temp += num; } } while (num_read == 10000); rhs = temp; return in_; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator+ ( uint16 lhs, const bigint_kernel_1& rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record (rhs.data->digits_used+rhs.slack); rhs.short_add(rhs.data,lhs,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator+ ( const bigint_kernel_1& lhs, uint16 rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record (lhs.data->digits_used+lhs.slack); lhs.short_add(lhs.data,rhs,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator+= ( uint16 rhs ) { // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; short_add(data,rhs,temp); data = temp; } // or if we need to enlarge data then do so else if (data->digits_used == data->size) { data_record* temp = new data_record(data->digits_used+slack); short_add(data,rhs,temp); delete data; data = temp; } // or if there is plenty of space and no references else { short_add(data,rhs,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator- ( uint16 lhs, const bigint_kernel_1& rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record(rhs.slack); *(temp->number) = lhs - *(rhs.data->number); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator- ( const bigint_kernel_1& lhs, uint16 rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record (lhs.data->digits_used+lhs.slack); lhs.short_sub(lhs.data,rhs,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator-= ( uint16 rhs ) { // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; short_sub(data,rhs,temp); data = temp; } else { short_sub(data,rhs,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator* ( uint16 lhs, const bigint_kernel_1& rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record (rhs.data->digits_used+rhs.slack); rhs.short_mul(rhs.data,lhs,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator* ( const bigint_kernel_1& lhs, uint16 rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record (lhs.data->digits_used+lhs.slack); lhs.short_mul(lhs.data,rhs,temp); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator*= ( uint16 rhs ) { // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; short_mul(data,rhs,temp); data = temp; } // or if we need to enlarge data else if (data->digits_used == data->size) { data_record* temp = new data_record(data->digits_used+slack); short_mul(data,rhs,temp); delete data; data = temp; } else { short_mul(data,rhs,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator/ ( uint16 lhs, const bigint_kernel_1& rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record(rhs.slack); // if rhs might not be bigger than lhs if (rhs.data->digits_used == 1) { *(temp->number) = lhs/ *(rhs.data->number); } return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator/ ( const bigint_kernel_1& lhs, uint16 rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record (lhs.data->digits_used+lhs.slack); uint16 remainder; lhs.short_div(lhs.data,rhs,temp,remainder); return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator/= ( uint16 rhs ) { uint16 remainder; // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; short_div(data,rhs,temp,remainder); data = temp; } else { short_div(data,rhs,data,remainder); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator% ( uint16 lhs, const bigint_kernel_1& rhs ) { typedef bigint_kernel_1 bigint; // temp is zero by default bigint::data_record* temp = new bigint::data_record(rhs.slack); if (rhs.data->digits_used == 1) { // if rhs is just an uint16 inside then perform the modulus *(temp->number) = lhs % *(rhs.data->number); } else { // if rhs is bigger than lhs then the answer is lhs *(temp->number) = lhs; } return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 operator% ( const bigint_kernel_1& lhs, uint16 rhs ) { typedef bigint_kernel_1 bigint; bigint::data_record* temp = new bigint::data_record(lhs.data->digits_used+lhs.slack); uint16 remainder; lhs.short_div(lhs.data,rhs,temp,remainder); temp->digits_used = 1; *(temp->number) = remainder; return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator%= ( uint16 rhs ) { uint16 remainder; // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; short_div(data,rhs,temp,remainder); data = temp; } else { short_div(data,rhs,data,remainder); } data->digits_used = 1; *(data->number) = remainder; return *this; } // ---------------------------------------------------------------------------------------- bool operator < ( uint16 lhs, const bigint_kernel_1& rhs ) { return (rhs.data->digits_used > 1 || lhs < *(rhs.data->number) ); } // ---------------------------------------------------------------------------------------- bool operator < ( const bigint_kernel_1& lhs, uint16 rhs ) { return (lhs.data->digits_used == 1 && *(lhs.data->number) < rhs); } // ---------------------------------------------------------------------------------------- bool operator == ( const bigint_kernel_1& lhs, uint16 rhs ) { return (lhs.data->digits_used == 1 && *(lhs.data->number) == rhs); } // ---------------------------------------------------------------------------------------- bool operator == ( uint16 lhs, const bigint_kernel_1& rhs ) { return (rhs.data->digits_used == 1 && *(rhs.data->number) == lhs); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator= ( uint16 rhs ) { // check if there are other references to our data if (data->references != 1) { data->references -= 1; try { data = new data_record(slack); } catch (...) { data->references += 1; throw; } } else { data->digits_used = 1; } *(data->number) = rhs; return *this; } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator++ ( ) { // if there are other references to this data then make a copy of it if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; increment(data,temp); data = temp; } // or if we need to enlarge data then do so else if (data->digits_used == data->size) { data_record* temp = new data_record(data->digits_used+slack); increment(data,temp); delete data; data = temp; } else { increment(data,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator++ ( int ) { data_record* temp; // this is the copy of temp we will return in the end data_record* temp2 = new data_record(data->digits_used+slack); increment(data,temp2); temp = data; data = temp2; return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- bigint_kernel_1& bigint_kernel_1:: operator-- ( ) { // if there are other references to this data if (data->references != 1) { data_record* temp = new data_record(data->digits_used+slack); data->references -= 1; decrement(data,temp); data = temp; } else { decrement(data,data); } return *this; } // ---------------------------------------------------------------------------------------- const bigint_kernel_1 bigint_kernel_1:: operator-- ( int ) { data_record* temp; // this is the copy of temp we will return in the end data_record* temp2 = new data_record(data->digits_used+slack); decrement(data,temp2); temp = data; data = temp2; return bigint_kernel_1(temp,0); } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // private member function definitions // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: short_add ( const data_record* data, uint16 value, data_record* result ) const { // put value into the carry part of temp uint32 temp = value; temp <<= 16; const uint16* number = data->number; const uint16* end = number + data->digits_used; // one past the end of number uint16* r = result->number; while (number != end) { // add *number and the current carry temp = *number + (temp>>16); // put the low word of temp into *r *r = static_cast(temp & 0xFFFF); ++number; ++r; } // if there is a final carry if ((temp>>16) != 0) { result->digits_used = data->digits_used + 1; // store the carry in the most significant digit of the result *r = static_cast(temp>>16); } else { result->digits_used = data->digits_used; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: short_sub ( const data_record* data, uint16 value, data_record* result ) const { const uint16* number = data->number; const uint16* end = number + data->digits_used - 1; uint16* r = result->number; uint32 temp = *number - value; // put the low word of temp into *data *r = static_cast(temp & 0xFFFF); while (number != end) { ++number; ++r; // subtract the carry from *number temp = *number - (temp>>31); // put the low word of temp into *r *r = static_cast(temp & 0xFFFF); } // if we lost a digit in the subtraction if (*r == 0) { if (data->digits_used == 1) result->digits_used = 1; else result->digits_used = data->digits_used - 1; } else { result->digits_used = data->digits_used; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: short_mul ( const data_record* data, uint16 value, data_record* result ) const { uint32 temp = 0; const uint16* number = data->number; uint16* r = result->number; const uint16* end = r + data->digits_used; while ( r != end) { // multiply *data and value and add in the carry temp = *number*(uint32)value + (temp>>16); // put the low word of temp into *data *r = static_cast(temp & 0xFFFF); ++number; ++r; } // if there is a final carry if ((temp>>16) != 0) { result->digits_used = data->digits_used + 1; // put the final carry into the most significant digit of the result *r = static_cast(temp>>16); } else { result->digits_used = data->digits_used; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: short_div ( const data_record* data, uint16 value, data_record* result, uint16& rem ) const { uint16 remainder = 0; uint32 temp; const uint16* number = data->number + data->digits_used - 1; const uint16* end = number - data->digits_used; uint16* r = result->number + data->digits_used - 1; // if we are losing a digit in this division if (*number < value) { if (data->digits_used == 1) result->digits_used = 1; else result->digits_used = data->digits_used - 1; } else { result->digits_used = data->digits_used; } // perform the actual division while (number != end) { temp = *number + (((uint32)remainder)<<16); *r = static_cast(temp/value); remainder = static_cast(temp%value); --number; --r; } rem = remainder; } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: long_add ( const data_record* lhs, const data_record* rhs, data_record* result ) const { // put value into the carry part of temp uint32 temp=0; uint16* min_num; // the number with the least digits used uint16* max_num; // the number with the most digits used uint16* min_end; // one past the end of min_num uint16* max_end; // one past the end of max_num uint16* r = result->number; uint32 max_digits_used; if (lhs->digits_used < rhs->digits_used) { max_digits_used = rhs->digits_used; min_num = lhs->number; max_num = rhs->number; min_end = min_num + lhs->digits_used; max_end = max_num + rhs->digits_used; } else { max_digits_used = lhs->digits_used; min_num = rhs->number; max_num = lhs->number; min_end = min_num + rhs->digits_used; max_end = max_num + lhs->digits_used; } while (min_num != min_end) { // add *min_num, *max_num and the current carry temp = *min_num + *max_num + (temp>>16); // put the low word of temp into *r *r = static_cast(temp & 0xFFFF); ++min_num; ++max_num; ++r; } while (max_num != max_end) { // add *max_num and the current carry temp = *max_num + (temp>>16); // put the low word of temp into *r *r = static_cast(temp & 0xFFFF); ++max_num; ++r; } // check if there was a final carry if ((temp>>16) != 0) { result->digits_used = max_digits_used + 1; // put the carry into the most significant digit in the result *r = static_cast(temp>>16); } else { result->digits_used = max_digits_used; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: long_sub ( const data_record* lhs, const data_record* rhs, data_record* result ) const { const uint16* number1 = lhs->number; const uint16* number2 = rhs->number; const uint16* end = number2 + rhs->digits_used; uint16* r = result->number; uint32 temp =0; while (number2 != end) { // subtract *number2 from *number1 and then subtract any carry temp = *number1 - *number2 - (temp>>31); // put the low word of temp into *r *r = static_cast(temp & 0xFFFF); ++number1; ++number2; ++r; } end = lhs->number + lhs->digits_used; while (number1 != end) { // subtract the carry from *number1 temp = *number1 - (temp>>31); // put the low word of temp into *r *r = static_cast(temp & 0xFFFF); ++number1; ++r; } result->digits_used = lhs->digits_used; // adjust the number of digits used appropriately --r; while (*r == 0 && result->digits_used > 1) { --r; --result->digits_used; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: long_div ( const data_record* lhs, const data_record* rhs, data_record* result, data_record* remainder ) const { // zero result result->digits_used = 1; *(result->number) = 0; uint16* a; uint16* b; uint16* end; // copy lhs into remainder remainder->digits_used = lhs->digits_used; a = remainder->number; end = a + remainder->digits_used; b = lhs->number; while (a != end) { *a = *b; ++a; ++b; } // if rhs is bigger than lhs then result == 0 and remainder == lhs // so then we can quit right now if (is_less_than(lhs,rhs)) { return; } // make a temporary number data_record temp(lhs->digits_used + slack); // shift rhs left until it is one shift away from being larger than lhs and // put the number of left shifts necessary into shifts uint32 shifts; shifts = (lhs->digits_used - rhs->digits_used) * 16; shift_left(rhs,&temp,shifts); // while (lhs > temp) while (is_less_than(&temp,lhs)) { shift_left(&temp,&temp,1); ++shifts; } // make sure lhs isn't smaller than temp while (is_less_than(lhs,&temp)) { shift_right(&temp,&temp); --shifts; } // we want to execute the loop shifts +1 times ++shifts; while (shifts != 0) { shift_left(result,result,1); // if (temp <= remainder) if (!is_less_than(remainder,&temp)) { long_sub(remainder,&temp,remainder); // increment result uint16* r = result->number; uint16* end = r + result->digits_used; while (true) { ++(*r); // if there was no carry then we are done if (*r != 0) break; ++r; // if we hit the end of r and there is still a carry then // the next digit of r is 1 and there is one more digit used if (r == end) { *r = 1; ++(result->digits_used); break; } } } shift_right(&temp,&temp); --shifts; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: long_mul ( const data_record* lhs, const data_record* rhs, data_record* result ) const { // make result be zero result->digits_used = 1; *(result->number) = 0; const data_record* aa; const data_record* bb; if (lhs->digits_used < rhs->digits_used) { // make copies of lhs and rhs and give them an appropriate amount of // extra memory so there won't be any overflows aa = lhs; bb = rhs; } else { // make copies of lhs and rhs and give them an appropriate amount of // extra memory so there won't be any overflows aa = rhs; bb = lhs; } // this is where we actually copy lhs and rhs data_record b(*bb,aa->digits_used+slack); // the larger(approximately) of lhs and rhs uint32 shift_value = 0; uint16* anum = aa->number; uint16* end = anum + aa->digits_used; while (anum != end ) { uint16 bit = 0x0001; for (int i = 0; i < 16; ++i) { // if the specified bit of a is 1 if ((*anum & bit) != 0) { shift_left(&b,&b,shift_value); shift_value = 0; long_add(&b,result,result); } ++shift_value; bit <<= 1; } ++anum; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: shift_left ( const data_record* data, data_record* result, uint32 shift_amount ) const { uint32 offset = shift_amount/16; shift_amount &= 0xf; // same as shift_amount %= 16; uint16* r = result->number + data->digits_used + offset; // result uint16* end = data->number; uint16* s = end + data->digits_used; // source const uint32 temp = 16 - shift_amount; *r = (*(--s) >> temp); // set the number of digits used in the result // if the upper bits from *s were zero then don't count this first word if (*r == 0) { result->digits_used = data->digits_used + offset; } else { result->digits_used = data->digits_used + offset + 1; } --r; while (s != end) { *r = ((*s << shift_amount) | ( *(s-1) >> temp)); --r; --s; } *r = *s << shift_amount; // now zero the rest of the result end = result->number; while (r != end) *(--r) = 0; } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: shift_right ( const data_record* data, data_record* result ) const { uint16* r = result->number; // result uint16* s = data->number; // source uint16* end = s + data->digits_used - 1; while (s != end) { *r = (*s >> 1) | (*(s+1) << 15); ++r; ++s; } *r = *s >> 1; // calculate the new number for digits_used if (*r == 0) { if (data->digits_used != 1) result->digits_used = data->digits_used - 1; else result->digits_used = 1; } else { result->digits_used = data->digits_used; } } // ---------------------------------------------------------------------------------------- bool bigint_kernel_1:: is_less_than ( const data_record* lhs, const data_record* rhs ) const { uint32 lhs_digits_used = lhs->digits_used; uint32 rhs_digits_used = rhs->digits_used; // if lhs is definitely less than rhs if (lhs_digits_used < rhs_digits_used ) return true; // if lhs is definitely greater than rhs else if (lhs_digits_used > rhs_digits_used) return false; else { uint16* end = lhs->number; uint16* l = end + lhs_digits_used; uint16* r = rhs->number + rhs_digits_used; while (l != end) { --l; --r; if (*l < *r) return true; else if (*l > *r) return false; } // at this point we know that they are equal return false; } } // ---------------------------------------------------------------------------------------- bool bigint_kernel_1:: is_equal_to ( const data_record* lhs, const data_record* rhs ) const { // if lhs and rhs are definitely not equal if (lhs->digits_used != rhs->digits_used ) { return false; } else { uint16* l = lhs->number; uint16* r = rhs->number; uint16* end = l + lhs->digits_used; while (l != end) { if (*l != *r) return false; ++l; ++r; } // at this point we know that they are equal return true; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: increment ( const data_record* source, data_record* dest ) const { uint16* s = source->number; uint16* d = dest->number; uint16* end = s + source->digits_used; while (true) { *d = *s + 1; // if there was no carry then break out of the loop if (*d != 0) { dest->digits_used = source->digits_used; // copy the rest of the digits over to d ++d; ++s; while (s != end) { *d = *s; ++d; ++s; } break; } ++s; // if we have hit the end of s and there was a carry up to this point // then just make the next digit 1 and add one to the digits used if (s == end) { ++d; dest->digits_used = source->digits_used + 1; *d = 1; break; } ++d; } } // ---------------------------------------------------------------------------------------- void bigint_kernel_1:: decrement ( const data_record* source, data_record* dest ) const { uint16* s = source->number; uint16* d = dest->number; uint16* end = s + source->digits_used; while (true) { *d = *s - 1; // if there was no carry then break out of the loop if (*d != 0xFFFF) { // if we lost a digit in the subtraction if (*d == 0 && s+1 == end) { if (source->digits_used == 1) dest->digits_used = 1; else dest->digits_used = source->digits_used - 1; } else { dest->digits_used = source->digits_used; } break; } else { ++d; ++s; } } // copy the rest of the digits over to d ++d; ++s; while (s != end) { *d = *s; ++d; ++s; } } // ---------------------------------------------------------------------------------------- } #endif // DLIB_BIGINT_KERNEL_1_CPp_