/* ****************************************************************************
*
* Copyright 2013 Nedim Srndic
*
* This file is part of rsa - the RSA implementation in C++.
*
* rsa is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* rsa is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with rsa. If not, see .
*
* BigInt.cpp
*
* Author: Nedim Srndic
* Release date: 14th of March 2008
*
* This file contains the implementation for the BigInt class.
*
* There are two static constants defined in this file:
*
* - ULongMax : ULONG_MAX (defined in climits) of type BigInt
* Mainly used for speedup in the multiply() private member function.
* Represents the largest unsigned long integer a particular platform can
* handle. If a BigInt is <= ULongMax, it can be converted to unsigned
* long int. This is platform-specific.
* - SqrtUlongMax : sqrt(ULONG_MAX) of type BigInt
* Mainly used for speedup in the multiply() private member function.
* Represents the square root of the largest unsigned long integer a
* particular platform can handle. If two BigInts are <= SqrtULongMax,
* they can be converted to unsigned long int and safely multiplied
* by the CPU. This is platform-specific.
*
* ****************************************************************************
*/
//comment the following line if you want to use long multiplication
//#define KARATSUBA
#include "BigInt.h"
#include //strlen()
#include //ULONG_MAX
#include //vector
#include //operator std::string()
#include //reverse_copy(), copy(), copy_backward(),
//fill(), fill_n()
using std::cout;
using std::endl;
//define and initialize BigInt::FACTOR
const double BigInt::FACTOR = 1.6;
//A BigInt number with the value of ULONG_MAX
static const BigInt ULongMax(ULONG_MAX);
//A BigInt number with the value of sqrt(ULONG_MAX)
static const BigInt SqrtULongMax
(static_cast(sqrt(static_cast(ULONG_MAX))));
/* Transforms the number from unsigned long int to unsigned char[]
* and pads the result with zeroes. Returns the number of digits. */
unsigned long int BigInt::int2uchar(unsigned long int number,
unsigned char *digits,
unsigned long int padding = 0L)
{
int i(0);
do
{
//the number is stored in reverse
//(i.e. long int 456 is stored as unsigned char[] {[6][5][4]})
digits[i++] = (unsigned char) (number % 10);
number /= 10;
} while (number > 0L);
std::fill_n(digits + i, padding, 0);
return i;
}
/* Converts ASCII digits to equivalent unsigned char numeric values. */
void BigInt::char2uchar(unsigned char *array,
unsigned long int length)
{
for (unsigned long int i(0L); i < length; i++)
array[i] -= '0';
}
/* Check if all ASCII values are digits '0' to '9'. */
bool BigInt::allCharsAreDigits( const char *array,
unsigned long int length)
{
for (unsigned long int i(0L); i < length; i++)
if (array[i] < '0' || array[i] > '9')
return false;
return true;
}
/* Compares two BigInt. If the last two arguments are
* omitted, the comparison is sign-insensitive (comparison by
* absolute value). Returns 0 if a == b, 1 if a > b, 2 if a < b. */
int BigInt::compareNumbers( unsigned char *a, unsigned long int na,
unsigned char *b, unsigned long int nb,
bool aPositive, bool bPositive)
{
if (na < nb || (!aPositive && bPositive))
//a < b
return 2;
else if (na > nb || (aPositive && !bPositive))
//a > b
return 1;
//check the digits one by one starting from the most significant one
for (long int i = na - 1; i >= 0L; i--)
//compare the digits
if (a[i] != b[i])
{
if (a[i] < b[i]) // |a| < |b|
if (aPositive)
return 2; // a < b
else
return 1; // a > b
else // |a| > |b|
if (aPositive)
return 1; // a > b
else
return 2; // a < b
}
//a == b
return 0;
}
/* Multiplies two unsigned char[] using the Divide and Conquer
* a.k.a. Karatsuba algorithm .*/
void BigInt::karatsubaMultiply( unsigned char *a, unsigned char *b,
unsigned long int n, unsigned char *buf1)
{
//if *a <= SqrtULongMax && *b <= SqrtULongMax,
//the CPU can do the multiplication
if (compareNumbers(a, n, SqrtULongMax.digits, SqrtULongMax.digitCount) != 1
&&
compareNumbers(b, n, SqrtULongMax.digits, SqrtULongMax.digitCount) != 1
)
{
int2uchar(toInt(a, n) * toInt(b, n), buf1, n << 1);
return;
}
//nh = higher half digits, nl = lower half digits
//nh == nl || nh + 1 == nl
//nt is used to avoid too much nl + 1 addition operations
unsigned long int nh(n >> 1), nl(n - nh), nt(nl + 1);
//t1 is a temporary pointer, points to p1
unsigned char *t1(buf1 + (n << 1));
BigInt::add(a + nl, nh, a, nl, buf1, nt);
BigInt::add(b + nl, nh, b, nl, buf1 + nt, nt);
BigInt::karatsubaMultiply(a + nl, b + nl, nh, t1); //p1
BigInt::karatsubaMultiply(a, b, nl, t1 + (nh << 1)); //p2
BigInt::karatsubaMultiply(buf1, buf1 + nt, nt, t1 + (n << 1));//p3
//for leftshifting p3 and p1
unsigned long int power(n);
if (power & 1)
power++;
//since the original multiplier is not needed any more, we can reuse a
a = buf1 + (power >> 1);
//copy and shift left p3 by power / 2 and pad right to n * 2 with zeroes
std::fill(buf1, a, 0);
std::copy(t1 + (n << 1), t1 + ((n + nl) << 1) + 1, a);
std::fill(a + (nl << 1) + 1, t1, 0);
//shifted p3 -= p2
//a = shifted p3, b = p2
BigInt::quickSub(a, t1 + (nh << 1), t1, nl);
//shifted p3 -= p1
//a = shifted p3, b = p1
BigInt::quickSub(a, t1, t1, nh);
//shifted p3 += shifted p1
//a = p3[power], b = p1
a = buf1 + power;
BigInt::quickAdd(a, t1, nh);
//p3 += p2
//a = p3, b = p2
unsigned char carry = BigInt::quickAdd(buf1, t1 + (nh << 1), nl);
a = buf1 + (nl << 1);
for (unsigned long int i(0L); carry; i++)
{
a[i] += 1;
carry = a[i] / 10;
a[i] %= 10;
}
}
/* Multiplies two unsigned char[] the long way. */
void BigInt::longMultiply( unsigned char *a, unsigned long int na,
unsigned char *b, unsigned long int nb,
unsigned char *result)
{
std::fill_n(result, na + nb, 0);
unsigned char mult(0);
int carry(0);
for (unsigned long int i(0L); i < na; i++)
{
for (unsigned long int j(0L); j < nb; j++)
{
mult = a[i] * b[j] + result[i + j] + carry;
result[i + j] = static_cast(mult) % 10;
carry = static_cast(mult) / 10;
}
if (carry)
{
result[i + nb] += carry;
carry = 0;
}
}
}
/* Simple addition, used by the multiply function.
* Returns the remaining carry. */
unsigned char BigInt::quickAdd( unsigned char *a, unsigned char *b,
unsigned long int n)
{
unsigned char carry(0), sum(0);
for (unsigned long int i(0L); i < (n << 1); i++)
{
sum = a[i] + b[i] + carry;
carry = sum / 10;
a[i] = sum % 10;
}
return carry;
}
/* Simple subtraction, used by the multiply function. */
void BigInt::quickSub( unsigned char *a, unsigned char *b,
unsigned char *end, unsigned long int n)
{
unsigned char carry(0), sum(0);
for (unsigned long int i(0L); i < (n << 1); i++)
{
sum = 10 + a[i] - (b[i] + carry);
if (sum < 10) //carry
{
a[i] = sum;
carry = 1;
}
else
{
a[i] = sum % 10;
carry = 0;
}
}
a = &a[n << 1];
for (; carry && a < end; a++)
if (*a)
{
(*a)--;
break;
}
else
*a = 9;
}
/* Divides two BigInt numbers by the formula
* dividend = divisor * quotient + remainder*/
void BigInt::divide(const BigInt ÷nd, const BigInt &divisor,
BigInt "ient, BigInt &remainder)
{
BigInt Z1, R, X(dividend.Abs());
/* Make sure quotient and remainder are zero.
* The lack of this assignment introduces a bug if the actual parameters
* are not zero when calling this function. */
quotient = BigIntZero;
remainder = BigIntZero;
// while |X| >= |divisor|
while (BigInt::compareNumbers( X.digits, X.digitCount,
divisor.digits, divisor.digitCount,
true, true) != 2)
{
unsigned long int O(X.digitCount - divisor.digitCount);
if (O <= ULongMax.digitCount - 2)
{
unsigned long int i;
if (X.digitCount > ULongMax.digitCount - 1)
i = ULongMax.digitCount - 1;
else
i = X.digitCount;
unsigned long int j(i - O);
Z1 = toInt(X.digits + X.digitCount - i, i) /
toInt(divisor.digits + divisor.digitCount - j, j);
}
else
{
unsigned long int i(ULongMax.digitCount - 1);
unsigned long int j;
if (divisor.digitCount > ULongMax.digitCount - 2)
j = ULongMax.digitCount - 2;
else
j = divisor.digitCount;
Z1 = toInt(X.digits + X.digitCount - i, i) /
toInt(divisor.digits + divisor.digitCount - j, j);
Z1.shiftLeft(O - Z1.digitCount);
}
predictZ1:
R = (Z1 * divisor).Abs();
if (X >= R)
{
X = X - R;
quotient += Z1;
}
else
{
if (Z1.digitCount > 1)
Z1.shiftRight(1);
else
--Z1;
goto predictZ1;
}
}
remainder = X;
}
/* Returns the value of the specified unsigned char[] as long int. */
unsigned long int BigInt::toInt(unsigned char *digits, int n)
{
unsigned long int newInt(0L);
unsigned long int powerOf10(1);
for (int i(0); i < n; i++)
{
newInt += digits[i] * powerOf10;
powerOf10 *= 10;
}
return newInt;
}
/* Saves the sum of two unsigned char* shorter and longer into result.
* It must be nShorter <= nLonger. If doFill == true, it fills the
* remaining free places with zeroes (used in KaratsubaMultiply()).
* Returns true if there was an overflow at the end (meaning that
* the result.digitCount was longer.digitCount + 1. */
bool BigInt::add(unsigned char *shorter, unsigned long int nShorter,
unsigned char *longer, unsigned long int nLonger,
unsigned char *result, int nResult, bool doFill)
{
//single digitwise sum and carry
unsigned char subSum(0);
unsigned char subCarry(0);
//count the digits
unsigned long int i(0L);
//add the digits
for (; i < nShorter; i++)
{
subSum = longer[i] + shorter[i] + subCarry;
subCarry = subSum / 10;
result[i] = subSum % 10;
}
for (; i < nLonger; i++)
{
subSum = longer[i] + subCarry;
subCarry = subSum / 10;
result[i] = subSum % 10;
}
if (doFill)
std::fill_n(result + i, nResult - i, 0);
if (subCarry)
{
result[i++] = 1;
return true;
}
return false;
}
/* Shifts the digits n places left. */
BigInt &BigInt::shiftLeft(unsigned long int n)
{
//if the number is 0, we won't shift it
if (EqualsZero())
return *this;
if (length <= digitCount + n + 2)
expandTo(digitCount + n + 2);
std::copy_backward(digits, digits + digitCount, digits + n + digitCount);
std::fill_n(digits, n, 0);
digitCount += n;
return *this;
}
/* Shifts the digits n places right. */
BigInt &BigInt::shiftRight(unsigned long int n)
{
if (n >= digitCount)
throw "Error BIGINT00: Overflow on shift right.";
std::copy_backward( digits + n, digits + digitCount,
digits + digitCount - n);
digitCount -= n;
return *this;
}
/* Expands the digits* to n. */
void BigInt::expandTo(unsigned long int n)
{
unsigned long int oldLength(length);
length = n;
unsigned char *oldDigits(digits);
try
{
digits = new unsigned char[length];
}
catch (...)
{
delete[] digits;
digits = oldDigits;
length = oldLength;
throw "Error BIGINT01: BigInt creation error (out of memory?).";
}
std::copy(oldDigits, oldDigits + digitCount, digits);
delete[] oldDigits;
}
BigInt::BigInt() : digits(0), length(10), digitCount(1), positive(true)
{
try
{
digits = new unsigned char[length];
}
catch (...)
{
delete[] digits;
throw "Error BIGINT02: BigInt creation error (out of memory?).";
}
//initialize to 0
digits[0] = 0;
}
BigInt::BigInt(const char * charNum) : digits(0)
{
digitCount = (unsigned long int) strlen(charNum);
if (digitCount == 0L)
throw "Error BIGINT03: Input string empty.";
else
{
switch (charNum[0])
{
case '+':
digitCount--;
charNum++;
positive = true;
break;
case '-':
digitCount--;
charNum++;
positive = false;
break;
default:
positive = true;
}
}
//get rid of the leading zeroes
while (charNum[0] == '0')
{
charNum++;
digitCount --;
}
//check if the string contains only decimal digits
if (! BigInt::allCharsAreDigits(charNum, digitCount))
throw "Error BIGINT04: Input string contains characters"
" other than digits.";
//the input string was like ('+' or '-')"00...00\0"
if (charNum[0] == '\0')
{
digitCount = 1;
charNum--;
positive = true;
}
length = (unsigned long int)(digitCount * BigInt::FACTOR + 1);
try
{
digits = new unsigned char[length];
}
catch (...)
{
delete[] digits;
throw "Error BIGINT05: BigInt creation error (out of memory?).";
}
//copy the digits backwards to the new BigInt
std::reverse_copy(charNum, charNum + digitCount, digits);
//convert them to unsigned char
BigInt::char2uchar(digits, digitCount);
}
BigInt::BigInt(unsigned long int intNum) : digits(0)
{
positive = true;
//we don't know how many digits there are in intNum since
//sizeof(long int) is platform dependent (2^128 ~ 39 digits), so we'll
//first save them in a temporary unsigned char[], and later copy them
unsigned char tempDigits[40] = {0};
digitCount = int2uchar(intNum, tempDigits);
length = (unsigned long int)(digitCount * BigInt::FACTOR + 1);
try
{
digits = new unsigned char[length];
}
catch (...)
{
delete [] digits;
throw "Error BIGINT06: BigInt creation error (out of memory?).";
}
std::copy(tempDigits, tempDigits + digitCount, digits);
}
BigInt::BigInt(const std::string &str) : digits(0), length(10),
digitCount(1), positive(true)
{
try
{
digits = new unsigned char[length];
}
catch (...)
{
delete[] digits;
throw "Error BIGINT07: BigInt creation error (out of memory?).";
}
//initialize to 0
digits[0] = 0;
BigInt a(str.c_str());
*this = a;
}
BigInt::BigInt(const BigInt &rightNumber) : length(rightNumber.length),
digitCount(rightNumber.digitCount), positive(rightNumber.positive)
{
//make sure we have just enough space
if (length <= digitCount + 2 || length > (digitCount << 2))
length = (unsigned long int) (digitCount * BigInt::FACTOR + 1);
try
{
digits = new unsigned char[length];
}
catch (...)
{
delete[] digits;
throw "Error BIGINT08: BigInt creation error (out of memory?).";
}
std::copy(rightNumber.digits, rightNumber.digits + digitCount, digits);
}
BigInt::operator std::string() const
{
return ToString();
}
BigInt &BigInt::operator =(const BigInt &rightNumber)
{
//if the right-hand operand is longer than the left-hand one or
//twice as small
if (length < rightNumber.digitCount + 2 ||
length > (rightNumber.digitCount << 2))
{
length = (unsigned long int)
(rightNumber.digitCount * BigInt::FACTOR + 1);
//keep a pointer to the current digits, in case
//there is not enough memory to allocate for the new digits
unsigned char *tempDigits(digits);
try
{
digits = new unsigned char[length];
}
catch (...)
{
//clean up the mess
delete[] digits;
//restore the digits
digits = tempDigits;
throw "Error BIGINT09: BigInt assignment error (out of memory?).";
}
//it turns out we don't need this any more
delete[] tempDigits;
}
//destructive self-assignment protection
else if (this == &rightNumber)
return *this;
//copy the values
digitCount = rightNumber.digitCount;
positive = rightNumber.positive;
std::copy(rightNumber.digits, rightNumber.digits + digitCount, digits);
return *this;
}
std::ostream &operator <<(std::ostream &cout, const BigInt &number)
{
if (!number.positive)
cout << '-';
for (int i = number.digitCount - 1; i >= 0; i--)
cout << (int(number.digits[i]));
return cout;
}
std::istream &operator >>(std::istream &cin, BigInt &number)
{
std::string newNumber;
std::cin >> std::ws >> newNumber;
if (!cin)
{
cin.clear();
throw "Error BIGINT16: Input stream error.";
}
number = newNumber;
return cin;
}
bool operator <(const BigInt &a, const BigInt &b)
{
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount,
a.positive, b.positive) == 2)
return true;
return false;
}
bool operator <=(const BigInt &a, const BigInt &b)
{
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount,
a.positive, b.positive) == 1)
return false;
return true;
}
bool operator >(const BigInt &a, const BigInt &b)
{
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount,
a.positive, b.positive) == 1)
return true;
return false;
}
bool operator >=(const BigInt &a, const BigInt &b)
{
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount,
a.positive, b.positive) == 2)
return false;
return true;
}
bool operator ==(const BigInt &a, const BigInt &b)
{
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount,
a.positive, b.positive))
return false;
return true;
}
bool operator !=(const BigInt &a, const BigInt &b)
{
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount,
a.positive, b.positive))
return true;
return false;
}
BigInt operator +(const BigInt &a, const BigInt &b)
{
if (a.positive && !b.positive)
return a - (-b);
else if (!a.positive && b.positive)
return b - (-a);
//find the longer of the operands
const BigInt *shorter, *longer;
if (BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount) == 1)
{
shorter = &b;
longer = &a;
}
else
{
shorter = &a;
longer = &b;
}
//Copies the "positive" field too. That is good because now either a and b
//are both positive or both negative, so the result has the same sign.
BigInt sum(*longer);
bool overflow = BigInt::add(shorter->digits, shorter->digitCount,
longer->digits, longer->digitCount,
sum.digits, 0, false);
if (overflow)
sum.digitCount++;
return sum;
}
/*overloaded ++ operator, prefix version*/
BigInt &BigInt::operator++()
{
return *this += BigIntOne;
}
/*overloaded ++ operator, postfix version*/
BigInt BigInt::operator++(int)
{
BigInt temp(*this);
*this += BigIntOne;
return temp;
}
BigInt &BigInt::operator+=(const BigInt &number)
{
*this = *this + number;
return *this;
}
BigInt BigInt::operator-() const
{
if (!this->EqualsZero())
{
BigInt temp(*this);
temp.positive = !temp.positive;
return temp;
}
return *this;
}
BigInt operator-(const BigInt &a, const BigInt &b)
{
if (!a.positive && b.positive)
{
return -((-a) + b);
}
if (a.positive && !b.positive)
{
return a + (-b);
}
const int cmpAbs = BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount);
//if a == b
if ((cmpAbs == 0) && (a.positive == b.positive))
{
return BigIntZero;
}
//find the longer of the operands (bigger by absolute value)
const BigInt *shorter, *longer;
bool sign(a.positive); //the sign of the result
if (cmpAbs != 2) // a >= b
{
shorter = &b;
longer = &a;
}
else
{
shorter = &a;
longer = &b;
sign = !sign;
}
BigInt result(*longer);
result.positive = sign;
//temporary variable
const BigInt shorterCopy(*shorter);
//often used temporary variable
const int rDigits(shorterCopy.digitCount);
//in case of longer digitwise carry, overflow = true
bool overflow(false);
for (int i(0); i < rDigits; i++)
{
overflow = (longer->digits[i] - shorterCopy.digits[i]) < 0;
if (overflow)
{
result.digits[i] = longer->digits[i] + 10 - shorterCopy.digits[i];
//transfer carry
shorterCopy.digits[i+1]++;
}
else
//make the digitwise subtraction
result.digits[i] = longer->digits[i] - shorterCopy.digits[i];
}
//if there is a carry and the following digit is 0 => there will
//be a carry again...
if (overflow && result.digits[rDigits] == 0)
{
result.digits[rDigits] = 9;
int i(rDigits + 1);
for (; result.digits[i] == 0; i++)
result.digits[i] = 9;
result.digits[i] -= 1;
} //there is a carry but there will be no more carries
else if (overflow)
result.digits[rDigits]--;
//get rid of the leading zeroes
for (int i(result.digitCount - 1); i > 0; i--)
if (result.digits[i] == 0)
result.digitCount--;
else
break;
return result;
}
/*overloaded -- operator, prefix version*/
BigInt &BigInt::operator--()
{
*this = *this - BigIntOne;
return *this;
}
/*overloaded -- operator, postfix version*/
BigInt BigInt::operator--(int)
{
BigInt temp(*this);
*this = *this - BigIntOne;
return temp;
}
BigInt &BigInt::operator-=(const BigInt &number)
{
*this = *this - number;
return *this;
}
BigInt operator*(const BigInt &a, const BigInt &b)
{
if (a.EqualsZero() || b.EqualsZero())
return BigIntZero;
//this controls wether Karatsuba algorithm will be used for multiplication
#ifdef KARATSUBA
int n((a.digitCount < b.digitCount ? b.digitCount : a.digitCount));
//we will use a temporary buffer for multiplication
unsigned char *buffer(0);
try
{
buffer = new unsigned char[11 * n];
}
catch (...)
{
delete[] buffer;
throw "Error BIGINT10: Not enough memory?";
}
unsigned char *bb(buffer + n), *bc(bb + n);
std::copy(a.digits, a.digits + a.digitCount, buffer);
std::fill(buffer + a.digitCount, buffer + n, 0);
std::copy(b.digits, b.digits + b.digitCount, bb);
std::fill(bb + b.digitCount, bb + n, 0);
BigInt::karatsubaMultiply(buffer, bb, n, bc);
n <<= 1;
#else
int n = a.digitCount + b.digitCount;
unsigned char *buffer = new unsigned char[n];
BigInt::longMultiply( a.digits, a.digitCount,
b.digits, b.digitCount, buffer);
unsigned char *bc(buffer);
#endif /*KARATSUBA*/
BigInt bigIntResult; //we assume it's a positive number
if (a.positive != b.positive)
bigIntResult.positive = false;
bigIntResult.expandTo(n + 10);
std::copy(bc, bc + n, bigIntResult.digits);
for (unsigned long int i = n - 1; i > 0L; i--)
{
if (bigIntResult.digits[i])
{
bigIntResult.digitCount = i + 1;
break;
}
}
delete[] buffer;
return bigIntResult;
}
BigInt &BigInt::operator*=(const BigInt &number)
{
*this = *this * number;
return *this;
}
BigInt operator /(const BigInt &a, const BigInt &b)
{
if (b.EqualsZero())
throw "Error BIGINT11: Attempt to divide by zero.";
//we don't want to call this function twice
int comparison(BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount));
//if a == 0 or |a| < |b|
if (a.EqualsZero() || comparison == 2)
return BigIntZero;
//if a == b
if (comparison == 0)
{
if (a.positive == b.positive)
return BigIntOne;
else
return -BigIntOne;
}
BigInt quotient, remainder;
BigInt::divide(a, b, quotient, remainder);
//adjust the sign (positive by default)
if (a.positive != b.positive)
quotient.positive = false;
return quotient;
}
BigInt &BigInt::operator /=(const BigInt &number)
{
*this = *this / number;
return *this;
}
BigInt operator%(const BigInt &a, const BigInt &b)
{
if (b.EqualsZero())
throw "Error BIGINT12: Attempt to divide by zero.";
//we don't want to call this function twice
int comparison(BigInt::compareNumbers( a.digits, a.digitCount,
b.digits, b.digitCount));
//a == b
if (comparison == 0)
return BigIntZero;
//if a < b
if (comparison == 2 && a.positive)
return a;
BigInt quotient, remainder;
BigInt::divide(a, b, quotient, remainder);
if (!a.positive && !remainder.EqualsZero())
remainder.positive = false;
return remainder;
}
BigInt &BigInt::operator%=(const BigInt &number)
{
*this = *this % number;
return *this;
}
/* Returns *this to the power of n
* using the fast Square and Multiply algorithm. */
BigInt BigInt::GetPower(unsigned long int n) const
{
BigInt result(BigIntOne);
BigInt base(*this);
while (n)
{
//if n is odd
if (n & 1)
{
result = result * base;
n--;
}
n /= 2;
base = base * base;
}
//number was negative and the exponent is odd, the result is negative
if (!positive && (n & 1))
result.positive = false;
return result;
}
/* *this = *this to the power of n. */
void BigInt::SetPower(unsigned long int n)
{
*this = (*this).GetPower(n);
}
/* Returns *this to the power of n
* using the fast Square and Multiply algorithm. */
BigInt BigInt::GetPower(BigInt n) const
{
if (!n.positive)
throw "Error BIGINT13: Negative exponents not supported!";
BigInt result(BigIntOne);
BigInt base(*this);
BigInt bigIntTwo(BigIntOne + BigIntOne);
while (!n.EqualsZero())
{
//if n is odd
if (n.digits[0] & 1)
{
result = result * base;
n--;
}
n = n / bigIntTwo;
base = base * base;
}
//number was negative and the exponent is odd, the result is negative
if (!positive && (n.digits[0] & 1))
result.positive = false;
return result;
}
/* *this = *this to the power of n. */
void BigInt::SetPower(BigInt n)
{
*this = (*this).GetPower(n);
}
/* Returns (*this to the power of b) mod n. */
BigInt BigInt::GetPowerMod(const BigInt &b, const BigInt &n) const
{
BigInt a(*this);
a.SetPowerMod(b, n);
return a;
}
/* *this = (*this to the power of b) mod n. */
void BigInt::SetPowerMod(const BigInt &b, const BigInt &n)
{
if (!b.positive)
throw "Error BIGINT14: Negative exponent not supported.";
//we will need this value later, since *this is going to change
const BigInt a(*this);
//temporary variables
BigInt bCopy(b), q, r;
const BigInt two(BigIntOne + BigIntOne);
//first we will find the binary representation of b
std::vector bits;
while (!bCopy.EqualsZero())
{
BigInt::divide(bCopy, two, q, r);
bCopy = q;
if (r.EqualsZero())
bits.push_back(false);
else
bits.push_back(true);
}
//do the exponentiating
*this = BigIntOne;
for (int i = (int) bits.size() - 1; i >= 0; i--)
{
BigInt::divide(*this * *this, n, q, *this);
if (bits[i])
BigInt::divide(*this * a, n, q, *this);
}
}
/* Returns the nth digit read-only, zero-based, right-to-left. */
unsigned char BigInt::GetDigit(unsigned long int index) const
{
if (index >= digitCount)
throw "Error BIGINT15: Index out of range.";
return digits[index];
}
/* Returns the nth digit, zero-based, right-to-left. */
void BigInt::SetDigit(unsigned long int index, unsigned char value)
{
if (index >= digitCount)
throw "Error BIGINT15: Index out of range.";
if (value > 9)
throw "Error BIGINT16: Digit value out of range.";
digits[index] = value;
}
/* Returns the value of BigInt as std::string. */
std::string BigInt::ToString(bool forceSign) const
{
(void)forceSign; // avoid unused warning
std::string number;
if (!positive)
number.push_back('-');
for (int i = digitCount - 1; i >= 0; i--)
number.push_back(char(digits[i]) + '0');
return number;
}
/* Returns the absolute value. */
BigInt BigInt::Abs() const
{
return ((positive) ? *this : -(*this));
}