Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Schönhage–Strassen Algorithm Implementation #60

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
8 changes: 7 additions & 1 deletion big-int/src/bigint.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,17 @@

#include <iostream>
#include <string>
#include <vector>
#include <complex>

namespace libbig
{
// constants used with the bool largeInt::sign attribute
// this->sign = POSITIVE; instead of this->sign = true;
constexpr bool POSITIVE = true;
constexpr bool NEGATIVE = false;
const double PI = 2*acos(0.0);
typedef std::vector<std::complex<double>> complexCoeffs;
class largeInt
{
private:
Expand Down Expand Up @@ -125,7 +129,9 @@ class largeInt
friend std::istream &operator>>(std::istream &, largeInt &);
friend std::ostream &operator<<(std::ostream &, const largeInt &);
};
int char_int_converter(const char &x);
// HELPERS
int char_int_converter(const char&);
complexCoeffs fast_fourier_transform(const bool is_IDFT, const complexCoeffs);
} // namespace libbig

#endif
39 changes: 39 additions & 0 deletions big-int/src/helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,49 @@
#include <ostream>
#include <bigint.hpp>
#include <algorithm>
#include <vector>
#include <complex>

namespace libbig
{
int char_int_converter(const char &x) {
return ((x >= '0' && x <= '9') ? x - '0' : x + '0') ;
}

complexCoeffs fast_fourier_transform(const bool is_IDFT, const complexCoeffs num) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


const int len = num.size();
const int half_len = len/2;
const double phase_angle = (is_IDFT) ? (-PI/half_len):(PI/half_len);
if(len == 1) {
return num;
}
std::complex<double> w_n (1.0, phase_angle);
std::complex<double> w (1, 0);
complexCoeffs even_coeffs;
complexCoeffs odd_coeffs;
for (int i = 0; i<num.size(); ++i) {
if(i%2) {
even_coeffs.push_back(num[i]);
}
else {
odd_coeffs.push_back(num[i]);
}

}
even_coeffs = fast_fourier_transform(is_IDFT, even_coeffs);
odd_coeffs = fast_fourier_transform(is_IDFT, odd_coeffs);
complexCoeffs Answer;
Answer.assign(len, 0.0);
for(int i = 0; i<half_len; ++i) {
Answer[i] = even_coeffs[i] + w * odd_coeffs[i];
Answer[half_len + i] = even_coeffs[i] - w * odd_coeffs[i];
if(is_IDFT) {
Answer[i] /= len;
Answer[half_len + i] /= len;
}
w *= w_n;
}
return Answer;
}
} // namespace libbig
58 changes: 39 additions & 19 deletions big-int/src/operators/multiply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <ostream>
#include <bigint.hpp>
#include <algorithm>
#include <complex>

namespace libbig
{
Expand Down Expand Up @@ -89,6 +90,21 @@ namespace libbig
return Answer;
};

auto get_polynomial = [] (const largeInt &num) {
const int len = num.number.length();
int factor = 1;
complexCoeffs Answer;
int i = 1;
while (i != len+1) {
std::complex<float> single(static_cast<float> (factor*char_int_converter(num.number[len - i])), 0.0);
Answer.push_back(single);
factor *= 10;
++i;
}
std::cout<<std::endl;
return Answer;
};

largeInt x = *this;
largeInt y = next_number;

Expand All @@ -99,30 +115,34 @@ namespace libbig
return simple_multiplication(x, y);
}

const int lower = std::min(x.number.length(), y.number.length());
const int higher = std::max(x.number.length(), y.number.length());

const int f = (higher >= 2*lower) ? lower:higher/2;

largeInt x1 = (f == x.number.length()) ? largeInt():largeInt(x.number.substr(0, x.number.length() - f));
largeInt y1 = (f == y.number.length()) ? largeInt():largeInt(y.number.substr(0, y.number.length() - f));
largeInt x2 = (f == x.number.length()) ? x:largeInt(x.number.substr(x.number.length() - f, x.number.length()));
largeInt y2 = (f == y.number.length()) ? y:largeInt(y.number.substr(y.number.length() - f, y.number.length()));

const largeInt x3 = x1 + x2;
const largeInt y3 = y1 + y2;
const complexCoeffs polynomial_x = get_polynomial(x);
const complexCoeffs polynomial_y = get_polynomial(y);

const complexCoeffs DFT_x = fast_fourier_transform(false, polynomial_x);
const complexCoeffs DFT_y = fast_fourier_transform(false, polynomial_y);

largeInt x1y1 = simple_multiplication(x1, y1);
largeInt x2y2 = simple_multiplication(x2, y2);
largeInt x3y3 = simple_multiplication(x3, y3);
const int min = std::min(DFT_x.size(), DFT_y.size());

largeInt xy = append_zeroes(x1y1, 2*f) + append_zeroes((x3y3 - x1y1 - x2y2), f) + x2y2;
complexCoeffs DFT_xy;

if(x.sign != y.sign)
xy.sign = NEGATIVE;
for(int i = 0; i<min; ++i) {
DFT_xy.push_back(DFT_x[i]*DFT_y[i]);
}

return remove_zeroes(xy);
largeInt Answer;
complexCoeffs IDFT_xy = fast_fourier_transform(true, DFT_xy);
for(int i = 0; i<IDFT_xy.size(); ++i) {
largeInt single(std::to_string(static_cast<int>(std::abs(IDFT_xy[i]))));
Answer = Answer + single;
}
return Answer;
}

largeInt largeInt::operator*(int next_number) {
return *this * largeInt(next_number);
}

