Created
December 26, 2018 01:24
-
-
Save andraantariksa/b23dda9fe024d533fd44576ae34f9852 to your computer and use it in GitHub Desktop.
libBG single
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <sstream> | |
#include <map> | |
#include <algorithm> | |
#include <cstdio> | |
#include <cctype> | |
// included bigint.h | |
#ifndef DODECAHEDRON_BIGINT_H_ | |
#define DODECAHEDRON_BIGINT_H_ | |
#include <vector> | |
#include <iostream> | |
#include <map> | |
#include <stdexcept> | |
#include <string> | |
namespace Dodecahedron | |
{ | |
class __fft; | |
class Bigint | |
{ | |
public: | |
class arithmetic_error : public std::runtime_error | |
{ | |
public: | |
explicit arithmetic_error(const std::string& what_arg) | |
: std::runtime_error(what_arg) {} | |
}; | |
friend class __fft; | |
private: | |
std::vector<int> number; | |
// don't modify this directly through const. use flip_positive | |
mutable bool positive; | |
static const int default_base=100000000; | |
static const int default_digits_per_element=8; | |
public: | |
//Constructors | |
Bigint(); | |
Bigint(long long); | |
Bigint(const std::string&); | |
Bigint(const Bigint& b); | |
//Adding | |
Bigint operator+(Bigint const &) const; | |
Bigint &operator+=(Bigint const &); | |
Bigint &operator++() {return *this += 1;} | |
Bigint operator++(int) {Bigint bk(*this); ++*this; return bk;} | |
//Subtraction | |
Bigint operator-(Bigint const &) const; | |
Bigint &operator-=(Bigint const &); | |
Bigint &operator--() {return *this -= 1;} | |
Bigint operator--(int) {Bigint bk(*this); --*this; return bk;} | |
//Multiplication | |
Bigint operator*(Bigint const &) const; | |
Bigint &operator*=(Bigint const &); | |
bool force_fft; | |
//Division & modulo operation | |
Bigint operator/(Bigint const&) const; | |
Bigint &operator/=(Bigint const &); | |
Bigint operator%(Bigint const&) const; | |
Bigint &operator%=(Bigint const &); | |
friend void sub_number(Bigint const&, Bigint const&, Bigint&); | |
friend void divide(Bigint, Bigint const&, Bigint&, Bigint&); | |
//Compare | |
bool operator<(const Bigint &) const; | |
bool operator>(const Bigint &) const; | |
bool operator<=(const Bigint &) const; | |
bool operator>=(const Bigint &) const; | |
bool operator==(const Bigint &) const; | |
bool operator!=(const Bigint &) const; | |
//Allocation | |
Bigint &operator=(const long long); | |
//Input&Output | |
friend std::istream &operator>>(std::istream &, Bigint &); | |
friend std::ostream &operator<<(std::ostream &, Bigint const &); | |
//Helpers | |
void clear(); | |
Bigint &abs(); | |
//Power | |
Bigint &pow(int const); | |
//Trivia | |
int digits() const; | |
int trailing_zeros() const; | |
int to_builtin() const {return number.empty() ? 0 : number.front();} | |
private: | |
int segment_length(int) const; | |
Bigint pow(int const, std::map<int, Bigint> &); | |
int compare(Bigint const &) const; //0 a == b, -1 a < b, 1 a > b | |
void flip_positive() const; | |
void delete_precode_zero(); | |
}; | |
Bigint abs(Bigint); | |
std::string to_string(Bigint const &); | |
Bigint factorial(int); | |
Bigint pow(Bigint, int const); | |
} | |
#endif | |
#ifndef DODECAHEDRON_FFT_H_ | |
#define DODECAHEDRON_FFT_H_ | |
namespace Dodecahedron | |
{ | |
void __fft_mul(Bigint const &a,Bigint const &b,Bigint &c); | |
} | |
#include <cmath> | |
#include <complex> | |
#include <vector> | |
#include <algorithm> | |
#include <iterator> | |
namespace Dodecahedron | |
{ | |
class __fft | |
{ | |
typedef double real; | |
typedef std::complex<real> cp; | |
typedef std::vector<cp> arr; | |
arr a,b,w,tt; | |
int n; | |
const real pi; | |
int cpy(arr &d,Bigint const &s) | |
{ | |
d.clear(); | |
for(std::vector<int>::const_iterator it(s.number.begin()); it!=s.number.end(); ++it) | |
{ | |
d.push_back(cp(*it%10000,0)); | |
d.push_back(cp(*it/10000,0)); | |
} | |
return d.size(); | |
} | |
void dft(arr &a,int s,int t) | |
{ | |
if((n>>t)==1) return; | |
dft(a,s,t+1); | |
dft(a,s+(1<<t),t+1); | |
for(int i=0; i<(n>>(t+1)); ++i) | |
{ | |
int p=(i<<(t+1))+s; | |
cp wt=w[i<<t]*a[p+(1<<t)]; | |
tt[i]=a[p]+wt; | |
tt[i+(n>>(t+1))]=a[p]-wt; | |
} | |
for(int i=0; i<(n>>t); ++i) | |
a[(i<<t)+s]=tt[i]; | |
} | |
long long round(real x) | |
{ | |
// WARNING: only works with positive number | |
return x+0.5; | |
} | |
void back(Bigint &cc) | |
{ | |
std::vector<long long> c(n+1); | |
for(int i=0; i<n; ++i) | |
{ | |
c[i]+=round(a[i].real()/n); | |
c[i+1]=c[i]/10000; | |
c[i]%=10000; | |
} | |
if(!c.empty()) | |
{ | |
long long incs; | |
while((incs=c.back())>=10000) | |
{ | |
c.back()%=10000; | |
c.push_back(incs/10000); | |
} | |
} | |
while(!c.empty()&&!c.back()) | |
c.pop_back(); | |
cc.number.clear(); | |
for(std::vector<long long>::const_iterator it(c.begin()); it<c.end(); it+=2) | |
{ | |
int tmp1=*it; | |
int tmp2=it+1==c.end()?0:*(it+1); | |
cc.number.push_back(tmp1+tmp2*10000); | |
} | |
} | |
public: | |
__fft():pi(std::acos((real)-1.0)) {} | |
void set(Bigint const &a,Bigint const &b) | |
{ | |
n=1; | |
int lla=cpy(this->a,a); | |
int llb=cpy(this->b,b); | |
while((n>>1)<lla)n+=n; | |
while((n>>1)<llb)n+=n; | |
for(int i=0; i<n; ++i) | |
w.push_back(cp(std::cos(pi*2*i/n),std::sin(pi*2*i/n))); | |
this->a.resize(n); | |
this->b.resize(n); | |
tt.resize(n); | |
} | |
void mul(Bigint &c) | |
{ | |
dft(a,0,0); | |
dft(b,0,0); | |
for(int i=0; i<n; ++i) | |
a[i]=a[i]*b[i]; | |
for(int i=0; i<n; ++i) | |
w[i]=cp(w[i].real(),-w[i].imag()); | |
dft(a,0,0); | |
back(c); | |
} | |
}; | |
void __fft_mul(Bigint const &a,Bigint const &b,Bigint &c) | |
{ | |
__fft f; | |
f.set(a,b); | |
f.mul(c); | |
} | |
} | |
#endif | |
namespace Dodecahedron | |
{ | |
//Constructor | |
Bigint::Bigint() | |
: positive(true), | |
force_fft(false) | |
{} | |
Bigint::Bigint(const Bigint &b) | |
: number(b.number), | |
positive(b.positive), | |
force_fft(false) | |
{} | |
Bigint::Bigint(long long value) | |
:force_fft(false){ | |
if (value < 0) { | |
positive = false; | |
value *= -1; | |
} else { | |
positive = true; | |
} | |
while (value) { | |
number.push_back((int) (value % Bigint::default_base)); | |
value /= Bigint::default_base; | |
} | |
} | |
Bigint::Bigint(const std::string &stringInteger) | |
:force_fft(false){ | |
int size = stringInteger.length(); | |
positive = (stringInteger[0] != '-'); | |
while (true) { | |
if (size <= 0) break; | |
if (!positive && size <= 1) break; | |
int length = 0; | |
int num = 0; | |
int prefix = 1; | |
for (int i(size - 1); i >= 0 && i >= size - Bigint::default_digits_per_element; --i) { | |
if (stringInteger[i] < '0' || stringInteger[i] > '9') break; | |
num += (stringInteger[i] - '0') * prefix; | |
prefix *= 10; | |
++length; | |
} | |
number.push_back(num); | |
size -= length; | |
} | |
delete_precode_zero(); | |
} | |
//Adding | |
Bigint Bigint::operator+(Bigint const &b) const | |
{ | |
Bigint c = *this; | |
c += b; | |
return c; | |
} | |
Bigint &Bigint::operator+=(Bigint const &b) | |
{ | |
if (positive && !b.positive) { | |
b.flip_positive(); | |
*this -= b; | |
b.flip_positive(); | |
return *this; | |
} | |
if (!positive && b.positive) { | |
flip_positive(); | |
*this -= b; | |
flip_positive(); | |
return *this; | |
} | |
if (!positive && !b.positive) { | |
flip_positive(); | |
b.flip_positive(); | |
*this += b; | |
flip_positive(); | |
b.flip_positive(); | |
return *this; | |
} | |
std::vector<int>::iterator | |
it1 = number.begin(); | |
std::vector<int>::const_iterator | |
it2 = b.number.begin(); | |
int sum = 0; | |
while (it1 != number.end() || it2 != b.number.end()) { | |
if (it1 != number.end()) { | |
sum += *it1; | |
} else { | |
number.push_back(0); | |
it1 = number.end()-1; | |
} | |
if (it2 != b.number.end()) { | |
sum += *it2; | |
++it2; | |
} | |
*it1 = sum % Bigint::default_base; | |
++it1; | |
sum /= Bigint::default_base; | |
} | |
if (sum) number.push_back(1); | |
return *this; | |
} | |
//Subtraction | |
Bigint Bigint::operator-(Bigint const &b) const | |
{ | |
Bigint c = *this; | |
c -= b; | |
return c; | |
} | |
Bigint &Bigint::operator-=(Bigint const &b) | |
{ | |
if (!positive || !b.positive){ | |
b.flip_positive(); | |
*this += b; | |
b.flip_positive(); | |
return *this; | |
} | |
std::vector<int>::iterator | |
it1 = number.begin(); | |
std::vector<int>::const_iterator | |
it2 = b.number.begin(); | |
int dif = 0; | |
while (it1 != number.end() || it2 != b.number.end()) { | |
if (it1 != number.end()) { | |
dif += *it1; | |
++it1; | |
} else { | |
number.push_back(0); | |
it1 = number.end(); | |
} | |
if (it2 != b.number.end()) { | |
dif -= *it2; | |
++it2; | |
} | |
if (dif < 0) { | |
*(it1 - 1) = (dif + Bigint::default_base) % Bigint::default_base; | |
dif = -1; | |
} else { | |
*(it1 - 1) = dif % Bigint::default_base; | |
dif /= Bigint::default_base; | |
} | |
} | |
if (dif < 0) { | |
std::string newstr("1"); | |
int c_seg = number.size(); | |
while(c_seg--) | |
for(int i=1; i<Bigint::default_base; i*=10) | |
newstr += "0"; | |
*this = Bigint(newstr) - *this; | |
positive = false; | |
} | |
delete_precode_zero(); | |
return *this; | |
} | |
//Multiplication | |
static bool is_fft_needed(unsigned long long a, unsigned long long b) | |
{ | |
# ifdef BIGINT_DISABLE_FFT | |
return false; | |
# endif | |
return a * b > | |
# ifdef BIGINT_FFT_TRIGGER | |
BIGINT_FFT_TRIGGER | |
# else | |
1024 * 1024 | |
# endif | |
; | |
} | |
Bigint Bigint::operator*(Bigint const &b) const | |
{ | |
if (force_fft || b.force_fft || is_fft_needed(this->number.size(), b.number.size())) | |
{ | |
Bigint c; | |
bool result_positive = !(positive ^ b.positive); | |
__fft_mul(*this, b, c); | |
c.positive = result_positive; | |
return c; | |
} | |
const long long max_longlong = | |
static_cast<long long>( | |
static_cast<unsigned long long>( | |
static_cast<long long>(-1) | |
) >> 1 | |
); | |
const long long update_limit = | |
max_longlong - static_cast<long long>(Bigint::default_base - 1) * (Bigint::default_base - 1); | |
bool update_flag = false; | |
Bigint const &a = *this; | |
Bigint c; | |
std::vector<long long> number(a.number.size()+b.number.size()); | |
for(std::vector<int>::const_iterator | |
it1(a.number.begin()); it1!=a.number.end(); ++it1){ | |
update_flag = false; | |
for(std::vector<int>::const_iterator | |
it2(b.number.begin()); it2!=b.number.end(); ++it2) | |
update_flag = (( | |
number[ | |
(it1 - a.number.begin()) + | |
(it2 - b.number.begin()) ] | |
+= static_cast<long long>(*it1) * *it2 | |
) > update_limit || update_flag); | |
if(update_flag) | |
for(std::vector<long long>::iterator it(number.begin() + 1); | |
it < number.end(); ++it){ | |
*it += *(it - 1) / Bigint::default_base; | |
*(it - 1) %= Bigint::default_base; | |
} | |
} | |
if(!update_flag) | |
for(std::vector<long long>::iterator it(number.begin() + 1); | |
it < number.end(); ++it){ | |
*it += *(it - 1) / Bigint::default_base; | |
*(it - 1) %= Bigint::default_base; | |
} | |
c.positive = !(a.positive ^ b.positive); | |
std::copy(number.begin(), number.end(), std::back_inserter(c.number)); | |
c.delete_precode_zero(); | |
return c; | |
} | |
Bigint &Bigint::operator*=(Bigint const &b) | |
{ | |
return *this = *this * b; | |
} | |
//Division | |
static std::string to_string(const int value) | |
{ | |
char str[16]; | |
std::sprintf(str, "%d", value); | |
return str; | |
} | |
void sub_number(Bigint const &p, Bigint const &q, Bigint &c){ | |
std::string tmpx0, tmpx1, tmpx3; | |
int window_size = std::min(p.digits(), q.digits()); | |
int last_i_iterator; | |
std::vector<int>::const_reverse_iterator i(p.number.rbegin()); | |
while(i!=p.number.rend() && window_size>0){ | |
tmpx0 = to_string(*i); | |
int ssss = tmpx0.size(); | |
if(i!=p.number.rbegin() && ssss<Bigint::default_digits_per_element){ | |
tmpx0 = std::string(Bigint::default_digits_per_element-ssss,'0') + tmpx0; | |
} | |
if(window_size - ssss < 0){ | |
tmpx3=tmpx0; | |
tmpx0=""; | |
for(int i=0;i<window_size;i++){ | |
tmpx0+=tmpx3[i]; | |
last_i_iterator=i; | |
} | |
window_size = window_size - tmpx0.size(); | |
tmpx1 += tmpx0; | |
} | |
else{ | |
window_size = window_size - tmpx0.size(); | |
tmpx1 += tmpx0; | |
++i; | |
} | |
} | |
c = tmpx1; | |
if(i!=p.number.rend() && c<q){ | |
if(tmpx3.size()!=0){ | |
window_size++; | |
tmpx0 = tmpx3[last_i_iterator+1]; | |
tmpx1 += tmpx0; | |
c=tmpx1; | |
} | |
else{ | |
window_size++; | |
tmpx0 = to_string(*i); | |
if(i!=p.number.rbegin() && tmpx0.size()<Bigint::default_digits_per_element){ | |
tmpx0 = std::string(Bigint::default_digits_per_element-tmpx0.size(),'0') + tmpx0; | |
} | |
tmpx0 = tmpx0[0]; | |
tmpx1 += tmpx0; | |
c=tmpx1; | |
} | |
} | |
} | |
void divide(Bigint p, Bigint const &q, Bigint &sum_quotient, Bigint &sub_p){ | |
/*Algorithm used is "Double division algorithm"*/ | |
const int look_up_table_size=4; | |
Bigint look_up[look_up_table_size]={ | |
q, | |
q*2, | |
q*4, | |
q*8 | |
}; | |
bool done_flag=false; | |
int tmp_quotient; Bigint *ptmpx1, tmpx2; | |
int qdigits = q.digits(); | |
while(true){ | |
sub_number(p, q, sub_p); // cut a portion from the dividened equal in size with the divisor | |
for(int i=0;i<look_up_table_size;i++){ // looking in the look_up table | |
if (sub_p < look_up[i]){ | |
if (i){ | |
ptmpx1 = look_up+i-1; | |
tmp_quotient = 1<<(i-1); | |
break; | |
} else { | |
if(qdigits >= p.digits()){ | |
done_flag=true; | |
break; | |
} | |
} | |
} else if((i==look_up_table_size-1 && sub_p>look_up[i]) || sub_p==look_up[i]){ | |
ptmpx1 = look_up+i; | |
tmp_quotient= 1<<i; | |
break; | |
} | |
} | |
if (done_flag) | |
break; | |
std::string temppp(p.digits()-(sub_p.digits()),'0'); | |
temppp="1"+temppp; | |
tmpx2=temppp; | |
if(sum_quotient.digits()==0) | |
sum_quotient=tmpx2*tmp_quotient; | |
else | |
sum_quotient+=tmpx2*tmp_quotient; | |
p-=*ptmpx1*tmpx2; | |
} | |
} | |
static void check_divisor(Bigint const &b) | |
{ | |
if (b == 0) | |
throw Bigint::arithmetic_error("Divide by zero"); | |
} | |
Bigint Bigint::operator/(Bigint const &b) const | |
{ | |
check_divisor(b); | |
if (*this == 0) return 0; | |
bool result_positive = !(positive ^ b.positive); | |
bool origin_positive_this = positive; | |
bool origin_positive_b = b.positive; | |
positive = true; | |
b.positive = true; | |
Bigint a1, a2; | |
divide(*this, b, a1, a2); | |
Bigint &ans = a1; | |
positive = origin_positive_this; | |
b.positive = origin_positive_b; | |
ans.positive = result_positive; | |
return ans; | |
} | |
Bigint &Bigint::operator/=(Bigint const &b) | |
{ | |
return *this = *this / b; | |
} | |
Bigint Bigint::operator%(Bigint const &b) const | |
{ | |
check_divisor(b); | |
if (*this == 0) return 0; | |
bool result_positive = positive; | |
bool origin_positive_this = positive; | |
bool origin_positive_b = b.positive; | |
positive = true; | |
b.positive = true; | |
Bigint a1, a2; | |
divide(*this, b, a1, a2); | |
Bigint &ans = a2; | |
positive = origin_positive_this; | |
b.positive = origin_positive_b; | |
ans.positive = ans==0 ? true : result_positive; | |
return ans; | |
} | |
Bigint &Bigint::operator%=(Bigint const &b) | |
{ | |
return *this = *this % b; | |
} | |
//Power | |
Bigint Bigint::pow(int const power, std::map<int, Bigint> &lookup) | |
{ | |
if (power == 1) return *this; | |
if (lookup.count(power)) return lookup[power]; | |
int closestPower = 1; | |
while (closestPower < power) closestPower <<= 1; | |
closestPower >>= 1; | |
if (power == closestPower) lookup[power] = pow(power / 2, lookup) * pow(power / 2, lookup); | |
else lookup[power] = pow(closestPower, lookup) * pow(power - closestPower, lookup); | |
return lookup[power]; | |
} | |
Bigint &Bigint::pow(int const power) | |
{ | |
if (!power) return *this = Bigint(1); | |
std::map<int, Bigint> lookup; | |
if (power % 2 == 0 && !positive) { | |
positive = true; | |
} | |
*this = pow(power, lookup); | |
return *this; | |
} | |
//Compare | |
int Bigint::compare(const Bigint &a) const //0 this == a || -1 this < a || 1 this > a | |
{ | |
if (positive && !a.positive) return 1; | |
if (!positive && a.positive) return -1; | |
int check = 1; | |
if (!positive && !a.positive) check = -1; | |
if (number.size() < a.number.size()) return -1 * check; | |
if (number.size() > a.number.size()) return check; | |
for (size_t i(number.size()); i > 0; --i) { | |
if (number[i-1] < a.number[i-1]) return -1 * check; | |
if (number[i-1] > a.number[i-1]) return check; | |
} | |
return 0; // == | |
} | |
bool Bigint::operator<(Bigint const &b) const | |
{ | |
return compare(b) == -1; | |
} | |
bool Bigint::operator<=(const Bigint &b) const | |
{ | |
int compared = compare(b); | |
return compared == 0 || compared == -1; | |
} | |
bool Bigint::operator>(const Bigint &b) const | |
{ | |
return compare(b) == 1; | |
} | |
bool Bigint::operator>=(const Bigint &b) const | |
{ | |
int compared = compare(b); | |
return compared == 0 || compared == 1; | |
} | |
bool Bigint::operator==(Bigint const &b) const | |
{ | |
return compare(b) == 0; | |
} | |
bool Bigint::operator!=(Bigint const &b) const | |
{ | |
return ! (*this == b); | |
} | |
//Allocation | |
Bigint &Bigint::operator=(const long long a) | |
{ | |
return *this = Bigint(a); | |
} | |
//Trivia | |
int Bigint::digits() const | |
{ | |
int segments = number.size(); | |
if (segments == 0) return 0; | |
int digits = Bigint::default_digits_per_element * (segments - 1); | |
digits += segment_length(number.back()); | |
return digits; | |
} | |
int Bigint::trailing_zeros() const | |
{ | |
if (number.empty() || (number.size() == 1 && number[0] == 0)) return 1; | |
int zeros = 0; | |
std::vector<int>::const_iterator it = number.begin(); | |
if (number.size() > 1) { | |
for (; it != number.end() - 1 && *it == 0; ++it) { | |
zeros += Bigint::default_digits_per_element; | |
} | |
} | |
int a = *it; | |
while (a % 10 == 0 && a) { | |
++zeros; | |
a /= 10; | |
} | |
return zeros; | |
} | |
//Helpers | |
void Bigint::clear() | |
{ | |
number.clear(); | |
positive = true; | |
} | |
Bigint &Bigint::abs() | |
{ | |
positive = true; | |
return *this; | |
} | |
void Bigint::flip_positive() const | |
{ | |
// WARN: private use, must call as pair!!! | |
positive = !positive; | |
} | |
void Bigint::delete_precode_zero() | |
{ | |
while (!number.empty() && !number.back()) | |
number.pop_back(); | |
} | |
//Input&Output | |
std::ostream &operator<<(std::ostream &out, Bigint const &a) | |
{ | |
if (!a.number.size()) return out << 0; | |
int i = a.number.size() - 1; | |
for (; i>=0 && a.number[i] == 0; --i); | |
if (i == -1) return out << 0; | |
if (!a.positive) out << '-'; | |
std::vector<int>::const_reverse_iterator it = a.number.rbegin() + (a.number.size() - i - 1); | |
out << *it++; | |
for (; it != a.number.rend(); ++it) { | |
for (int i(0), len = a.segment_length(*it); i < Bigint::default_digits_per_element - len; ++i) out << '0'; | |
if (*it) out << *it; | |
} | |
return out; | |
} | |
std::istream &operator>>(std::istream &in, Bigint &a) | |
{ | |
std::string str; | |
int ch; | |
if (!in) | |
{ | |
a = 0; | |
return in; | |
} | |
while (!std::isdigit(ch = in.get()) && ch != EOF && ch != '-' ); | |
if (!in) | |
{ | |
a = 0; | |
return in; | |
} | |
if (ch == '-') | |
str += (char) ch; | |
else | |
in.unget(); | |
while (std::isdigit(ch = in.get())) | |
str += (char) ch; | |
if (in) in.unget(); | |
if (str == "-") | |
{ | |
a = 0; | |
return in; | |
} | |
a = str; | |
return in; | |
} | |
int Bigint::segment_length(int segment) const | |
{ | |
int length = 0; | |
while (segment) { | |
segment /= 10; | |
++length; | |
} | |
return length; | |
} | |
Bigint abs(Bigint value) | |
{ | |
return value.abs(); | |
} | |
std::string to_string(Bigint const &value) | |
{ | |
std::ostringstream stream; | |
stream << value; | |
return stream.str(); | |
} | |
Bigint factorial(int n) | |
{ | |
Bigint result = 1; | |
if (n % 2) { | |
result = n; | |
--n; | |
} | |
int last = 0; | |
for (; n >= 2; n -= 2) { | |
result *= n + last; | |
last += n; | |
} | |
return result; | |
} | |
Bigint pow(Bigint a, int const b) | |
{ | |
return a.pow(b); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment