I have a very large number represented by a string. Say String n = "64772890123784224827" . I want to divide the number by 3 efficiently. How can I do it? Some implementations are given below which can find out remainder. But how to get the quotient efficiently?
In Java, the number can be represented with BigInteger and the division operation can be done on BigInteger. But that takes too much time. Please help me find out the efficient way to divide this large number by 3.
Well following is a very basic implementation to find out the remainder:
#include <bits/stdc++.h>
using namespace std;
int divideByN(string, int);
int main()
{
string str = "-64772890123784224827";
//string str = "21";
int N = 3;
int remainder = divideByN(str, N);
cout << "\nThe remainder = " << remainder << endl;
return 0;
}
int divideByN(string s, int n)
{
int carry = 0;
int remainder = 0;
for(int i = 0; i < s.size(); i++)
{
if(i == 0 && s.at(i) == '-')
{
cout << "-";
continue;
}
//Check for any illegal characters here. If any, throw exception.
int tmp = (s.at(i) - '0') + remainder * carry;
cout << (tmp / n);
if(tmp % n == 0)
{
carry = 0;
remainder = 0;
}
else
{
remainder = tmp % n;
carry = 10;
}
}
return remainder;
}
Based on some good answers, here is a minimal implementation using lookup table to find out the remainder:
#include <bits/stdc++.h>
using namespace std;
int divideByN_Lookup(string, int);
int lookup[] = { 0, 1, 2, 0, 1, 2, 0, 1, 2, 0 }; //lookup considering 3 as divisor.
int main() {
string str = "64772890123784224827";
int N = 3;
int remaninder_lookup = divideByN_Lookup(str, N);
cout << "Look up implementation of remainder = " << remaninder_lookup
<< endl;
return 0;
}
int divideByN_Lookup(string s, int n) {
int rem = 0;
int start = 0;
if (s.at(start) == '-')
start = 1;
for (unsigned int i = start; i < s.size(); i++)
rem = (rem + lookup[s.at(i) - '0']) % n;
return rem;
}
What about quotient? I know I can process all characters one by one and add the quotient to a char array or string. But what is the most efficient way to find out the quotient?
If all you need is the remainder after dividing by 3, make a look up table or function that converts each string character digit to an int, which is the remainder when you divide the digit by 3, and add up the ints across all digits in the string, and then there is a fact that the remainder when you divide your original number by 3 is the same as the remainder when you divide the sum of digits by 3. It would be virtually impossible to not be able to fit the sum of 0,1,2 values into a 32 or 64 byte integer. The input would simply have to be too large. And if it does start to become almost too large when you're summing the digits, then just take the remainder when you divide by 3 when you start getting close to the maximum value for an int. Then you can process any length number, using very few division remainder (modulus) operations (which is important because they are much slower than addition).
The reason why the sum-of-digits fact is true is that the remainder when you divide any power of 10 by 3 is always 1.
This is actually very simple. Since every power of 10 is equivalent to 1 modulo 3, all you have to do is add the digits together. The resulting number will have the same remainder when divided by 3 as the original large number.
For example:
3141592654 % 3 = 1
3+1+4+1+5+9+2+6+5+4 = 40
40 % 3 = 1
I think you can start processing from the left, dividing each digit by 3, and adding the remainder to the next one.
In your example you divide the 6, write 2, then divide the 4, write 1 and add the remainder of 1 to the 7 to get 17... Divide the 17... and so on.
EDIT:
I've just verified my solution works using this code. Note you may get a leading zero:
int main( int argc, char* argv[] )
{
int x = 0;
for( char* p = argv[1]; *p; p++ ) {
int d = x*10 + *p-'0';
printf("%d", d/3);
x = d % 3;
}
printf("\n");
return 0;
}
It's not optimal using so many divs and muls, but CS-wise it's O(N) ;-)
I wrote this a while ago.. Doesn't seem slow :S
I've only included the necessary parts for "division"..
#include <string>
#include <cstring>
#include <algorithm>
#include <stdexcept>
#include <iostream>
class BigInteger
{
public:
char sign;
std::string digits;
const std::size_t base = 10;
short toDigit(std::size_t index) const {return index >= 0 && index < digits.size() ? digits[index] - '0' : 0;}
protected:
void Normalise();
BigInteger& divide(const BigInteger &Divisor, BigInteger* Remainder);
public:
BigInteger();
BigInteger(const std::string &value);
inline bool isNegative() const {return sign == '-';}
inline bool isPositive() const {return sign == '+';}
inline bool isNeutral() const {return sign == '~';}
inline std::string toString() const
{
std::string digits = this->digits;
std::reverse(digits.begin(), digits.end());
if (!isNeutral())
{
std::string sign;
sign += this->sign;
return sign + digits;
}
return digits;
}
bool operator < (const BigInteger &other) const;
bool operator > (const BigInteger &other) const;
bool operator <= (const BigInteger &other) const;
bool operator >= (const BigInteger &other) const;
bool operator == (const BigInteger &other) const;
bool operator != (const BigInteger &other) const;
BigInteger& operator /= (const BigInteger &other);
BigInteger operator / (const BigInteger &other) const;
BigInteger Remainder(const BigInteger &other) const;
};
BigInteger::BigInteger() : sign('~'), digits(1, '0') {}
BigInteger::BigInteger(const std::string &value) : sign('~'), digits(value)
{
sign = digits.empty() ? '~' : digits[0] == '-' ? '-' : '+';
if (digits[0] == '+' || digits[0] == '-') digits.erase(0, 1);
std::reverse(digits.begin(), digits.end());
Normalise();
for (std::size_t I = 0; I < digits.size(); ++I)
{
if (!isdigit(digits[I]))
{
sign = '~';
digits = "0";
break;
}
}
}
void BigInteger::Normalise()
{
for (int I = digits.size() - 1; I >= 0; --I)
{
if (digits[I] != '0') break;
digits.erase(I, 1);
}
if (digits.empty())
{
digits = "0";
sign = '~';
}
}
bool BigInteger::operator < (const BigInteger &other) const
{
if (isNeutral() || other.isNeutral())
{
return isNeutral() ? other.isPositive() : isNegative();
}
if (sign != other.sign)
{
return isNegative();
}
if (digits.size() != other.digits.size())
{
return (digits.size() < other.digits.size() && isPositive()) || (digits.size() > other.digits.size() && isNegative());
}
for (int I = digits.size() - 1; I >= 0; --I)
{
if (toDigit(I) < other.toDigit(I))
return isPositive();
if (toDigit(I) > other.toDigit(I))
return isNegative();
}
return false;
}
bool BigInteger::operator > (const BigInteger &other) const
{
if (isNeutral() || other.isNeutral())
{
return isNeutral() ? other.isNegative() : isPositive();
}
if ((sign != other.sign) && !(isNeutral() || other.isNeutral()))
{
return isPositive();
}
if (digits.size() != other.digits.size())
{
return (digits.size() > other.digits.size() && isPositive()) || (digits.size() < other.digits.size() && isNegative());
}
for (int I = digits.size() - 1; I >= 0; --I)
{
if (toDigit(I) > other.toDigit(I))
return isPositive();
if (toDigit(I) < other.toDigit(I))
return isNegative();
}
return false;
}
bool BigInteger::operator <= (const BigInteger &other) const
{
return (*this < other) || (*this == other);
}
bool BigInteger::operator >= (const BigInteger &other) const
{
return (*this > other) || (*this == other);
}
bool BigInteger::operator == (const BigInteger &other) const
{
if (sign != other.sign || digits.size() != other.digits.size())
return false;
for (int I = digits.size() - 1; I >= 0; --I)
{
if (toDigit(I) != other.toDigit(I))
return false;
}
return true;
}
bool BigInteger::operator != (const BigInteger &other) const
{
return !(*this == other);
}
BigInteger& BigInteger::divide(const BigInteger &Divisor, BigInteger* Remainder)
{
if (Divisor.isNeutral())
{
throw std::overflow_error("Division By Zero Exception.");
}
char rem_sign = sign;
bool neg_res = sign != Divisor.sign;
if (!isNeutral()) sign = '+';
if (*this < Divisor)
{
if (Remainder)
{
Remainder->sign = this->sign;
Remainder->digits = this->digits;
}
sign = '~';
digits = "0";
return *this;
}
if (this == &Divisor)
{
if (Remainder)
{
Remainder->sign = this->sign;
Remainder->digits = this->digits;
}
sign = '+';
digits = "1";
return *this;
}
BigInteger Dvd(*this);
BigInteger Dvr(Divisor);
BigInteger Quotient("0");
Dvr.sign = '+';
std::size_t len = std::max(Dvd.digits.size(), Dvr.digits.size());
std::size_t diff = std::max(Dvd.digits.size(), Dvr.digits.size()) - std::min(Dvd.digits.size(), Dvr.digits.size());
std::size_t offset = len - diff - 1;
Dvd.digits.resize(len, '0');
Dvr.digits.resize(len, '0');
Quotient.digits.resize(len, '0');
memmove(&Dvr.digits[diff], &Dvr.digits[0], len - diff);
memset(&Dvr.digits[0], '0', diff);
while(offset < len)
{
while (Dvd >= Dvr)
{
int borrow = 0, total = 0;
for (std::size_t I = 0; I < len; ++I)
{
total = Dvd.toDigit(I) - Dvr.toDigit(I) - borrow;
borrow = 0;
if (total < 0)
{
borrow = 1;
total += 10;
}
Dvd.digits[I] = total + '0';
}
Quotient.digits[len - offset - 1]++;
}
if (Remainder && offset == len - 1)
{
Remainder->digits = Dvd.digits;
Remainder->sign = rem_sign;
Remainder->Normalise();
if (Remainder == this)
{
return *this;
}
}
memmove(&Dvr.digits[0], &Dvr.digits[1], len - 1);
memset(&Dvr.digits[len - 1], '0', 1);
++offset;
}
Quotient.sign = neg_res ? '-' : '+';
Quotient.Normalise();
this->sign = Quotient.sign;
this->digits = Quotient.digits;
return *this;
}
BigInteger& BigInteger::operator /= (const BigInteger &other)
{
return divide(other, nullptr);
}
BigInteger BigInteger::operator / (const BigInteger &other) const
{
return BigInteger(*this) /= other;
}
BigInteger BigInteger::Remainder(const BigInteger &other) const
{
BigInteger remainder;
BigInteger(*this).divide(other, &remainder);
return remainder;
}
int main()
{
BigInteger a{"-64772890123784224827"};
BigInteger b{"3"};
BigInteger result = a/b;
std::cout<<result.toString();
}
Related
This weekend I followed the wiki to implement the basic big integer multiplication. I use the Toom-3 algorithm to implement. But the time spends unexpectedly at the beginning is slower than long multiplication(grade-school multiplication) and gone forever. I hope the program can over the grade-school multiplication within 500 digits, How should I do, please?
I try to optimize, I reserve the vector capacity and remove the supernumerary code. But is not very effective.
And should I use the vector<long long> to be my base digits?
The whole source code in Github:
typedef long long BigIntBase;
typedef vector<BigIntBase> BigIntDigits;
// ceil(numeric_limits<BigIntBase>::digits10 / 2.0) - 1;
static const int digit_base_len = 9;
// b
static const BigIntBase digit_base = 1000000000;
class BigInt {
public:
BigInt(int digits_capacity = 0, bool nega = false) {
negative = nega;
digits.reserve(digits_capacity);
}
BigInt(BigIntDigits _digits, bool nega = false) {
negative = nega;
digits = _digits;
}
BigInt(const span<const BigIntBase> &range, bool nega = false) {
negative = nega;
digits = BigIntDigits(range.begin(), range.end());
}
BigInt operator+(const BigInt &rhs) {
if ((*this).negative == rhs.negative)
return BigInt(plus((*this).digits, rhs.digits), (*this).negative);
if (greater((*this).digits, rhs.digits))
return BigInt(minus((*this).digits, rhs.digits), (*this).negative);
return BigInt(minus(rhs.digits, (*this).digits), rhs.negative);
}
BigInt operator-(const BigInt &rhs) { return *this + BigInt(rhs.digits, !rhs.negative); }
BigInt operator*(const BigInt &rhs) {
if ((*this).digits.empty() || rhs.digits.empty()) {
return BigInt();
} else if ((*this).digits.size() == 1 && rhs.digits.size() == 1) {
BigIntBase val = (*this).digits[0] * rhs.digits[0];
return BigInt(val < digit_base ? BigIntDigits{val} : BigIntDigits{val % digit_base, val / digit_base}, (*this).negative ^ rhs.negative);
} else if ((*this).digits.size() == 1)
return BigInt(multiply(rhs, (*this).digits[0]).digits, (*this).negative ^ rhs.negative);
else if (rhs.digits.size() == 1)
return BigInt(multiply((*this), rhs.digits[0]).digits, (*this).negative ^ rhs.negative);
return BigInt(toom3(span((*this).digits), span(rhs.digits)), (*this).negative ^ rhs.negative);
}
string to_string() {
if (this->digits.empty())
return "0";
stringstream ss;
if (this->negative)
ss << "-";
ss << std::to_string(this->digits.back());
for (auto it = this->digits.rbegin() + 1; it != this->digits.rend(); ++it)
ss << setw(digit_base_len) << setfill('0') << std::to_string(*it);
return ss.str();
}
BigInt from_string(string s) {
digits.clear();
negative = s[0] == '-';
for (int pos = max(0, (int)s.size() - digit_base_len); pos >= 0; pos -= digit_base_len)
digits.push_back(stoll(s.substr(pos, digit_base_len)));
if (s.size() % digit_base_len)
digits.push_back(stoll(s.substr(0, s.size() % digit_base_len)));
return *this;
}
private:
bool negative;
BigIntDigits digits;
const span<const BigIntBase> toom3_slice_num(const span<const BigIntBase> &num, const int &n, const int &i) {
int begin = n * i;
if (begin < num.size()) {
const span<const BigIntBase> result = num.subspan(begin, min((int)num.size() - begin, i));
return result;
}
return span<const BigIntBase>();
}
BigIntDigits toom3(const span<const BigIntBase> &num1, const span<const BigIntBase> &num2) {
int i = ceil(max(num1.size() / 3.0, num2.size() / 3.0));
const span<const BigIntBase> m0 = toom3_slice_num(num1, 0, i);
const span<const BigIntBase> m1 = toom3_slice_num(num1, 1, i);
const span<const BigIntBase> m2 = toom3_slice_num(num1, 2, i);
const span<const BigIntBase> n0 = toom3_slice_num(num2, 0, i);
const span<const BigIntBase> n1 = toom3_slice_num(num2, 1, i);
const span<const BigIntBase> n2 = toom3_slice_num(num2, 2, i);
BigInt pt0 = plus(m0, m2);
BigInt pp0 = m0;
BigInt pp1 = plus(pt0.digits, m1);
BigInt pn1 = pt0 - m1;
BigInt pn2 = multiply(pn1 + m2, 2) - m0;
BigInt pin = m2;
BigInt qt0 = plus(n0, n2);
BigInt qp0 = n0;
BigInt qp1 = plus(qt0.digits, n1);
BigInt qn1 = qt0 - n1;
BigInt qn2 = multiply(qn1 + n2, 2) - n0;
BigInt qin = n2;
BigInt rp0 = pp0 * qp0;
BigInt rp1 = pp1 * qp1;
BigInt rn1 = pn1 * qn1;
BigInt rn2 = pn2 * qn2;
BigInt rin = pin * qin;
BigInt r0 = rp0;
BigInt r4 = rin;
BigInt r3 = divide(rn2 - rp1, 3);
BigInt r1 = divide(rp1 - rn1, 2);
BigInt r2 = rn1 - rp0;
r3 = divide(r2 - r3, 2) + multiply(rin, 2);
r2 = r2 + r1 - r4;
r1 = r1 - r3;
BigIntDigits result = r0.digits;
if (!r1.digits.empty()) {
shift_left(r1.digits, i);
result = plus(result, r1.digits);
}
if (!r2.digits.empty()) {
shift_left(r2.digits, i << 1);
result = plus(result, r2.digits);
}
if (!r3.digits.empty()) {
shift_left(r3.digits, i * 3);
result = plus(result, r3.digits);
}
if (!r4.digits.empty()) {
shift_left(r4.digits, i << 2);
result = plus(result, r4.digits);
}
return result;
}
BigIntDigits plus(const span<const BigIntBase> &lhs, const span<const BigIntBase> &rhs) {
if (lhs.empty())
return BigIntDigits(rhs.begin(), rhs.end());
if (rhs.empty())
return BigIntDigits(lhs.begin(), lhs.end());
int max_length = max(lhs.size(), rhs.size());
BigIntDigits result;
result.reserve(max_length + 1);
for (int w = 0; w < max_length; ++w)
result.push_back((lhs.size() > w ? lhs[w] : 0) + (rhs.size() > w ? rhs[w] : 0));
for (int w = 0; w < result.size() - 1; ++w) {
result[w + 1] += result[w] / digit_base;
result[w] %= digit_base;
}
if (result.back() >= digit_base) {
result.push_back(result.back() / digit_base);
result[result.size() - 2] %= digit_base;
}
return result;
}
BigIntDigits minus(const span<const BigIntBase> &lhs, const span<const BigIntBase> &rhs) {
if (lhs.empty())
return BigIntDigits(rhs.begin(), rhs.end());
if (rhs.empty())
return BigIntDigits(lhs.begin(), lhs.end());
BigIntDigits result;
result.reserve(lhs.size() + 1);
for (int w = 0; w < lhs.size(); ++w)
result.push_back((lhs.size() > w ? lhs[w] : 0) - (rhs.size() > w ? rhs[w] : 0));
for (int w = 0; w < result.size() - 1; ++w)
if (result[w] < 0) {
result[w + 1] -= 1;
result[w] += digit_base;
}
while (!result.empty() && !result.back())
result.pop_back();
return result;
}
void shift_left(BigIntDigits &lhs, const int n) {
if (!lhs.empty()) {
BigIntDigits zeros(n, 0);
lhs.insert(lhs.begin(), zeros.begin(), zeros.end());
}
}
BigInt divide(const BigInt &lhs, const int divisor) {
BigIntDigits reminder(lhs.digits);
BigInt result(lhs.digits.capacity(), lhs.negative);
for (int w = reminder.size() - 1; w >= 0; --w) {
result.digits.insert(result.digits.begin(), reminder[w] / divisor);
reminder[w - 1] += (reminder[w] % divisor) * digit_base;
}
while (!result.digits.empty() && !result.digits.back())
result.digits.pop_back();
return result;
}
BigInt multiply(const BigInt &lhs, const int multiplier) {
BigInt result(lhs.digits, lhs.negative);
for (int w = 0; w < result.digits.size(); ++w)
result.digits[w] *= multiplier;
for (int w = 0; w < result.digits.size(); ++w)
if (result.digits[w] >= digit_base) {
if (w + 1 == result.digits.size())
result.digits.push_back(result.digits[w] / digit_base);
else
result.digits[w + 1] += result.digits[w] / digit_base;
result.digits[w] %= digit_base;
}
return result;
}
bool greater(const BigIntDigits &lhs, const BigIntDigits &rhs) {
if (lhs.size() == rhs.size()) {
int w = lhs.size() - 1;
while (w >= 0 && lhs[w] == rhs[w])
--w;
return w >= 0 && lhs[w] > rhs[w];
} else
return lhs.size() > rhs.size();
}
};
Digits
Grade-school
Toom-3
10
4588
10003
50
24147
109084
100
52165
286535
150
92405
476275
200
172156
1076570
250
219599
1135946
300
320939
1530747
350
415655
1689745
400
498172
1937327
450
614467
2629886
500
863116
3184277
The problem is that you do a million allocations in among others toom3_slice_num, here you could use a std::span (or a std::pair of iterator to the actual part) as the number you give is a const. toom3 is also allocator hell.
The multiply might allocate 1 more time. Count the bits needed or just add 1 to the size.
And the vectors should be pmr (with appropriate allocator) for nearly lock free allocations.
All this is wasted if not compiled with -O2 or -O3.
I made a program for BigInteger in which I implemented Addition Subtraction and Karatsuba but it is giving wrong result. After several debuting I am not able to figure out the problem. Here is my code:-
//
// Created by bothra on 09/07/20.
//
#include <sstream>
#include"BigInteger.h++"
BigInteger::BigInteger(std::string a) {
digits = a;
}
BigInteger BigInteger::operator+(BigInteger othr) {
return add(othr);
}
BigInteger BigInteger::operator-(BigInteger othr) {
return Subtract(othr);
}
bool BigInteger::operator>(BigInteger othr) {
if(digits.size() > othr.digits.size()){
return true;
}
else if(digits.size() < othr.digits.size()){
return false;
}
else{
for(int i = digits.size() - 1;i >= 0;i--){
if(digits[i] < othr.digits[i]){
return false;
}
}
return true;
}
}
bool BigInteger::operator==(BigInteger othr) {
if(digits.size() == othr.digits.size()){
int flag = 0;
for(int i = digits.size() - 1;i >= 0;i--){
if(digits[i] < othr.digits[i]){
return false;
}
if(digits[i] > othr.digits[i]){
flag = 1;
}
}
if(flag == 0){
return true;
}
}
return false;
}
BigInteger::BigInteger(int a) {
}
BigInteger BigInteger::add(BigInteger other) {
if(sign == other.sign) {
int base = 10;
BigInteger ans("0");
std::string a = digits;
std::string b = other.digits;
std::string result = "";
int s = 0;
int i = a.size() - 1;
int j = b.size() - 1;
while (i >= 0 || j >= 0 || s == 1) {
s += ((i >= 0) ? a[i] - '0' : 0);
s += ((j >= 0) ? b[j] - '0' : 0);
result = char(s % base + '0') + result;
s /= base;
i--;
j--;
}
ans.sign = sign;
ans.digits = result;
return ans;
}
else{
return Subtract(other);
}
}
BigInteger BigInteger::MakeShifting(BigInteger a,int stepnum){
std::string shifted = a.digits;
for (int i = 0 ; i < stepnum ; i++)
shifted = shifted + '0';
return shifted;
}
int makeEqualLength(std::string &str1, std::string &str2)
{
int len1 = str1.size();
int len2 = str2.size();
if (len1 < len2)
{
for (int i = 0 ; i < len2 - len1 ; i++)
str1 = '0' + str1;
return len2;
}
else if (len1 > len2)
{
for (int i = 0 ; i < len1 - len2 ; i++)
str2 = '0' + str2;
}
return len1; // If len1 >= len2
}
std::string getString(char x)
{
std::string s(1, x);
return s;
}
std::string DecimalToBinary(long long int number)
{
std::string result = "";
int base = 10;
if (number <= 0){
return "0";
}
else{
int i = 0;
char temp;
while (number > 0){
long long int num= number % base;
temp = num + '0';
result = getString(temp) + result;
number = number / base;
i++;
}
return result;
}
}
BigInteger BigInteger::Subtract(BigInteger a)
{
if(a.sign != sign){
a.sign = sign;
BigInteger ans = add(a);
ans.sign = sign;
return ans;
}
if(*this > a) {
BigInteger ans("0");
std::string rhs = a.digits;
std::string lhs = digits;
int length = makeEqualLength(lhs, rhs);
int diff;
std::string result;
int base = 10;
for (int i = length - 1; i >= 0; i--) {
diff = (lhs[i] - '0') - (rhs[i] - '0');
if (diff >= 0) {
result = DecimalToBinary(diff) + result;
} else {
for (int j = i - 1; j >= 0; j--) {
lhs[j] = ((lhs[j] - '0') - 1) % 10 + '0';
if (lhs[j] != '1') {
break;
}
}
result = DecimalToBinary(diff + base) + result;
}
}
ans.sign = sign;
ans.digits = result;
return ans;
}
if(*this == a){
return BigInteger("0");
}
else{
BigInteger ans("0");
std::string rhs = digits;
std::string lhs = a.digits;
int length = makeEqualLength(lhs, rhs);
int diff;
std::string result;
int base = 79;
for (int i = length - 1; i >= 0; i--) {
diff = (lhs[i] - '0') - (rhs[i] - '0');
if (diff >= 0) {
result = DecimalToBinary(diff) + result;
} else {
for (int j = i - 1; j >= 0; j--) {
lhs[j] = ((lhs[j] - '0') - 1) % 10 + '0';
if (lhs[j] != '1') {
break;
}
}
result = DecimalToBinary(diff + base) + result;
}
}
ans.sign = a.sign;
ans.digits = result;
return ans;
}
}
BigInteger BigInteger::Multiply(BigInteger other)
{
std::string X = digits;
std::string Y = other.digits;
int n = makeEqualLength(X, Y);
if (n == 1) return BigInteger(DecimalToBinary((X[0] - '0') * (Y[0] - '0')));
int fh = n/2; // First half of string, floor(n/2)
int sh = (n-fh); // Second half of string, ceil(n/2)
// Find the first half and second half of first string.
std::string Xl = X.substr(0, fh);
std::string Xr = X.substr(fh, sh);
// Find the first half and second half of second string
std::string Yl = Y.substr(0, fh);
std::string Yr = Y.substr(fh, sh);
// Recursively calculate the three products of inputs of size n/2
BigInteger P1 = BigInteger(Xl).Multiply(BigInteger(Yl));
BigInteger P2 = BigInteger(Xr).Multiply(BigInteger(Yr));
BigInteger P3 = (BigInteger(Xl)+BigInteger(Xr)).Multiply(BigInteger(Yl) + BigInteger(Yr));
// return added string version
return (P2 + MakeShifting(P1,2*(n - n/2))) + (MakeShifting(P3 - (P1 + P2) , n - n/2));
}
and the header:
//
// Created by bothra on 09/07/20.
//
#ifndef BIGINTEGER_BIGINTEGER_H
#define BIGINTEGER_BIGINTEGER_H
#include<iostream>
class BigInteger{
public:
std::string digits;
bool sign = false;//false indicates positive
BigInteger(int a);
BigInteger(std::string a);
BigInteger operator + (BigInteger othr);
BigInteger operator - (BigInteger othr);
bool operator > (BigInteger othr);
bool operator ==(BigInteger othr);
BigInteger add(BigInteger other);
BigInteger MakeShifting(BigInteger a,int stepnum);
BigInteger Subtract(BigInteger other);
BigInteger Multiply(BigInteger other);
};
#endif //BIGINTEGER_BIGINTEGER_H
But this code Multiplication is not working . It is keep on giving incorrect answer.
For example here is a driver code:-
#include <iostream>
#include "BigInteger.h++"
int main() {
BigInteger a("429");
BigInteger b("429");
a = a.Multiply(b);
std::cout << a.digits;
return 0;
}
Here it does 429 * 429 :
Output : 1397541
Output should have been : 184041
Please help me out.
Thanks in advance
I've been trying to solve this problem (from school) for just about a week now. We're given two numbers, from -(10^100000) to +that.
Of course the simplest solution is to implement written addition, so that's what I did. I decided, that I would store the numbers as strings, using two functions:
int ti(char a) { // changes char to int
int output = a - 48;
return output;
}
char tc(int a) { // changes int to char
char output = a + 48;
return output;
}
This way I can store negative digits, like -2. With that in mind I implemented a toMinus function:
void toMinus(std::string &a) { // 123 -> -1 -2 -3
for (auto &x : a) {
x = tc(-ti(x));
}
}
I also created a changeSize function, which adds 0 to the beginning of the number until they are both their max size + 1 and removeZeros, which removes leading zeros:
void changeSize(std::string &a, std::string &b) {
size_t exp_size = std::max(a.size(), b.size()) + 2;
while (a.size() != exp_size) {
a = '0' + a;
}
while (b.size() != exp_size) {
b = '0' + b;
}
}
void removeZeros(std::string &a) {
int i = 0;
for (; i < a.size(); i++) {
if (a[i] != '0') {
break;
}
}
a.erase(0, i);
if (a.size() == 0) {
a = "0";
}
}
After all that, I created the main add() function:
std::string add(std::string &a, std::string &b) {
bool neg[2] = {false, false};
bool out_negative = false;
if (a[0] == '-') {
neg[0] = true;
a.erase(0, 1);
}
if (b[0] == '-') {
neg[1] = true;
b.erase(0, 1);
}
changeSize(a, b);
if (neg[0] && !(neg[1] && neg[0])) {
toMinus(a);
}
if(neg[1] && !(neg[1] && neg[0])) {
toMinus(b);
}
if (neg[1] && neg[0]) {
out_negative = true;
}
// Addition
for (int i = a.size() - 1; i > 0; i--) {
int _a = ti(a[i]);
int _b = ti(b[i]);
int out = _a + _b;
if (out >= 10) {
a[i - 1] += out / 10;
} else if (out < 0) {
if (abs(out) < 10) {
a[i - 1]--;
} else {
a[i - 1] += abs(out) / 10;
}
if (i != 1)
out += 10;
}
a[i] = tc(abs(out % 10));
}
if (ti(a[0]) == -1) { // Overflow
out_negative = true;
a[0] = '0';
a[1]--;
for (int i = 2; i < a.size(); i++) {
if (i == a.size() - 1) {
a[i] = tc(10 - ti(a[i]));
} else {
a[i] = tc(9 - ti(a[i]));
}
}
}
if (neg[0] && neg[1]) {
out_negative = true;
}
removeZeros(a);
if (out_negative) {
a = '-' + a;
}
return a;
}
This program works in most cases, although our school checker found that it doesn't - like instead of
-4400547114413430129608370706728634555709161366260921095898099024156859909714382493551072616612065064
it returned
-4400547114413430129608370706728634555709161366260921095698099024156859909714382493551072616612065064
I can't find what the problem is. Please help and thank you in advance.
Full code on pastebin
While I think your overall approach is totally reasonable for this problem, your implementation seems a bit too complicated. Trying to solve this myself, I came up with this:
#include <iostream>
#include <limits>
#include <random>
#include <string>
bool greater(const std::string& a, const std::string& b)
{
if (a.length() == b.length()) return a > b;
return a.length() > b.length();
}
std::string add(std::string a, std::string b)
{
std::string out;
bool aNeg = a[0] == '-';
if (aNeg) a.erase(0, 1);
bool bNeg = b[0] == '-';
if (bNeg) b.erase(0, 1);
bool resNeg = aNeg && bNeg;
if (aNeg ^ bNeg && (aNeg && greater(a, b) || bNeg && greater(b, a)))
{
resNeg = true;
std::swap(a, b);
}
int i = a.length() - 1;
int j = b.length() - 1;
int carry = 0;
while (i >= 0 || j >= 0)
{
const int digitA = (i >= 0) ? a[i] - '0' : 0;
const int digitB = (j >= 0) ? b[j] - '0' : 0;
const int sum = (aNeg == bNeg ? digitA + digitB : (bNeg ? digitA - digitB : digitB - digitA)) + carry;
carry = 0;
if (sum >= 10) carry = 1;
else if (sum < 0) carry = -1;
out = std::to_string((sum + 20) % 10) + out;
i--;
j--;
}
if (carry) out = '1' + out;
while (out[0] == '0') out.erase(0, 1);
if (resNeg) out = '-' + out;
return out;
}
void test()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(-std::numeric_limits<int32_t>::max(), std::numeric_limits<int32_t>::max());
for (int i = 0; i < 1000000; ++i)
{
const int64_t a = dis(gen);
const int64_t b = dis(gen);
const auto expected = std::to_string(a + b);
const auto actual = add(std::to_string(a), std::to_string(b));
if (actual != expected) {
std::cout << "mismatch expected: " << expected << std::endl;
std::cout << "mismatch actual : " << actual << std::endl;
std::cout << " a: " << a << std::endl;
std::cout << " b: " << b << std::endl;
}
}
}
int main()
{
test();
}
It can potentially be further optimized, but the main points are:
If the sign of both numbers is the same, we can do simple written addition. If both are negative, we simply prepend - at the end.
If the signs are different, we do written subtraction. If the minuend is greater than the subtrahend, there's no issue, we know that the result will be positive. If, however, the subtrahend is greater, we have to reformulate the problem. For example, 123 - 234 we would formulate as -(234 - 123). The inner part we can solve using regular written subtraction, after which we prepend -.
I test this with random numbers for which we can calculate the correct result using regular integer arithmetic. Since it doesn't fail for those, I'm pretty confident it also works correctly for larger inputs. An approach like this could also help you uncover cases where your implementation fails.
Other than that, I think you should use a known failing case with a debugger or simply print statements for the intermediate steps to see where it fails. The only small differences in the failing example you posted could point at some issue with handling a carry-over.
How can i store a big number in a variable and use a for loop?
I have a very big number 75472202764752234070123900087933251 and i need to loop from 0 to this number!
Is it even possible to do this? how much time will it take to end?
EDIT: i am trying to solve a hard problem by brute force. its a combination problem.the bruteforcing cases may reach 470C450.
so i guess i should use a different algorithm...
This might take
0.23 x 10^23 years if C++ processed 100,000 loops per second :|
http://www.wolframalpha.com/input/?i=75472202764752234070123900087933251%2F%28100000*1*3600*24*365%29
It looks that this number fits into 128 bit. So you could use a modern system and a modern compiler that implements such numbers. This would e.g be the case for a 64bit linux system with gcc as a compiler. This has something like __uint128_t that you could use.
Obviously you can't use such a variable as a for-loop variable, others have give you the calculations. But you could use it to store some of your calculations.
Well, you would need an implementation that can handle at least a subset of the initialization, boolean, and arithmetic functions on very large integers. Something like: https://mattmccutchen.net/bigint/.
For something that would give a bit better performance than a general large integer math library, you could use specialized operations specifically to allow use of a large integer as a counter. For an example of this, see dewtell's updated answer to this question.
As for it being possible for you to loop from 0 to that number: well, yes, it is possible to write the code for it with one of the above solutions, but I think the answer is no, you personally will not be able to do it because you will not be alive to see it finish.
[edit: Yes, I would definitely recommend you find a different algorithm. :D]
If you need to loop a certain number of times, and that number is greater than 2^64, just use while(1) because your computer will break before it counts up to 2^64 anyway.
There's no need for a complete bignum package - if all you need is a loop counter, here's a simple byte counter that uses an array of bytes as a counter. It stops when the byte array wraps around to all zeros again. If you wanted to count to some other value than 2^(bytesUsed*CHAR_BITS), you could just compute the two's complement value of the negative of the number of iterations you wanted, and let it count up to 0, keeping in mind that bytes[0] is the low-order byte (or use the positive value and count down instead of up).
#include <stdio.h>
#define MAXBYTES 20
/* Simple byte counter - note it uses argc as # of bytes to use for convenience */
int main(int argc, char **argv) {
unsigned char bytes[MAXBYTES];
const int bytesUsed = argc < MAXBYTES? argc : MAXBYTES;
int i;
unsigned long counter = (unsigned long)-1; /* to give loop something to do */
for (i = 0; i < bytesUsed; i++) bytes[i] = 0; /* Initialize bytes */
do {
for (i = 0; i < bytesUsed && !++bytes[i]; i++) ; /* NULL BODY - this is the byte counter */
counter++;
} while (i < bytesUsed);
printf("With %d bytes used, final counter value = %lu\n", bytesUsed, counter);
}
Run times for the first 4 values (under Cygwin, on a Lenovo T61):
$ time ./bytecounter
With 1 bytes used, final counter value = 255
real 0m0.078s
user 0m0.031s
sys 0m0.046s
$ time ./bytecounter a
With 2 bytes used, final counter value = 65535
real 0m0.063s
user 0m0.031s
sys 0m0.031s
$ time ./bytecounter a a
With 3 bytes used, final counter value = 16777215
real 0m0.125s
user 0m0.015s
sys 0m0.046s
$ time ./bytecounter a a a
With 4 bytes used, final counter value = 4294967295
real 0m6.578s
user 0m0.015s
sys 0m0.047s
At this rate, five bytes should take around half an hour, and six bytes should take the better part of a week. Of course the counter value will be inaccurate for those - it's mostly just there to verify the number of iterations for the smaller byte values and give the loop something to do.
Edit: And here's the time for five bytes, around half an hour as I predicted:
$ time ./bytecounter a a a a
With 5 bytes used, final counter value = 4294967295
real 27m22.184s
user 0m0.015s
sys 0m0.062s
Ok, here's code to take an arbitrary decimal number passed as the first arg and count down from it to zero. I set it up to allow the counter to use different size elements (just change the typedef for COUNTER_BASE), but it turns out that bytes are actually somewhat faster than either short or long on my system.
#include <stdio.h>
#include <limits.h> // defines CHAR_BIT
#include <ctype.h>
#include <vector>
using std::vector;
typedef unsigned char COUNTER_BASE;
typedef vector<COUNTER_BASE> COUNTER;
typedef vector<unsigned char> BYTEVEC;
const unsigned long byteMask = (~0ul) << CHAR_BIT;
const size_t MAXBYTES=20;
void mult10(BYTEVEC &val) {
// Multiply value by 10
unsigned int carry = 0;
int i;
for (i = 0; i < val.size(); i++) {
unsigned long value = val[i]*10ul+carry;
carry = (value & byteMask) >> CHAR_BIT;
val[i] = value & ~byteMask;
}
if (carry > 0) val.push_back(carry);
}
void addDigit(BYTEVEC &val, const char digit) {
// Add digit to the number in BYTEVEC.
unsigned int carry = digit - '0'; // Assumes ASCII char set
int i;
for (i = 0; i < val.size() && carry; i++) {
unsigned long value = static_cast<unsigned long>(val[i])+carry;
carry = (value & byteMask) >> CHAR_BIT;
val[i] = value & ~byteMask;
}
if (carry > 0) val.push_back(carry);
}
BYTEVEC Cstr2Bytevec(const char *str) {
// Turn a C-style string into a BYTEVEC. Only the digits in str apply,
// so that one can use commas, underscores, or other non-digits to separate
// digit groups.
BYTEVEC result;
result.reserve(MAXBYTES);
result[0]=0;
unsigned char *res=&result[0]; // For debugging
while (*str) {
if (isdigit(static_cast<int>(*str))) {
mult10(result);
addDigit(result, *str);
}
str++;
}
return result;
}
void packCounter(COUNTER &ctr, const BYTEVEC &val) {
// Pack the bytes from val into the (possibly larger) datatype of COUNTER
int i;
ctr.erase(ctr.begin(), ctr.end());
COUNTER_BASE value = 0;
for (i = 0; i < val.size(); i++) {
int pos = i%sizeof(COUNTER_BASE); // position of this byte in the value
if (i > 0 && pos == 0) {
ctr.push_back(value);
value = val[i];
} else {
value |= static_cast<COUNTER_BASE>(val[i]) << pos*CHAR_BIT;
}
}
ctr.push_back(value);
}
inline bool decrementAndTest(COUNTER &ctr) {
// decrement value in ctr and return true if old value was not all zeros
int i;
for (i = 0; i < ctr.size() && !(ctr[i]--); i++) ; // EMPTY BODY
return i < ctr.size();
}
inline bool decrementAndTest2(COUNTER_BASE *ctr, const size_t size) {
// decrement value in ctr and return true if old value was not all zeros
int i;
for (i = 0; i < size && !(ctr[i]--); i++) ; // EMPTY BODY
return i < size;
}
/* Vector counter - uses first arg (if supplied) as the count */
int main(int argc, const char *argv[]) {
BYTEVEC limit = Cstr2Bytevec(argc > 1? argv[1] : "0");
COUNTER ctr;
packCounter(ctr, limit);
COUNTER_BASE *ctr_vals = ctr.size() > 0 ? &ctr[0] : NULL;
size_t ctr_size = ctr.size();
unsigned long ul_counter = 0ul; /* to give loop something to do */
while(decrementAndTest2(ctr_vals, ctr_size)) {
ul_counter++;
};
printf("With %d bytes used, final ul_counter value = %lu\n", limit.size(), ul_counter);
return 0;
}
Examples of use:
$ time ./bigcounter 5
With 1 bytes used, final ul_counter value = 5
real 0m0.094s
user 0m0.031s
sys 0m0.047s
$ time ./bigcounter 5,000
With 2 bytes used, final ul_counter value = 5000
real 0m0.062s
user 0m0.015s
sys 0m0.062s
$ time ./bigcounter 5,000,000
With 3 bytes used, final ul_counter value = 5000000
real 0m0.093s
user 0m0.015s
sys 0m0.046s
$ time ./bigcounter 1,000,000,000
With 4 bytes used, final ul_counter value = 1000000000
real 0m2.688s
user 0m0.015s
sys 0m0.015s
$ time ./bigcounter 2,000,000,000
With 4 bytes used, final ul_counter value = 2000000000
real 0m5.125s
user 0m0.015s
sys 0m0.046s
$ time ./bigcounter 3,000,000,000
With 4 bytes used, final ul_counter value = 3000000000
real 0m7.485s
user 0m0.031s
sys 0m0.047s
$ time ./bigcounter 4,000,000,000
With 4 bytes used, final ul_counter value = 4000000000
real 0m9.875s
user 0m0.015s
sys 0m0.046s
$ time ./bigcounter 5,000,000,000
With 5 bytes used, final ul_counter value = 705032704
real 0m12.594s
user 0m0.046s
sys 0m0.015s
$ time ./bigcounter 6,000,000,000
With 5 bytes used, final ul_counter value = 1705032704
real 0m14.813s
user 0m0.015s
sys 0m0.062s
Unwrapping the counter vector into C-style data structures (i.e., using decrementAndTest2 instead of decrementAndTest) sped things up by around 20-25%, but the code is still about twice as slow as my previous C program for similar-sized examples (around 4 billion). This is with MS Visual C++ 6.0 as the compiler in release mode, optimizing for speed, on a 2GHz dual-core system, for both programs. Inlining the decrementAndTest2 function definitely makes a big difference (around 12 sec. vs. 30 for the 5 billion loop), but I'll have to see whether physically inlining the code as I did in the C program can get similar performance.
the variable in main function can Store even 100 factorial
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <string>
#include <map>
#include <functional>
#include <algorithm>
#include <cstdlib>
#include <iomanip>
#include <stack>
#include <queue>
#include <deque>
#include <limits>
#include <cmath>
#include <numeric>
#include <set>
using namespace std;
//template for BIGINIT
// base and base_digits must be consistent
const int base = 10;
const int base_digits = 1;
struct bigint {
vector<int> a;
int sign;
bigint() :
sign(1) {
}
bigint(long long v) {
*this = v;
}
bigint(const string &s) {
read(s);
}
void operator=(const bigint &v) {
sign = v.sign;
a = v.a;
}
void operator=(long long v) {
sign = 1;
if (v < 0)
sign = -1, v = -v;
for (; v > 0; v = v / base)
a.push_back(v % base);
}
bigint operator+(const bigint &v) const {
if (sign == v.sign) {
bigint res = v;
for (int i = 0, carry = 0; i < (int) max(a.size(), v.a.size()) || carry; ++i) {
if (i == (int) res.a.size())
res.a.push_back(0);
res.a[i] += carry + (i < (int) a.size() ? a[i] : 0);
carry = res.a[i] >= base;
if (carry)
res.a[i] -= base;
}
return res;
}
return *this - (-v);
}
bigint operator-(const bigint &v) const {
if (sign == v.sign) {
if (abs() >= v.abs()) {
bigint res = *this;
for (int i = 0, carry = 0; i < (int) v.a.size() || carry; ++i) {
res.a[i] -= carry + (i < (int) v.a.size() ? v.a[i] : 0);
carry = res.a[i] < 0;
if (carry)
res.a[i] += base;
}
res.trim();
return res;
}
return -(v - *this);
}
return *this + (-v);
}
void operator*=(int v) {
if (v < 0)
sign = -sign, v = -v;
for (int i = 0, carry = 0; i < (int) a.size() || carry; ++i) {
if (i == (int) a.size())
a.push_back(0);
long long cur = a[i] * (long long) v + carry;
carry = (int) (cur / base);
a[i] = (int) (cur % base);
//asm("divl %%ecx" : "=a"(carry), "=d"(a[i]) : "A"(cur), "c"(base));
}
trim();
}
bigint operator*(int v) const {
bigint res = *this;
res *= v;
return res;
}
friend pair<bigint, bigint> divmod(const bigint &a1, const bigint &b1) {
int norm = base / (b1.a.back() + 1);
bigint a = a1.abs() * norm;
bigint b = b1.abs() * norm;
bigint q, r;
q.a.resize(a.a.size());
for (int i = a.a.size() - 1; i >= 0; i--) {
r *= base;
r += a.a[i];
int s1 = r.a.size() <= b.a.size() ? 0 : r.a[b.a.size()];
int s2 = r.a.size() <= b.a.size() - 1 ? 0 : r.a[b.a.size() - 1];
int d = ((long long) base * s1 + s2) / b.a.back();
r -= b * d;
while (r < 0)
r += b, --d;
q.a[i] = d;
}
q.sign = a1.sign * b1.sign;
r.sign = a1.sign;
q.trim();
r.trim();
return make_pair(q, r / norm);
}
bigint operator/(const bigint &v) const {
return divmod(*this, v).first;
}
bigint operator%(const bigint &v) const {
return divmod(*this, v).second;
}
void operator/=(int v) {
if (v < 0)
sign = -sign, v = -v;
for (int i = (int) a.size() - 1, rem = 0; i >= 0; --i) {
long long cur = a[i] + rem * (long long) base;
a[i] = (int) (cur / v);
rem = (int) (cur % v);
}
trim();
}
bigint operator/(int v) const {
bigint res = *this;
res /= v;
return res;
}
int operator%(int v) const {
if (v < 0)
v = -v;
int m = 0;
for (int i = a.size() - 1; i >= 0; --i)
m = (a[i] + m * (long long) base) % v;
return m * sign;
}
void operator+=(const bigint &v) {
*this = *this + v;
}
void operator-=(const bigint &v) {
*this = *this - v;
}
void operator*=(const bigint &v) {
*this = *this * v;
}
void operator/=(const bigint &v) {
*this = *this / v;
}
bool operator<(const bigint &v) const {
if (sign != v.sign)
return sign < v.sign;
if (a.size() != v.a.size())
return a.size() * sign < v.a.size() * v.sign;
for (int i = a.size() - 1; i >= 0; i--)
if (a[i] != v.a[i])
return a[i] * sign < v.a[i] * sign;
return false;
}
bool operator>(const bigint &v) const {
return v < *this;
}
bool operator<=(const bigint &v) const {
return !(v < *this);
}
bool operator>=(const bigint &v) const {
return !(*this < v);
}
bool operator==(const bigint &v) const {
return !(*this < v) && !(v < *this);
}
bool operator!=(const bigint &v) const {
return *this < v || v < *this;
}
void trim() {
while (!a.empty() && !a.back())
a.pop_back();
if (a.empty())
sign = 1;
}
bool isZero() const {
return a.empty() || (a.size() == 1 && !a[0]);
}
bigint operator-() const {
bigint res = *this;
res.sign = -sign;
return res;
}
bigint abs() const {
bigint res = *this;
res.sign *= res.sign;
return res;
}
long long longValue() const {
long long res = 0;
for (int i = a.size() - 1; i >= 0; i--)
res = res * base + a[i];
return res * sign;
}
friend bigint gcd(const bigint &a, const bigint &b) {
return b.isZero() ? a : gcd(b, a % b);
}
friend bigint lcm(const bigint &a, const bigint &b) {
return a / gcd(a, b) * b;
}
void read(const string &s) {
sign = 1;
a.clear();
int pos = 0;
while (pos < (int) s.size() && (s[pos] == '-' || s[pos] == '+')) {
if (s[pos] == '-')
sign = -sign;
++pos;
}
for (int i = s.size() - 1; i >= pos; i -= base_digits) {
int x = 0;
for (int j = max(pos, i - base_digits + 1); j <= i; j++)
x = x * 10 + s[j] - '0';
a.push_back(x);
}
trim();
}
friend istream& operator>>(istream &stream, bigint &v) {
string s;
stream >> s;
v.read(s);
return stream;
}
friend ostream& operator<<(ostream &stream, const bigint &v) {
if (v.sign == -1)
stream << '-';
stream << (v.a.empty() ? 0 : v.a.back());
for (int i = (int) v.a.size() - 2; i >= 0; --i)
stream << setw(base_digits) << setfill('0') << v.a[i];
return stream;
}
static vector<int> convert_base(const vector<int> &a, int old_digits, int new_digits) {
vector<long long> p(max(old_digits, new_digits) + 1);
p[0] = 1;
for (int i = 1; i < (int) p.size(); i++)
p[i] = p[i - 1] * 10;
vector<int> res;
long long cur = 0;
int cur_digits = 0;
for (int i = 0; i < (int) a.size(); i++) {
cur += a[i] * p[cur_digits];
cur_digits += old_digits;
while (cur_digits >= new_digits) {
res.push_back(int(cur % p[new_digits]));
cur /= p[new_digits];
cur_digits -= new_digits;
}
}
res.push_back((int) cur);
while (!res.empty() && !res.back())
res.pop_back();
return res;
}
typedef vector<long long> vll;
static vll karatsubaMultiply(const vll &a, const vll &b) {
int n = a.size();
vll res(n + n);
if (n <= 32) {
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
res[i + j] += a[i] * b[j];
return res;
}
int k = n >> 1;
vll a1(a.begin(), a.begin() + k);
vll a2(a.begin() + k, a.end());
vll b1(b.begin(), b.begin() + k);
vll b2(b.begin() + k, b.end());
vll a1b1 = karatsubaMultiply(a1, b1);
vll a2b2 = karatsubaMultiply(a2, b2);
for (int i = 0; i < k; i++)
a2[i] += a1[i];
for (int i = 0; i < k; i++)
b2[i] += b1[i];
vll r = karatsubaMultiply(a2, b2);
for (int i = 0; i < (int) a1b1.size(); i++)
r[i] -= a1b1[i];
for (int i = 0; i < (int) a2b2.size(); i++)
r[i] -= a2b2[i];
for (int i = 0; i < (int) r.size(); i++)
res[i + k] += r[i];
for (int i = 0; i < (int) a1b1.size(); i++)
res[i] += a1b1[i];
for (int i = 0; i < (int) a2b2.size(); i++)
res[i + n] += a2b2[i];
return res;
}
bigint operator*(const bigint &v) const {
vector<int> a6 = convert_base(this->a, base_digits, 6);
vector<int> b6 = convert_base(v.a, base_digits, 6);
vll a(a6.begin(), a6.end());
vll b(b6.begin(), b6.end());
while (a.size() < b.size())
a.push_back(0);
while (b.size() < a.size())
b.push_back(0);
while (a.size() & (a.size() - 1))
a.push_back(0), b.push_back(0);
vll c = karatsubaMultiply(a, b);
bigint res;
res.sign = sign * v.sign;
for (int i = 0, carry = 0; i < (int) c.size(); i++) {
long long cur = c[i] + carry;
res.a.push_back((int) (cur % 1000000));
carry = (int) (cur / 1000000);
}
res.a = convert_base(res.a, 6, base_digits);
res.trim();
return res;
}
};
//use : bigint var;
//template for biginit over
int main()
{
bigint var=10909000890789;
cout<<var;
return 0;
}
So I've been working recently on an implementation of the Miller-Rabin primality test. I am limiting it to a scope of all 32-bit numbers, because this is a just-for-fun project that I am doing to familiarize myself with c++, and I don't want to have to work with anything 64-bits for awhile. An added bonus is that the algorithm is deterministic for all 32-bit numbers, so I can significantly increase efficiency because I know exactly what witnesses to test for.
So for low numbers, the algorithm works exceptionally well. However, part of the process relies upon modular exponentiation, that is (num ^ pow) % mod. so, for example,
3 ^ 2 % 5 =
9 % 5 =
4
here is the code I have been using for this modular exponentiation:
unsigned mod_pow(unsigned num, unsigned pow, unsigned mod)
{
unsigned test;
for(test = 1; pow; pow >>= 1)
{
if (pow & 1)
test = (test * num) % mod;
num = (num * num) % mod;
}
return test;
}
As you might have already guessed, problems arise when the arguments are all exceptionally large numbers. For example, if I want to test the number 673109 for primality, I will at one point have to find:
(2 ^ 168277) % 673109
now 2 ^ 168277 is an exceptionally large number, and somewhere in the process it overflows test, which results in an incorrect evaluation.
on the reverse side, arguments such as
4000111222 ^ 3 % 1608
also evaluate incorrectly, for much the same reason.
Does anyone have suggestions for modular exponentiation in a way that can prevent this overflow and/or manipulate it to produce the correct result? (the way I see it, overflow is just another form of modulo, that is num % (UINT_MAX+1))
Exponentiation by squaring still "works" for modulo exponentiation. Your problem isn't that 2 ^ 168277 is an exceptionally large number, it's that one of your intermediate results is a fairly large number (bigger than 2^32), because 673109 is bigger than 2^16.
So I think the following will do. It's possible I've missed a detail, but the basic idea works, and this is how "real" crypto code might do large mod-exponentiation (although not with 32 and 64 bit numbers, rather with bignums that never have to get bigger than 2 * log (modulus)):
Start with exponentiation by squaring, as you have.
Perform the actual squaring in a 64-bit unsigned integer.
Reduce modulo 673109 at each step to get back within the 32-bit range, as you do.
Obviously that's a bit awkward if your C++ implementation doesn't have a 64 bit integer, although you can always fake one.
There's an example on slide 22 here: http://www.cs.princeton.edu/courses/archive/spr05/cos126/lectures/22.pdf, although it uses very small numbers (less than 2^16), so it may not illustrate anything you don't already know.
Your other example, 4000111222 ^ 3 % 1608 would work in your current code if you just reduce 4000111222 modulo 1608 before you start. 1608 is small enough that you can safely multiply any two mod-1608 numbers in a 32 bit int.
I wrote something for this recently for RSA in C++, bit messy though.
#include "BigInteger.h"
#include <iostream>
#include <sstream>
#include <stack>
BigInteger::BigInteger() {
digits.push_back(0);
negative = false;
}
BigInteger::~BigInteger() {
}
void BigInteger::addWithoutSign(BigInteger& c, const BigInteger& a, const BigInteger& b) {
int sum_n_carry = 0;
int n = (int)a.digits.size();
if (n < (int)b.digits.size()) {
n = b.digits.size();
}
c.digits.resize(n);
for (int i = 0; i < n; ++i) {
unsigned short a_digit = 0;
unsigned short b_digit = 0;
if (i < (int)a.digits.size()) {
a_digit = a.digits[i];
}
if (i < (int)b.digits.size()) {
b_digit = b.digits[i];
}
sum_n_carry += a_digit + b_digit;
c.digits[i] = (sum_n_carry & 0xFFFF);
sum_n_carry >>= 16;
}
if (sum_n_carry != 0) {
putCarryInfront(c, sum_n_carry);
}
while (c.digits.size() > 1 && c.digits.back() == 0) {
c.digits.pop_back();
}
//std::cout << a.toString() << " + " << b.toString() << " == " << c.toString() << std::endl;
}
void BigInteger::subWithoutSign(BigInteger& c, const BigInteger& a, const BigInteger& b) {
int sub_n_borrow = 0;
int n = a.digits.size();
if (n < (int)b.digits.size())
n = (int)b.digits.size();
c.digits.resize(n);
for (int i = 0; i < n; ++i) {
unsigned short a_digit = 0;
unsigned short b_digit = 0;
if (i < (int)a.digits.size())
a_digit = a.digits[i];
if (i < (int)b.digits.size())
b_digit = b.digits[i];
sub_n_borrow += a_digit - b_digit;
if (sub_n_borrow >= 0) {
c.digits[i] = sub_n_borrow;
sub_n_borrow = 0;
} else {
c.digits[i] = 0x10000 + sub_n_borrow;
sub_n_borrow = -1;
}
}
while (c.digits.size() > 1 && c.digits.back() == 0) {
c.digits.pop_back();
}
//std::cout << a.toString() << " - " << b.toString() << " == " << c.toString() << std::endl;
}
int BigInteger::cmpWithoutSign(const BigInteger& a, const BigInteger& b) {
int n = (int)a.digits.size();
if (n < (int)b.digits.size())
n = (int)b.digits.size();
//std::cout << "cmp(" << a.toString() << ", " << b.toString() << ") == ";
for (int i = n-1; i >= 0; --i) {
unsigned short a_digit = 0;
unsigned short b_digit = 0;
if (i < (int)a.digits.size())
a_digit = a.digits[i];
if (i < (int)b.digits.size())
b_digit = b.digits[i];
if (a_digit < b_digit) {
//std::cout << "-1" << std::endl;
return -1;
} else if (a_digit > b_digit) {
//std::cout << "+1" << std::endl;
return +1;
}
}
//std::cout << "0" << std::endl;
return 0;
}
void BigInteger::multByDigitWithoutSign(BigInteger& c, const BigInteger& a, unsigned short b) {
unsigned int mult_n_carry = 0;
c.digits.clear();
c.digits.resize(a.digits.size());
for (int i = 0; i < (int)a.digits.size(); ++i) {
unsigned short a_digit = 0;
unsigned short b_digit = b;
if (i < (int)a.digits.size())
a_digit = a.digits[i];
mult_n_carry += a_digit * b_digit;
c.digits[i] = (mult_n_carry & 0xFFFF);
mult_n_carry >>= 16;
}
if (mult_n_carry != 0) {
putCarryInfront(c, mult_n_carry);
}
//std::cout << a.toString() << " x " << b << " == " << c.toString() << std::endl;
}
void BigInteger::shiftLeftByBase(BigInteger& b, const BigInteger& a, int times) {
b.digits.resize(a.digits.size() + times);
for (int i = 0; i < times; ++i) {
b.digits[i] = 0;
}
for (int i = 0; i < (int)a.digits.size(); ++i) {
b.digits[i + times] = a.digits[i];
}
}
void BigInteger::shiftRight(BigInteger& a) {
//std::cout << "shr " << a.toString() << " == ";
for (int i = 0; i < (int)a.digits.size(); ++i) {
a.digits[i] >>= 1;
if (i+1 < (int)a.digits.size()) {
if ((a.digits[i+1] & 0x1) != 0) {
a.digits[i] |= 0x8000;
}
}
}
//std::cout << a.toString() << std::endl;
}
void BigInteger::shiftLeft(BigInteger& a) {
bool lastBit = false;
for (int i = 0; i < (int)a.digits.size(); ++i) {
bool bit = (a.digits[i] & 0x8000) != 0;
a.digits[i] <<= 1;
if (lastBit)
a.digits[i] |= 1;
lastBit = bit;
}
if (lastBit) {
a.digits.push_back(1);
}
}
void BigInteger::putCarryInfront(BigInteger& a, unsigned short carry) {
BigInteger b;
b.negative = a.negative;
b.digits.resize(a.digits.size() + 1);
b.digits[a.digits.size()] = carry;
for (int i = 0; i < (int)a.digits.size(); ++i) {
b.digits[i] = a.digits[i];
}
a.digits.swap(b.digits);
}
void BigInteger::divideWithoutSign(BigInteger& c, BigInteger& d, const BigInteger& a, const BigInteger& b) {
c.digits.clear();
c.digits.push_back(0);
BigInteger two("2");
BigInteger e = b;
BigInteger f("1");
BigInteger g = a;
BigInteger one("1");
while (cmpWithoutSign(g, e) >= 0) {
shiftLeft(e);
shiftLeft(f);
}
shiftRight(e);
shiftRight(f);
while (cmpWithoutSign(g, b) >= 0) {
g -= e;
c += f;
while (cmpWithoutSign(g, e) < 0) {
shiftRight(e);
shiftRight(f);
}
}
e = c;
e *= b;
f = a;
f -= e;
d = f;
}
BigInteger::BigInteger(const BigInteger& other) {
digits = other.digits;
negative = other.negative;
}
BigInteger::BigInteger(const char* other) {
digits.push_back(0);
negative = false;
BigInteger ten;
ten.digits[0] = 10;
const char* c = other;
bool make_negative = false;
if (*c == '-') {
make_negative = true;
++c;
}
while (*c != 0) {
BigInteger digit;
digit.digits[0] = *c - '0';
*this *= ten;
*this += digit;
++c;
}
negative = make_negative;
}
bool BigInteger::isOdd() const {
return (digits[0] & 0x1) != 0;
}
BigInteger& BigInteger::operator=(const BigInteger& other) {
if (this == &other) // handle self assignment
return *this;
digits = other.digits;
negative = other.negative;
return *this;
}
BigInteger& BigInteger::operator+=(const BigInteger& other) {
BigInteger result;
if (negative) {
if (other.negative) {
result.negative = true;
addWithoutSign(result, *this, other);
} else {
int a = cmpWithoutSign(*this, other);
if (a < 0) {
result.negative = false;
subWithoutSign(result, other, *this);
} else if (a > 0) {
result.negative = true;
subWithoutSign(result, *this, other);
} else {
result.negative = false;
result.digits.clear();
result.digits.push_back(0);
}
}
} else {
if (other.negative) {
int a = cmpWithoutSign(*this, other);
if (a < 0) {
result.negative = true;
subWithoutSign(result, other, *this);
} else if (a > 0) {
result.negative = false;
subWithoutSign(result, *this, other);
} else {
result.negative = false;
result.digits.clear();
result.digits.push_back(0);
}
} else {
result.negative = false;
addWithoutSign(result, *this, other);
}
}
negative = result.negative;
digits.swap(result.digits);
return *this;
}
BigInteger& BigInteger::operator-=(const BigInteger& other) {
BigInteger neg_other = other;
neg_other.negative = !neg_other.negative;
return *this += neg_other;
}
BigInteger& BigInteger::operator*=(const BigInteger& other) {
BigInteger result;
for (int i = 0; i < (int)digits.size(); ++i) {
BigInteger mult;
multByDigitWithoutSign(mult, other, digits[i]);
BigInteger shift;
shiftLeftByBase(shift, mult, i);
BigInteger add;
addWithoutSign(add, result, shift);
result = add;
}
if (negative != other.negative) {
result.negative = true;
} else {
result.negative = false;
}
//std::cout << toString() << " x " << other.toString() << " == " << result.toString() << std::endl;
negative = result.negative;
digits.swap(result.digits);
return *this;
}
BigInteger& BigInteger::operator/=(const BigInteger& other) {
BigInteger result, tmp;
divideWithoutSign(result, tmp, *this, other);
result.negative = (negative != other.negative);
negative = result.negative;
digits.swap(result.digits);
return *this;
}
BigInteger& BigInteger::operator%=(const BigInteger& other) {
BigInteger c, d;
divideWithoutSign(c, d, *this, other);
*this = d;
return *this;
}
bool BigInteger::operator>(const BigInteger& other) const {
if (negative) {
if (other.negative) {
return cmpWithoutSign(*this, other) < 0;
} else {
return false;
}
} else {
if (other.negative) {
return true;
} else {
return cmpWithoutSign(*this, other) > 0;
}
}
}
BigInteger& BigInteger::powAssignUnderMod(const BigInteger& exponent, const BigInteger& modulus) {
BigInteger zero("0");
BigInteger one("1");
BigInteger e = exponent;
BigInteger base = *this;
*this = one;
while (cmpWithoutSign(e, zero) != 0) {
//std::cout << e.toString() << " : " << toString() << " : " << base.toString() << std::endl;
if (e.isOdd()) {
*this *= base;
*this %= modulus;
}
shiftRight(e);
base *= BigInteger(base);
base %= modulus;
}
return *this;
}
std::string BigInteger::toString() const {
std::ostringstream os;
if (negative)
os << "-";
BigInteger tmp = *this;
BigInteger zero("0");
BigInteger ten("10");
tmp.negative = false;
std::stack<char> s;
while (cmpWithoutSign(tmp, zero) != 0) {
BigInteger tmp2, tmp3;
divideWithoutSign(tmp2, tmp3, tmp, ten);
s.push((char)(tmp3.digits[0] + '0'));
tmp = tmp2;
}
while (!s.empty()) {
os << s.top();
s.pop();
}
/*
for (int i = digits.size()-1; i >= 0; --i) {
os << digits[i];
if (i != 0) {
os << ",";
}
}
*/
return os.str();
And an example usage.
BigInteger a("87682374682734687"), b("435983748957348957349857345"), c("2348927349872344")
// Will Calculate pow(87682374682734687, 435983748957348957349857345) % 2348927349872344
a.powAssignUnderMod(b, c);
Its fast too, and has unlimited number of digits.
Two things:
Are you using the appropriate data type? In other words, does UINT_MAX allow you to have 673109 as an argument?
No, it does not, since at one point you have Your code does not work because at one point you have num = 2^16 and the num = ... causes overflow. Use a bigger data type to hold this intermediate value.
How about taking modulo at every possible overflow oppertunity such as:
test = ((test % mod) * (num % mod)) % mod;
Edit:
unsigned mod_pow(unsigned num, unsigned pow, unsigned mod)
{
unsigned long long test;
unsigned long long n = num;
for(test = 1; pow; pow >>= 1)
{
if (pow & 1)
test = ((test % mod) * (n % mod)) % mod;
n = ((n % mod) * (n % mod)) % mod;
}
return test; /* note this is potentially lossy */
}
int main(int argc, char* argv[])
{
/* (2 ^ 168277) % 673109 */
printf("%u\n", mod_pow(2, 168277, 673109));
return 0;
}
package playTime;
public class play {
public static long count = 0;
public static long binSlots = 10;
public static long y = 645;
public static long finalValue = 1;
public static long x = 11;
public static void main(String[] args){
int[] binArray = new int[]{0,0,1,0,0,0,0,1,0,1};
x = BME(x, count, binArray);
System.out.print("\nfinal value:"+finalValue);
}
public static long BME(long x, long count, int[] binArray){
if(count == binSlots){
return finalValue;
}
if(binArray[(int) count] == 1){
finalValue = finalValue*x%y;
}
x = (x*x)%y;
System.out.print("Array("+binArray[(int) count]+") "
+"x("+x+")" +" finalVal("+ finalValue + ")\n");
count++;
return BME(x, count,binArray);
}
}
LL is for long long int
LL power_mod(LL a, LL k) {
if (k == 0)
return 1;
LL temp = power(a, k/2);
LL res;
res = ( ( temp % P ) * (temp % P) ) % P;
if (k % 2 == 1)
res = ((a % P) * (res % P)) % P;
return res;
}
Use the above recursive function for finding the mod exp of the number. This will not result in overflow because it calculates in a bottom up manner.
Sample test run for :
a = 2 and k = 168277 shows output to be 518358 which is correct and the function runs in O(log(k)) time;
You could use following identity:
(a * b) (mod m) === (a (mod m)) * (b (mod m)) (mod m)
Try using it straightforward way and incrementally improve.
if (pow & 1)
test = ((test % mod) * (num % mod)) % mod;
num = ((num % mod) * (num % mod)) % mod;