largeInt largeInt::operator*(int64_t next_number) {
return *this * largeInt(std::to_string(next_number));
}
} // namespace libbig
138 changes: 133 additions & 5 deletions tests/operators/multiply_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,16 @@ int main()
{
/// Tests for multiplication of largeInt to largeInt (largeInt * largeInt)
/// Test 1
libbig::largeInt a("1");
libbig::largeInt a("1111");
libbig::largeInt b("1");
libbig::largeInt c = a * b;
assert(c == libbig::largeInt("1"));
assert(c == libbig::largeInt("1111"));

/// Test 2
a = libbig::largeInt("999");
b = libbig::largeInt("99999");
a = libbig::largeInt("24");
b = libbig::largeInt("25");
c = a * b;
assert(c == libbig::largeInt("99899001"));
assert(c == libbig::largeInt("600"));

/// Test 3
a = libbig::largeInt("32516889472103571029388908423975");
Expand Down Expand Up @@ -71,5 +71,133 @@ int main()
c = a * b;
assert(c == libbig::largeInt("7000770444056069403046119404826740387252166452093943636486324185225836788920060077258109995450330997820727632474615791121779806923541276193853962113432983583426568371447855101334504301369704676060587738461922443343618487980096828486083202559107333726983966552151422667448209619250487990929538296732965889159956209059231075"));

/// Tests for multiplication of largeInt to largeInt (largeInt * int)
/// Test 1
a = libbig::largeInt("1");
int d { 1 };
c = a * d;
assert(c == libbig::largeInt("1"));

/// Test 2
a = libbig::largeInt("999");
d = 99999;
c = a * d;
assert(c == libbig::largeInt("99899001"));

/// Test 3
a = libbig::largeInt("32516889472103571029388908423975");
d = 0;
c = a * d;
assert(c == libbig::largeInt("0"));

/// Test 4
a = libbig::largeInt("6666666666666");
d = 2147000000;
c = a * d;
assert(c == libbig::largeInt("14313333333331902000000"));

// Test 5
a = libbig::largeInt("33");
d = -2;
c = a * d;
assert(c == libbig::largeInt("-66"));

// Test 6
a = libbig::largeInt("-0");
d = 100;
c = a * d;
assert(c == libbig::largeInt("0"));

// Test 7
a = libbig::largeInt("-100");
d = -100;
c = a * d;
assert(c == libbig::largeInt("10000"));

// Test 8
a = libbig::largeInt("0000000000000000000000000000000000000000000000000000");
d = 1111111111;
c = a * d;
assert(c == libbig::largeInt("0"));

// Test 9
a = libbig::largeInt("824358293475908745902350926589023459023485089347892650234650273456207349236502347524357832456789235623489759235623789456782394567892359478235239423569782356234659837562378965278956237489235");
d = 2147111111;
c = a * d;
assert(c == libbig::largeInt("1769988851367122479149013395500437599508978045281688053754054359337011171465551557147132045207848595192391874649522705358582133685907728887725045238091914980923198260535639031943130151995891211390085"));

// Test 10
a = libbig::largeInt("824358293475908745902350926589023459023485089347892650234650273456207349236502347524357832456789235623489759235623789456782394567892359478235239423569782356234659837562378965278956237489235");
d = -0;
c = a * d;
assert(c == libbig::largeInt("0"));

/// Tests for multiplication of largeInt to largeInt (largeInt * int64_t(long long))
/// Test 1
a = libbig::largeInt("1");
int64_t e { 1 };
c = a * e;
assert(c == libbig::largeInt("1"));

/// Test 2
a = libbig::largeInt("999");
e = 99999;
c = a * e;
assert(c == libbig::largeInt("99899001"));

/// Test 3
a = libbig::largeInt("32516889472103571029388908423975");
e = 0;
c = a * e;
assert(c == libbig::largeInt("0"));

/// Test 4
a = libbig::largeInt("6666666666666");
e = 2147000000;
c = a * e;
assert(c == libbig::largeInt("14313333333331902000000"));

// Test 5
a = libbig::largeInt("33");
e = -2;
c = a * e;
assert(c == libbig::largeInt("-66"));

// Test 6
a = libbig::largeInt("-0");
e = 100;
c = a * e;
assert(c == libbig::largeInt("0"));

// Test 7
a = libbig::largeInt("-100");
e = -100;
c = a * e;
assert(c == libbig::largeInt("10000"));

// Test 8
a = libbig::largeInt("0000000000000000000000000000000000000000000000000000");
e = 1111111111;
c = a * e;
assert(c == libbig::largeInt("0"));

// Test 9
a = libbig::largeInt("824358293475908745902350926589023459023485089347892650234650273456207349236502347524357832456789235623489759235623789456782394567892359478235239423569782356234659837562378965278956237489235");
e = 2147111111;
c = a * e;
assert(c == libbig::largeInt("1769988851367122479149013395500437599508978045281688053754054359337011171465551557147132045207848595192391874649522705358582133685907728887725045238091914980923198260535639031943130151995891211390085"));

// Test 10
a = libbig::largeInt("824358293475908745902350926589023459023485089347892650234650273456207349236502347524357832456789235623489759235623789456782394567892359478235239423569782356234659837562378965278956237489235");
e = -0;
c = a * e;
assert(c == libbig::largeInt("0"));

// Test 1
a = libbig::largeInt("824358293475908745902350926589023459023485089347892650234650273456207349236502347524357832456789235623489759235623789456782394567892359478235239423569782356234659837562378965278956237489235");
e = 1265387145178649877;
c = a * e;
assert(c == libbig::largeInt("1043132387585823801991307287703268230197717355664659943770242721775843792669363443147242163866322648004732006134963833033002779153256893032797217422608922304113441680757314641399751543910917847399909621574095"));

return 0;
}