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;
Related
Question:
Given an array arr[] with N integers.
What is the maximum number of items that can be chosen from the array so that their GCD is greater than 1?
Example:
4
30 42 105 1
Answer: 3
Constransts
N <= 10^3
arr[i] <= 10^18
My take:
void solve(int i, int gcd, int chosen){
if(i > n){
maximize(res, chosen);
return;
}
solve(i+1, gcd, chosen);
if(gcd == -1) solve(i+1, arr[i], chosen+1);
else{
int newGcd = __gcd(gcd, arr[i]);
if(newGcd > 1) solve(i+1, newGcd, chosen+1);
}
}
After many tries, my code still clearly got TLE, is there any more optimized solution for this problem?
Interesting task you have. I implemented two variants of solutions.
All algorithms that are used in my code are: Greatest Common Divisor (through Euclidean Algorithm), Binary Modular Exponentiation, Pollard Rho, Trial Division, Fermat Primality Test.
First variant called SolveCommon() iteratively finds all possible unique factors of all numbers by computing pairwise Greatest Common Divisor.
When all possible unique factors are found one can compute count of each unique factor inside each number. Finally maximal count for any factor will be final answer.
Second variant called SolveFactorize() finds all factor by doing factorization of each number using three algorithms: Pollard Rho, Trial Division, Fermat Primality Test.
Pollard-Rho factorization algorithm is quite fast, it has time complexity O(N^(1/4)), so for 64-bit number it will take around 2^16 iterations. To compare, Trial Division algorithm has complexity of O(N^(1/2)) which is square times slower than Pollard Rho. So in code below Pollard Rho can handle 64 bit inputs, although not very fast.
First variant SolveCommon() is much faster than second SolveFactorize(), especially if numbers are quite large, timings are provided in console output after following code.
Code below as an example provides test of random 100 numbers each 20 bit. 64 bit 1000 numbers are too large to handle by SolveFactorize() method, but SolveCommon() method solves 1000 64-bit numbers within 1-2 seconds.
Try it online!
#include <cstdint>
#include <random>
#include <tuple>
#include <unordered_map>
#include <algorithm>
#include <set>
#include <iostream>
#include <chrono>
#include <cmath>
#include <map>
#define LN { std::cout << "LN " << __LINE__ << std::endl; }
using u64 = uint64_t;
using u128 = unsigned __int128;
static std::mt19937_64 rng{123}; //{std::random_device{}()};
auto CurTime() {
return std::chrono::high_resolution_clock::now();
}
static auto const gtb = CurTime();
double Time() {
return std::llround(std::chrono::duration_cast<
std::chrono::duration<double>>(CurTime() - gtb).count() * 1000) / 1000.0;
}
u64 PowMod(u64 a, u64 b, u64 const c) {
u64 r = 1;
while (b != 0) {
if (b & 1)
r = (u128(r) * a) % c;
a = (u128(a) * a) % c;
b >>= 1;
}
return r;
}
bool IsFermatPrp(u64 N, size_t ntrials = 24) {
// https://en.wikipedia.org/wiki/Fermat_primality_test
if (N <= 10)
return N == 2 || N == 3 || N == 5 || N == 7;
for (size_t trial = 0; trial < ntrials; ++trial)
if (PowMod(rng() % (N - 3) + 2, N - 1, N) != 1)
return false;
return true;
}
bool FactorTrialDivision(u64 N, std::vector<u64> & factors, u64 limit = u64(-1)) {
// https://en.wikipedia.org/wiki/Trial_division
if (N <= 1)
return true;
while ((N & 1) == 0) {
factors.push_back(2);
N >>= 1;
}
for (u64 d = 3; d <= limit && d * d <= N; d += 2)
while (N % d == 0) {
factors.push_back(d);
N /= d;
}
if (N > 1)
factors.push_back(N);
return N == 1;
}
u64 GCD(u64 a, u64 b) {
// https://en.wikipedia.org/wiki/Euclidean_algorithm
while (b != 0)
std::tie(a, b) = std::make_tuple(b, a % b);
return a;
}
bool FactorPollardRho(u64 N, std::vector<u64> & factors) {
// https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm
auto f = [N](auto x) -> u64 { return (u128(x + 1) * (x + 1)) % N; };
auto DiffAbs = [](auto x, auto y){ return x >= y ? x - y : y - x; };
if (N <= 1)
return true;
if (IsFermatPrp(N)) {
factors.push_back(N);
return true;
}
for (size_t trial = 0; trial < 8; ++trial) {
u64 x = rng() % (N - 2) + 1;
size_t total_steps = 0;
for (size_t cycle = 1;; ++cycle) {
bool good = true;
u64 y = x;
for (u64 i = 0; i < (u64(1) << cycle); ++i) {
x = f(x);
++total_steps;
u64 const d = GCD(DiffAbs(x, y), N);
if (d > 1) {
if (d == N) {
good = false;
break;
}
//std::cout << N << ": " << d << ", " << total_steps << std::endl;
if (!FactorPollardRho(d, factors))
return false;
if (!FactorPollardRho(N / d, factors))
return false;
return true;
}
}
if (!good)
break;
}
}
factors.push_back(N);
return false;
}
void Factor(u64 N, std::vector<u64> & factors) {
if (N <= 1)
return;
if (1) {
FactorTrialDivision(N, factors, 1 << 8);
N = factors.back();
factors.pop_back();
}
FactorPollardRho(N, factors);
}
size_t SolveFactorize(std::vector<u64> const & nums) {
std::unordered_map<u64, size_t> cnts;
std::vector<u64> factors;
std::set<u64> unique_factors;
for (auto num: nums) {
factors.clear();
Factor(num, factors);
//std::cout << num << ": "; for (auto f: factors) std::cout << f << " "; std::cout << std::endl;
unique_factors.clear();
unique_factors.insert(factors.begin(), factors.end());
for (auto f: unique_factors)
++cnts[f];
}
size_t max_cnt = 0;
for (auto [_, cnt]: cnts)
max_cnt = std::max(max_cnt, cnt);
return max_cnt;
}
size_t SolveCommon(std::vector<u64> const & nums) {
size_t const K = nums.size();
std::set<u64> cmn(nums.begin(), nums.end()), cmn2, tcmn;
std::map<u64, bool> used;
cmn.erase(1);
while (true) {
cmn2.clear();
used.clear();
for (auto i = cmn.rbegin(); i != cmn.rend(); ++i) {
auto j = i;
++j;
for (; j != cmn.rend(); ++j) {
auto gcd = GCD(*i, *j);
if (gcd != 1) {
used[*i] = true;
used[*j] = true;
cmn2.insert(gcd);
cmn2.insert(*i / gcd);
cmn2.insert(*j / gcd);
break;
}
}
if (!used[*i])
tcmn.insert(*i);
}
cmn2.erase(1);
if (cmn2.empty())
break;
cmn = cmn2;
}
//for (auto c: cmn) std::cout << c << " "; std::cout << std::endl;
std::unordered_map<u64, size_t> cnts;
for (auto num: nums)
for (auto c: tcmn)
if (num % c == 0)
++cnts[c];
size_t max_cnt = 0;
for (auto [_, cnt]: cnts)
max_cnt = std::max(max_cnt, cnt);
return max_cnt;
}
void TestRandom() {
size_t const cnt_nums = 1000;
std::vector<u64> nums;
for (size_t i = 0; i < cnt_nums; ++i) {
nums.push_back((rng() & ((u64(1) << 20) - 1)) | 1);
//std::cout << nums.back() << " ";
}
//std::cout << std::endl;
{
auto tb = Time();
std::cout << "common " << SolveCommon(nums) << " time " << (Time() - tb) << std::endl;
}
{
auto tb = Time();
std::cout << "factorize " << SolveFactorize(nums) << " time " << (Time() - tb) << std::endl;
}
}
int main() {
TestRandom();
}
Output:
common 325 time 0.061
factorize 325 time 0.005
I think you need to search among all possible prime numbers to find out which prime number can divide most element in the array.
Code:
std::vector<int> primeLessEqualThanN(int N) {
std::vector<int> primes;
for (int x = 2; x <= N; ++x) {
bool isPrime = true;
for (auto& p : primes) {
if (x % p == 0) {
isPrime = false;
break;
}
}
if (isPrime) primes.push_back(x);
}
return primes;
}
int maxNumberGCDGreaterThan1(int N, std::vector<int>& A) {
int A_MAX = *std::max_element(A.begin(), A.end()); // largest number in A
std::vector<int> primes = primeLessEqualThanN(std::sqrt(A_MAX));
int max_count = 0;
for (auto& p : primes) {
int count = 0;
for (auto& n : A)
if (n % p == 0)
count++;
max_count = count > max_count ? count : max_count;
}
return max_count;
}
Note that in this way you cannot find out the value of the GCD, the code is based on that we dont need to know it.
I am given a nxn grid with filled with 1 or 0. I want to count the number of subgrids where the corner tiles are all 1s. My solution goes through all pairs of rows and counts the number of matching 1s then it uses the formula numOf1s * (numOf1s-1)/2 and adds to the result. However, when I submit my solution on https://cses.fi/problemset/task/2137, there is no output on inputs with n = 3000 (probably caused by some error). What could the error be?
int main()
{
int n; cin>> n;
vector<bitset<3000>> grid(n);
for(int i=0;i<n;i++){
cin >> grid[i];
}
long result = 0;
for(int i=0;i<n-1;i++){
for(int j=i+1;j<n;j++){
int count = (grid[i]&grid[j]).count();
result += (count*(count-1))/2;
}
}
cout << result;
}
This solution will cause a time limit exceeded. bitset::count() is O(n) in worst case. The total complexity of your code is O(n^3). In the worst-case the number of operations would be 3000^3 > 10^10 which is too large.
I'm not sure this solution is the best you can come up with, but it is based on the original solution, with a homebrew alternative for the bitset. This allows me to work with 64 bits blocks, and using a fast popcnt(). An hardware version would be even better, as it would be to work with AVX registers, but this should be more portable and it works on cses.fi. Basically instead of generating a long intersection bitset and later count the number of ones, the function count_common() makes a piece of the intersection and immediately uses it just to count the ones.
The stream extractor could be probably improved, saving some more time.
#include <iostream>
#include <array>
#include <cstdint>
#include <climits>
uint64_t popcnt(uint64_t v) {
v = v - ((v >> 1) & (uint64_t)~(uint64_t)0 / 3);
v = (v & (uint64_t)~(uint64_t)0 / 15 * 3) + ((v >> 2) & (uint64_t)~(uint64_t)0 / 15 * 3);
v = (v + (v >> 4)) & (uint64_t)~(uint64_t)0 / 255 * 15;
uint64_t c = (uint64_t)(v * ((uint64_t)~(uint64_t)0 / 255)) >> (sizeof(uint64_t) - 1) * CHAR_BIT;
return c;
}
struct line {
uint64_t cells_[47] = { 0 }; // 3000/64 = 47
uint64_t& operator[](int pos) { return cells_[pos]; }
const uint64_t& operator[](int pos) const { return cells_[pos]; }
};
uint64_t count_common(const line& a, const line& b) {
uint64_t u = 0;
for (int i = 0; i < 47; ++i) {
u += popcnt(a[i] & b[i]);
}
return u;
}
std::istream& operator>>(std::istream& is, line& ln) {
is >> std::ws;
int pos = 0;
uint64_t val = 0;
while (true) {
char ch = is.get();
if (is && ch == '\n') {
break;
}
if (ch == '1') {
val |= 1LL << (63 - pos % 64);
}
if ((pos + 1) % 64 == 0) {
ln[pos / 64] = val;
val = 0;
}
++pos;
}
if (pos % 64 != 0) {
ln[pos / 64] = val;
}
return is;
}
struct grid {
int n_;
std::array<line, 3000> data_;
line& operator[](int r) {
return data_[r];
}
};
std::istream& operator>>(std::istream& is, grid& g) {
is >> g.n_;
for (int r = 0; r < g.n_; ++r) {
is >> g[r];
}
return is;
}
int main()
{
grid g;
std::cin >> g;
uint64_t count = 0;
for (int r1 = 0; r1 < g.n_; ++r1) {
for (int r2 = r1 + 1; r2 < g.n_; ++r2) {
uint64_t n = count_common(g[r1], g[r2]);
count += n * (n - 1) / 2;
}
}
std::cout << count << '\n';
return 0;
}
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.
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();
}