Adding negative and positive numbers up to 10^100000 - c++

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.

Related

string subscript out of range error when assigning variable to function

In order to become more familiar with cpp I began making a program that takes the derivative of simple polynomials using the power rule. So far, it is working fine for polynomials such as 5x^2+4x. However, if the polynomial contains a constant (like 5x + 3) I get a string subscript out of range error. I used the debugger and found the error triggers on line 33 (std::string term = differentiateTerm(*iter);). I'm not exactly sure what I'm doing wrong here and I would appreciate any help.
Full code:
#include <iostream>
#include <string>
#include <vector>
std::vector<std::string> terms;
std::vector<std::string>::const_iterator iter;
std::string takeDerivative(std::string expression);
void separateTerms(std::string expression);
std::string differentiateTerm(std::string inputTerm);
int main()
{
std::string userExpression;
std::cout << "Enter a polynomial.\n";
std::cin >> userExpression;
std::string outputExpression = takeDerivative(userExpression);
std::cout << "The derivative of your expression is: " + outputExpression;
return 0;
}
std::string takeDerivative(std::string expression)
{
std::string derivative;
separateTerms(expression);
for (iter = terms.begin(); iter != terms.end(); iter++)
{
std::string term = differentiateTerm(*iter);
if (iter - terms.begin() == 0)
{
derivative = term;
}
else
{
derivative += "+" + term;
}
}
return derivative;
}
void separateTerms(std::string expression)
{
int previousSign = 0;
bool firstTerm = true;
for (int i = 0; i < expression.size() + 1; i++)
{
if (expression[i] == '+' || expression[i] == '-')
{
if (firstTerm)
{
terms.push_back(expression.substr(0, i));
firstTerm = false;
previousSign = i;
}
else
{
terms.push_back(expression.substr(previousSign + 1, i - previousSign - 1));
previousSign = i;
}
}
else if (i == expression.size())
{
if (firstTerm)
{
terms.push_back(expression.substr(previousSign, i));
}
else
{
terms.push_back(expression.substr(previousSign + 1, i - previousSign));
}
}
}
}
std::string differentiateTerm(std::string inputTerm)
{
std::string outputTerm;
int coefficient = 1;
int exponent = 1;
int varPos = inputTerm.find('x');
if (inputTerm[varPos] == std::string::npos)
{
outputTerm = "0";
return outputTerm;
}
else {
if (inputTerm[varPos - 1] != std::string::npos)
{
coefficient = std::stoi(inputTerm.substr(0, varPos));
}
if (inputTerm[varPos + 1] == '^')
{
if (inputTerm[varPos + 2] != std::string::npos)
{
exponent = std::stoi(std::string(1, inputTerm[varPos + 2]));
}
}
}
coefficient = coefficient * exponent;
exponent--;
if (exponent <= 0)
{
outputTerm = std::to_string(coefficient);
}
else if (exponent == 1)
{
outputTerm = std::to_string(coefficient) + "x";
}
else
{
outputTerm = std::to_string(coefficient) + "x^" + std::to_string(exponent);
}
return outputTerm;
}
You're not checking the return value from find correctly in differentiateTerm. This causes inputTerm[varPos] to access out of bounds.
The correct check is
if (varPos == std::string::npos)
In the subsequent if statements, since you have a valid subscript in varPos, you should check that against the size of the string. So you'd have if (varPos > 0), if (varPos < inputTerm.size() - 1), etc.

Why karatsuba implemenation is giving wrong result

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

Prime checker doesn't include some multipliers of the number 10

