diff --git a/week_5/2018202051XYB/README.md b/week_5/2018202051XYB/README.md new file mode 100644 index 0000000..93f4e41 --- /dev/null +++ b/week_5/2018202051XYB/README.md @@ -0,0 +1,34 @@ +# BigInteger + +## Description +Homework5 on 2019.4.4 + +A 10-based `BigInteger` class. +`main.cpp` is an example. + +## Usage + +main(example) +``` +$ make +$ ./run +``` + +checker(check with random data) +``` +$ make check +``` + + +## API + +### `BigInteger::BigInteger` +Construct a `BigInteger` object from an `int` or a `std::string`. + +```cpp +//BigInteger::BigInteger(int x); +BigInteger a(19260817); + +//BigInteger::BigInteger(std::string str); +BigInteger b("-19260817"); +``` diff --git a/week_5/2018202051XYB/src/BigInteger.cpp b/week_5/2018202051XYB/src/BigInteger.cpp new file mode 100644 index 0000000..539549a --- /dev/null +++ b/week_5/2018202051XYB/src/BigInteger.cpp @@ -0,0 +1,396 @@ +#include +#include +#include + +#include "BigInteger.h" + +#define max(x, y) ((x)>(y)?(x):(y)) +#define min(x, y) ((x)<(y)?(x):(y)) + +int FFT_LEN; +std::vector rev; + +void BigInteger::normalize() +{ + len = data.size(); + for(int i = 0; i < len - 1; i++) + if(data[i] >= BASE) + { + data[i + 1] += data[i] / BASE; + data[i] %= BASE; + } + + while(data[len - 1] >= BASE) + { + data.push_back(data[len - 1] / BASE), + data[len - 1] %= BASE; + len++; + } + + for(int i = 0; i < len - 1; i++) + while(data[i] < 0) + { + data[i] += BASE; + data[i + 1] --; + } + + while(len > 1 && data[len - 1] == 0) + { + data.pop_back(); + len--; + } + if(len == 1 && data[0] == 0) + { + symbol = SYMBOL_POSI; + } +} + +BigInteger::BigInteger(int x) +{ + if(x < 0) + { + x = -x; + symbol = SYMBOL_NEGA; + } + else + symbol = SYMBOL_POSI; + data.push_back(x); + normalize(); +} + +BigInteger::BigInteger(std::string str) +{ + if(str[0] == '-') + { + symbol = SYMBOL_NEGA; + str = str.substr(1); + } + else + symbol = SYMBOL_POSI; + + len = str.size(); + for(int i = len - 1; i >= 0; i--) + data.push_back(str[i] - '0'); + normalize(); +} + +BigInteger operator-(BigInteger a) +{ + a.symbol ^= 1; + return a; +} + +BigInteger abs(BigInteger a) +{ + a.symbol = SYMBOL_POSI; + return a; +} + +// a >= 0 b >= 0 return a + b +BigInteger raw_add(BigInteger a, BigInteger b) +{ + BigInteger x; + x.symbol = SYMBOL_POSI; + int maxLen = max(a.len, b.len), + minLen = min(a.len, b.len); + + for(int i = 0; i < minLen; i++) + x.data.push_back(a.data[i] + b.data[i]); + if(a.len > b.len) + for(int i = minLen; i < maxLen; i++) + x.data.push_back(a.data[i]); + else + for(int i = minLen; i < maxLen; i++) + x.data.push_back(b.data[i]); + x.normalize(); + x.symbol = a.symbol; + return x; +} +// a >= b >= 0 return a - b +BigInteger raw_minus(BigInteger a, BigInteger b) +{ + BigInteger x; + x.symbol = SYMBOL_POSI; + int maxLen = max(a.len, b.len), + minLen = min(a.len, b.len); + for(int i = 0; i < minLen; i++) + x.data.push_back(a.data[i] - b.data[i]); + for(int i = minLen; i < maxLen; i++) + x.data.push_back(a.data[i]); + x.normalize(); + return x; +} + +bool operator==(BigInteger a, BigInteger b) +{ + if(a.symbol != b.symbol || a.len != b.len) + return false; + for(int i = 0; i < a.len; i++) + if(a.data[i] != b.data[i]) + return false; + return true; +} + +bool operator!=(BigInteger a, BigInteger b) +{ + return ! (a == b); +} + +bool operator<(BigInteger a, BigInteger b) +{ + if(a.symbol != b.symbol) + return a.symbol == SYMBOL_NEGA; + if(a.symbol == SYMBOL_NEGA) + return (-b) < (-a); + if(a.len != b.len) + return a.len < b.len; + for(int i = a.len - 1; i >= 0; i--) + if(a.data[i] != b.data[i]) + return a.data[i] < b.data[i]; + return false; +} + +bool operator>(BigInteger a, BigInteger b) +{ + return !((a < b) || (a == b)); +} +bool operator<=(BigInteger a, BigInteger b) +{ + return (a < b) || (a == b); +} +bool operator>=(BigInteger a, BigInteger b) +{ + return (a > b) || (a == b); +} + +BigInteger operator+(BigInteger a, BigInteger b) +{ + if(a.symbol == b.symbol) + if(a.symbol == SYMBOL_POSI) + return raw_add(a, b); // a > 0 b > 0 + else + return -raw_add(-a, -b); // a < 0 b < 0 + else + if(a.symbol == SYMBOL_NEGA) + return b - (-a); // a < 0 b > 0 + else + return a - (-b); // a > 0 b < 0 +} + +BigInteger operator-(BigInteger a, BigInteger b) +{ + if(a.symbol != b.symbol) + if(a.symbol == SYMBOL_POSI) + return a + (-b); // a > 0 b < 0 + else + return a + (-b); // a < 0 b > 0 + else + if(a.symbol == SYMBOL_NEGA) + return -((-a) - (-b)); // a < 0 b < 0 + else if(abs(a) > abs(b)) + return raw_minus(a, b); // a > b > 0 + else + return -(b - a); // b > a > 0 +} + + +BigInteger operator*(BigInteger a, BigInteger b) +{ + BigInteger x; + x.symbol = a.symbol ^ b.symbol; + InitFFT(a.len - 1, b.len - 1); + std::vector A, B; + for(int i = 0; i < FFT_LEN; i++) + { + A.push_back(Complex(0, 0)); + B.push_back(Complex(0, 0)); + } + for(int i = a.len - 1; i >= 0; i--) + A[i] = Complex(a.data[i], 0); + for(int i = b.len - 1; i >= 0; i--) + B[i] = Complex(b.data[i], 0); + + FFT(A, 1); + FFT(B, 1); + for(int i = 0; i < FFT_LEN; i++) + A[i] = A[i] * B[i]; + FFT(A, -1); + for(int i = 0; i < a.len + b.len - 1; i++) + x.data.push_back((int)(A[i].r + 0.5)); + x.normalize(); + return x; +} +/* +BigInteger operator*(BigInteger a, BigInteger b) +{ + BigInteger x; + x.symbol = a.symbol ^ b.symbol; + x.len = a.len + b.len; + for(int i = 0; i < x.len; i++) + x.data.push_back(0); + for(int i = 0; i < a.len; i++) + for(int j = 0; j < b.len; j++) + x.data[i + j] += a.data[i] * b.data[j]; + x.normalize(); + return x; +}*/ + +bool div_check(BigInteger a, BigInteger b, int pos) +{ + if(pos + b.len - 1 > a.len - 1) + return false; + if(pos + b.len <= a.len - 1) + a.data[pos + b.len - 1] += a.data[pos + b.len] * BASE; + + for(int i = b.len - 1; i >= 0; i--) + if(b.data[i] > a.data[pos + i]) + return false; + else + { + + a.data[pos + i] -= b.data[i]; + if(pos + i - 1 >= 0) + a.data[pos + i - 1] += a.data[pos + i] * BASE; + } + return true; +} + +void div_minus(BigInteger &a, BigInteger b, int pos) +{ + if(pos + b.len <= a.len - 1) + { + a.data[pos + b.len - 1] += a.data[pos + b.len] * BASE; + a.data[pos + b.len] = 0; + } + for(int i = b.len - 1; i >= 0; i--) + a.data[pos + i] -= b.data[i]; + + a.normalize(); + +} + +BigInteger operator/(BigInteger a, BigInteger b) +{ + if(abs(a) < abs(b)) + return BigInteger(0); + if(b == 0) + return a; + BigInteger x; + x.symbol = a.symbol ^ b.symbol; + + for(int i = 0; i < a.len - b.len + 1; i++) + x.data.push_back(0); + + for(int i = a.len - b.len; i >= 0; i--) + { + while(div_check(a, b, i)) + { + div_minus(a, b, i); + x.data[i]++; + } + } + x.normalize(); + return x; +} + +std::ostream& operator<<(std::ostream &os, BigInteger a) +{ + a.normalize(); + if(a.symbol == SYMBOL_NEGA) + os << "-"; + for(int i = a.len - 1; i >= 0; i--) + os << a.data[i]; +} + +BigInteger operator+(int k, BigInteger a) +{ + return (BigInteger)k + a; +} +BigInteger operator-(int k, BigInteger a) +{ + return (BigInteger)k - a; +} +BigInteger operator*(int k, BigInteger a) +{ + return (BigInteger)k * a; +} +BigInteger operator/(int k, BigInteger a) +{ + return (BigInteger)k / a; +} +BigInteger operator+(BigInteger a, int k) +{ + return (BigInteger)k + a; +} +BigInteger operator-(BigInteger a, int k) +{ + return (BigInteger)k - a; +} +BigInteger operator*(BigInteger a, int k) +{ + return (BigInteger)k * a; +} +BigInteger operator/(BigInteger a, int k) +{ + return (BigInteger)k / a; +} + +int toint(BigInteger a) +{ + int f = a.symbol == SYMBOL_NEGA?-1 : 1; + int ret = 0; + for(int i = a.len - 1; i >= 0; i--) + ret = ret * 10 + a.data[i]; + return ret * f; +} + +void swap(Complex &a, Complex &b) +{ + Complex c = a; + a = b; + b = c; +} + +void InitFFT(int l1, int l2) +{ + rev.clear(); + for(FFT_LEN = 1; FFT_LEN <= l1 + l2; FFT_LEN <<= 1); + for(int i = 0; i < FFT_LEN; i++) + rev.push_back(0); + + for(int i = 1; i < FFT_LEN; i++) + if(i & 1) + rev[i] = (rev[i >> 1] >> 1) ^ (FFT_LEN >> 1); + else + rev[i] = (rev[i >> 1] >> 1); +} + +void FFT(std::vector &x, int op) +{ + for(int i = 0; i < FFT_LEN; i++) + if(i < rev[i]) + { + Complex t = x[i]; + x[i] = x[rev[i]]; + x[rev[i]] = t; + } + for(int h = 2; h <= FFT_LEN; h <<= 1) + { + Complex wn(cos(2 * PI / h), sin(2 * PI * op / h)); + for(int i = 0; i < FFT_LEN; i += h) + { + Complex w(1, 0); + for(int j = i; j < i + h / 2; j++) + { + Complex u = x[j], t = x[j + h / 2]; + x[j] = u + w * t; + x[j + h / 2] = u - w * t; + w = w * wn; + } + } + } + if(op == -1) + for(int i = 0; i < FFT_LEN; i++) + x[i].r /= FFT_LEN; +} + diff --git a/week_5/2018202051XYB/src/BigInteger.h b/week_5/2018202051XYB/src/BigInteger.h new file mode 100644 index 0000000..5f23f2e --- /dev/null +++ b/week_5/2018202051XYB/src/BigInteger.h @@ -0,0 +1,120 @@ +#ifndef _BIGINTEGER_H +#define _BIGINTEGER_H + +#include +#include +#include +#include +#include + +#define BASE 10 +#define PI acos(-1.0) + +#define SYMBOL_NEGA true +#define SYMBOL_POSI false + +class BigInteger +{ +private: + std::vector data; + int len; + bool symbol; + void normalize(); + +public: + BigInteger() + { + symbol = SYMBOL_POSI; + } + BigInteger(int x); + BigInteger(std::string str); + + friend BigInteger fft_mul(BigInteger a, BigInteger b); + + friend BigInteger operator-(BigInteger a); + friend BigInteger abs(BigInteger a); + friend BigInteger raw_add(BigInteger a, BigInteger b); + friend BigInteger raw_minus(BigInteger a, BigInteger b); + + friend bool operator==(BigInteger a, BigInteger b); + friend bool operator<(BigInteger a, BigInteger b); + + friend BigInteger operator+(BigInteger a, BigInteger b); + friend BigInteger operator-(BigInteger a, BigInteger b); + friend BigInteger operator*(BigInteger a, BigInteger b); + friend BigInteger operator/(BigInteger a, BigInteger b); + + friend bool div_check(BigInteger a, BigInteger b, int pos); + friend void div_minus(BigInteger &a, BigInteger b, int pos); + + friend std::ostream& operator<<(std::ostream& os, BigInteger a); + + friend int toint(BigInteger a); +}; + +int toint(BigInteger a); //自然溢出 + +struct Complex +{ + double r, i; + Complex(double rx = 0.0, double ix = 0.0) + { + r = rx; + i = ix; + } + Complex operator+(Complex b) + { + return Complex(r + b.r, i + b.i); + } + Complex operator-(Complex b) + { + return Complex(r - b.r, i - b.i); + } + Complex operator*(Complex b) + { + return Complex(r * b.r - i * b.i, r * b.i + i * b.r); + } +}; + +extern int FFT_LEN; +extern std::vectorrev; + +BigInteger operator-(BigInteger a); +BigInteger abs(BigInteger a); + +BigInteger raw_add(BigInteger a, BigInteger b); +BigInteger raw_minus(BigInteger a, BigInteger b); + +bool operator==(BigInteger a, BigInteger b); +bool operator!=(BigInteger a, BigInteger b); +bool operator<(BigInteger a, BigInteger b); +bool operator>(BigInteger a, BigInteger b); +bool operator<=(BigInteger a, BigInteger b); +bool operator>=(BigInteger a, BigInteger b); + +BigInteger operator+(BigInteger a, BigInteger b); +BigInteger operator-(BigInteger a, BigInteger b); +BigInteger operator*(BigInteger a, BigInteger b); +BigInteger operator/(BigInteger a, BigInteger b); + +bool div_check(BigInteger a, BigInteger b, int pos); +void div_minus(BigInteger &a, BigInteger b, int pos); + +std::ostream& operator<<(std::ostream& os, BigInteger a); + +BigInteger operator+(int k, BigInteger a); +BigInteger operator-(int k, BigInteger a); +BigInteger operator*(int k, BigInteger a); +BigInteger operator/(int k, BigInteger a); + +BigInteger operator+(BigInteger a, int k); +BigInteger operator-(BigInteger a, int k); +BigInteger operator*(BigInteger a, int k); +BigInteger operator/(BigInteger a, int k); + +void swap(Complex &a, Complex &b); +void InitFFT(int l1, int l2); +void FFT(std::vector &x, int op); + + +#endif \ No newline at end of file diff --git a/week_5/2018202051XYB/src/checker.cpp b/week_5/2018202051XYB/src/checker.cpp new file mode 100644 index 0000000..b957b03 --- /dev/null +++ b/week_5/2018202051XYB/src/checker.cpp @@ -0,0 +1,51 @@ +#include + +#include "BigInteger.h" + + +int randNum() +{ + int f1 = (rand()&1) ? 1 : -1, + f2 = (rand()&1) ? 1 : 0; + int a = rand(), + b = rand(); + return f1 * (f2 * a + b); + +} + +char c[10] = {'0', '+', '-', '*', '/' , 'n'}; + +int main() +{ + int casenum = 10000, errornum = 0; + while(casenum--) + { + int a = randNum(), + b = randNum(); + BigInteger x(a), y(b); + int s[10], t[10]; + s[1] = toint(x + y), t[1] = a + b, + s[2] = toint(x - y), t[2] = a - b, + s[3] = toint(x * y), t[3] = a * b, + s[4] = toint(x / y), t[4] = a / b, + s[5] = toint(-x), t[5] = -a; + for(int i = 1; i <= 4; i++) + if(s[i] != t[i]) + { + std::cout << a << c[i] << b << std::endl; + std::cout << s[i] << std::endl; + std::cout << t[i] << std::endl; + errornum++; + } + if(s[5] != t[5]) + { + std::cout << '-' << a << std::endl; + std::cout << s[5] << std::endl; + std::cout << t[5] << std::endl; + errornum++; + } + } + if(errornum == 0) + std::cout << "No error\n"; + +} \ No newline at end of file diff --git a/week_5/2018202051XYB/src/main.cpp b/week_5/2018202051XYB/src/main.cpp new file mode 100644 index 0000000..64cc075 --- /dev/null +++ b/week_5/2018202051XYB/src/main.cpp @@ -0,0 +1,26 @@ +#include +#include +#include "BigInteger.h" + +#include + +int randNum() +{ + int f1 = (rand()&1) ? 1 : -1, + f2 = (rand()&1) ? 1 : 0; + int a = rand(), + b = rand(); + return f1 * (f2 * a + b); +} + +int main() +{ + BigInteger a(randNum()), + b(randNum()); + + std::cout << a << " + " << b << " = " << a + b << std::endl; + std::cout << a << " - " << b << " = " << a - b << std::endl; + std::cout << a << " * " << b << " = " << a * b << std::endl; + std::cout << a << " / " << b << " = " << a / b << std::endl; + +} diff --git a/week_5/2018202051XYB/src/makefile b/week_5/2018202051XYB/src/makefile new file mode 100644 index 0000000..9096e20 --- /dev/null +++ b/week_5/2018202051XYB/src/makefile @@ -0,0 +1,12 @@ +main : main.o BigInteger.o BigInteger.h + @g++ -o run main.o BigInteger.o +main.o : main.cpp BigInteger.h + @g++ -c main.cpp +BigInteger.o : BigInteger.cpp BigInteger.h + @g++ -c BigInteger.cpp +clean : + @rm -rf *.o + +check : checker.cpp BigInteger.o BigInteger.h + @g++ -o checker checker.cpp BigInteger.o + @./checker \ No newline at end of file