I need to make a program that will check whether or not the number typed in (a) and its mirrored self (a1) are both prime numbers. I got it to work up to the point where I input a multiplier of 10, in which case it declares it as a prime number, which it clearly isn't.
I've already tried setting the condition:
if ( a % 10 = 0 ) {//declare it as non prime}
After having done that, I would always get a return value of 0 after entering the number. Also tried declaring :
if ( a == 1 ) {//declare it as a non prime}
which fixed it for multipliers of 10 up to 100, but the rest would give me the previously stated error.
My go at it:
#include <iostream>
using namespace std;
int main() {
int a, a1, DN;
cin >> a;
DN = a;
a1 = 0;
for (; a != 0;) {
a1 *= 10;
a1 = a1 + a % 10;
a /= 10;
}
int este_prim, i, este_prim2;
este_prim = 1;
i = 2;
este_prim2 = 1;
while (i < DN && i < a1) {
if (DN % i == 0) {
este_prim = 0;
}
++i;
}
if (a1 > i && a1 % i == 0) {
este_prim2 = 0;
}
++i;
if (a == 1) {
este_prim = 0;
}
if (a1 == 1) {
este_prim2 = 0;
}
if (este_prim2 == 1 && este_prim == 1) {
cout << "DA";
} else {
cout << "NU";
}
return 0;
}
I'm a complete newbie at this so any help would be appreciated. Cheers!
Your loop checks if DN is prime, but it doesn't check if a1 is prime. And this block of code is something I do not understand.
if (a1 > i && a1 % i == 0) {
este_prim2 = 0;
}
So just remove that.
Use this worthy helper function to detect if a positive number is prime:
bool isPrime(int x)
{
if (x <= 1)
return false;
// 2 is the only even prime
if (x == 2)
return true;
// any other even number is not prime
if ((x % 2) == 0)
return false;
// try dividing by all odd numbers from 3 to sqrt(x)
int stop = sqrt(x);
for (int i = 3; i <= stop; i += 2)
{
if ((x % i) == 0)
return false;
}
return true;
}
And then your code to detect if DN and it's mirror, a1 are both prime is this:
int main() {
int a, a1, DN;
cin >> a;
DN = a;
a1 = 0;
for (; a != 0;) {
a1 *= 10;
a1 = a1 + a % 10;
a /= 10;
}
bool este_prim, este_prim2;
este_prim = isPrime(DN);
este_prim2 = isPrime(a1);
if (este_prim2 && este_prim) {
cout << "DA";
} else {
cout << "NU";
}
}

How to convert a decimal string to binary string?

I have a decimal string like this (length < 5000):
std::string decimalString = "555";
Is there a standard way to convert this string to binary representation? Like this:
std::string binaryString = "1000101011";
Update.
This post helps me.
As the number is very large, you can use a big integer library (boost, maybe?), or write the necessary functions yourself.
If you decide to implement the functions yourself, one way is to implement the old pencil-and-paper long division method in your code, where you'll need to divide the decimal number repeatedly by 2 and accumulate the remainders in another string. May be a little cumbersome, but division by 2 should not be so hard.
Since 10 is not a power of two (or the other way round), you're out of luck. You will have to implement arithmetics in base-10. You need the following two operations:
Integer division by 2
Checking the remainder after division by 2
Both can be computed by the same algorithm.
Alternatively, you can use one of the various big integer libraries for C++, such as GNU MP or Boost.Multiprecision.
I tried to do it.. I don't think my answer is right but here is the IDEA behind what I was trying to do..
Lets say we have 2 decimals:
100 and 200..
To concatenate these, we can use the formula:
a * CalcPower(b) + b where CalcPower is defined below..
Knowing this, I tried to split the very long decimal string into chunks of 4. I convert each string to binary and store them in a vector..
Finally, I go through each string and apply the formula above to concatenate each binary string into one massive one..
I didn't get it working but here is the code.. maybe someone else see where I went wrong.. BinaryAdd, BinaryMulDec, CalcPower works perfectly fine.. the problem is actually in ToBinary
#include <iostream>
#include <bitset>
#include <limits>
#include <algorithm>
std::string BinaryAdd(std::string First, std::string Second)
{
int Carry = 0;
std::string Result;
while(Second.size() > First.size())
First.insert(0, "0");
while(First.size() > Second.size())
Second.insert(0, "0");
for (int I = First.size() - 1; I >= 0; --I)
{
int FirstBit = First[I] - 0x30;
int SecondBit = Second[I] - 0x30;
Result += static_cast<char>((FirstBit ^ SecondBit ^ Carry) + 0x30);
Carry = (FirstBit & SecondBit) | (SecondBit & Carry) | (FirstBit & Carry);
}
if (Carry)
Result += 0x31;
std::reverse(Result.begin(), Result.end());
return Result;
}
std::string BinaryMulDec(std::string value, int amount)
{
if (amount == 0)
{
for (auto &s : value)
{
s = 0x30;
}
return value;
}
std::string result = value;
for (int I = 0; I < amount - 1; ++I)
result = BinaryAdd(result, value);
return result;
}
std::int64_t CalcPowers(std::int64_t value)
{
std::int64_t t = 1;
while(t < value)
t *= 10;
return t;
}
std::string ToBinary(const std::string &value)
{
std::vector<std::string> sets;
std::vector<int> multipliers;
int Len = 0;
int Rem = value.size() % 4;
for (auto it = value.end(), jt = value.end(); it != value.begin() - 1; --it)
{
if (Len++ == 4)
{
std::string t = std::string(it, jt);
sets.push_back(std::bitset<16>(std::stoull(t)).to_string());
multipliers.push_back(CalcPowers(std::stoull(t)));
jt = it;
Len = 1;
}
}
if (Rem != 0 && Rem != value.size())
{
sets.push_back(std::bitset<16>(std::stoull(std::string(value.begin(), value.begin() + Rem))).to_string());
}
auto formula = [](std::string a, std::string b, int mul) -> std::string
{
return BinaryAdd(BinaryMulDec(a, mul), b);
};
std::reverse(sets.begin(), sets.end());
std::reverse(multipliers.begin(), multipliers.end());
std::string result = sets[0];
for (std::size_t i = 1; i < sets.size(); ++i)
{
result = formula(result, sets[i], multipliers[i]);
}
return result;
}
void ConcatenateDecimals(std::int64_t* arr, int size)
{
auto formula = [](std::int64_t a, std::int64_t b) -> std::int64_t
{
return (a * CalcPowers(b)) + b;
};
std::int64_t val = arr[0];
for (int i = 1; i < size; ++i)
{
val = formula(val, arr[i]);
}
std::cout<<val;
}
int main()
{
std::string decimal = "64497387062899840145";
//6449738706289984014 = 0101100110000010000100110010111001100010100000001000001000001110
/*
std::int64_t arr[] = {644, 9738, 7062, 8998, 4014};
ConcatenateDecimals(arr, 5);*/
std::cout<<ToBinary(decimal);
return 0;
}
I found my old code that solve sport programming task:
ai -> aj
2 <= i,j <= 36; 0 <= a <= 10^1000
time limit: 1sec
Execution time was ~0,039 in worst case. Multiplication, addition and division algorithms is very fast because of using 10^9 as numeration system, but implementation can be optimized very well I think.
source link
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define sz(x) (int((x).size()))
typedef vector<int> vi;
typedef long long llong;
int DigToNumber(char c) {
if( c <= '9' && c >= '0' )
return c-'0';
return c-'A'+10;
}
char NumberToDig(int n) {
if( n < 10 )
return '0'+n;
return n-10+'A';
}
const int base = 1000*1000*1000;
void mulint(vi& a, int b) { //a*= b
for(int i = 0, carry = 0; i < sz(a) || carry; i++) {
if( i == sz(a) )
a.push_back(0);
llong cur = carry + a[i] * 1LL * b;
a[i] = int(cur%base);
carry = int(cur/base);
}
while( sz(a) > 1 && a.back() == 0 )
a.pop_back();
}
int divint(vi& a, int d) { // carry = a%d; a /= d; return carry;
int carry = 0;
for(int i = sz(a)-1; i >= 0; i--) {
llong cur = a[i] + carry * 1LL * base;
a[i] = int(cur/d);
carry = int(cur%d);
}
while( sz(a) > 1 && a.back() == 0 )
a.pop_back();
return carry;
}
void add(vi& a, vi& b) { // a += b
for(int i = 0, c = 0, l = max(sz(a),sz(b)); i < l || c; i++) {
if( i == sz(a) )
a.push_back(0);
a[i] += ((i<sz(b))?b[i]:0) + c;
c = a[i] >= base;
if( c ) a[i] -= base;
}
}
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
int from, to; cin >> from >> to;
string s; cin >> s;
vi res(1,0); vi m(1,1); vi tmp;
for(int i = sz(s)-1; i >= 0; i--) {
tmp.assign(m.begin(), m.end());
mulint(tmp,DigToNumber(s[i]));
add(res,tmp); mulint(m,from);
}
vi ans;
while( sz(res) > 1 || res.back() != 0 )
ans.push_back(divint(res,to));
if( sz(ans) == 0 )
ans.push_back(0);
for(int i = sz(ans)-1; i >= 0; i--)
cout << NumberToDig(ans[i]);
cout << "\n";
return 0;
}
How "from -> to" works for string "s":
accumulate Big Number (vector< int >) "res" with s[i]*from^(|s|-i-1), i = |s|-1..0
compute digits by dividing "res" by "to" until res > 0 and save them to another vector
send it to output digit-by-digit (you can use ostringstream instead)
PS I've noted that nickname of thread starter is Denis. And I think this link may be useful too.

Modular Exponentiation for high numbers in C++

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;