From 453274c4d995752ef3607abb8dc1e01fe61ca0cc Mon Sep 17 00:00:00 2001 From: a7458969 <290198252@qq.com> Date: Tue, 7 Jan 2020 01:04:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=B6=85=E5=A4=A7=E6=95=B0?= =?UTF-8?q?=E7=9A=84=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/workspace.xml | 7 +- CMakeLists.txt | 7 +- cmake-build-debug/General.cbp | 3 + obj/inc/rsa.cpp | 29 +- obj/inc/rsa.h | 4 +- src/math/BigInt.hpp | 1739 +++++++++++++++++++++++++++++++++ 6 files changed, 1775 insertions(+), 14 deletions(-) create mode 100644 src/math/BigInt.hpp diff --git a/.idea/workspace.xml b/.idea/workspace.xml index ffd71ee..8965904 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -12,10 +12,11 @@ - - + + + diff --git a/CMakeLists.txt b/CMakeLists.txt index dc811e3..8c4ab45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6,7 +6,8 @@ INCLUDE_DIRECTORIES (inc) aux_source_directory(src DIRSRCS) aux_source_directory(src/pattern PaternSrc) -add_library(General ${DIRSRCS} ${PaternSrc} src/pattern/signleton.h src/pattern/Observer.h src/pattern/stratergy.h src/pattern/adapter.h src/encrypt/base64.cpp src/encrypt/base64.h src/encrypt/aes.cpp src/encrypt/aes.h obj/inc/rsa.cpp obj/inc/rsa.h) +add_library(General ${DIRSRCS} ${PaternSrc} src/pattern/signleton.h src/pattern/Observer.h src/pattern/stratergy.h src/pattern/adapter.h src/encrypt/base64.cpp src/encrypt/base64.h src/encrypt/aes.cpp src/encrypt/aes.h obj/inc/rsa.cpp obj/inc/rsa.h + src/math/BigInt.hpp) set(COPYITEM inc) file(GLOB INCLUDES ${PROJECT_SOURCE_DIR}/inc/*) file(COPY ${INCLUDES} DESTINATION ${LIBRARY_OUTPUT_PATH}/inc @@ -19,4 +20,8 @@ file(COPY ${PatternINCLUDES} DESTINATION ${LIBRARY_OUTPUT_PATH}/inc file(GLOB EncryptINCLUDES ${PROJECT_SOURCE_DIR}/src/encrypt/*.h) file(COPY ${EncryptINCLUDES} DESTINATION ${LIBRARY_OUTPUT_PATH}/inc + FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_WRITE GROUP_READ WORLD_READ) + +file(GLOB MathINCLUDES ${PROJECT_SOURCE_DIR}/src/encrypt/*.hpp) +file(COPY ${MathINCLUDES} DESTINATION ${LIBRARY_OUTPUT_PATH}/inc FILE_PERMISSIONS OWNER_READ OWNER_WRITE GROUP_WRITE GROUP_READ WORLD_READ) \ No newline at end of file diff --git a/cmake-build-debug/General.cbp b/cmake-build-debug/General.cbp index 5613d60..6938d42 100644 --- a/cmake-build-debug/General.cbp +++ b/cmake-build-debug/General.cbp @@ -108,6 +108,9 @@ + + diff --git a/obj/inc/rsa.cpp b/obj/inc/rsa.cpp index 07a3014..a535064 100644 --- a/obj/inc/rsa.cpp +++ b/obj/inc/rsa.cpp @@ -68,6 +68,18 @@ const static int PrimeTable[550]= 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001 }; +static int Mod(uint8_t *dat,int size,int table){ + +} +/* +目前的做法是基于费马素性检测 +假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。 +也就是说, 如果p为素数, 那么对于任何a 0;i--) { m_ulValue[i] = m_ulValue[i]<<1; @@ -88,8 +100,8 @@ BigInt GetPrime(int bits) m_ulValue[0]++; for(i = 0; i <550;i++) { - //if(Mod(PrimeTable[i]) == 0) - // goto begin; + if(Mod(PrimeTable[i]) == 0) + goto begin; } //CBigInt S,A,I,K; //K.Mov(*this); @@ -181,15 +193,16 @@ bool rabinmiller(size_t n, size_t k) } BigInt::BigInt(int size) { - + memset(this->mDat,0,size); } BigInt::BigInt(int size, uint8_t *dat) { - + memcpy(this->mDat,dat,size); } -BigInt BigInt::operator=(const BigInt &) { - return BigInt(0); +bool BigInt::operator=(BigInt &cmp) { + return memcmp((const void *)cmp.Data(), + (const void *)this->Data(),this->mSize); } BigInt BigInt::operator>(const BigInt &) { @@ -208,6 +221,6 @@ string BigInt::ToString() { return std::__cxx11::string(); } -uint8_t *BigInt::Data() { +const uint8_t *BigInt::Data() { return mDat; } diff --git a/obj/inc/rsa.h b/obj/inc/rsa.h index 98c2d9b..d346a89 100644 --- a/obj/inc/rsa.h +++ b/obj/inc/rsa.h @@ -13,12 +13,12 @@ class BigInt{ public: BigInt(int size); BigInt(int size,uint8_t *dat); - BigInt operator=(const BigInt&); + bool operator=(BigInt&); BigInt operator>(const BigInt&); BigInt operator<(const BigInt&); BigInt operator^(const BigInt&); string ToString(); - uint8_t *Data(); + const uint8_t *Data(); private: uint8_t mDat[2048]; int mSize; diff --git a/src/math/BigInt.hpp b/src/math/BigInt.hpp new file mode 100644 index 0000000..d544676 --- /dev/null +++ b/src/math/BigInt.hpp @@ -0,0 +1,1739 @@ +/* + BigInt + ------ + Arbitrary-sized integer class for C++. + + Version: 0.4.0-dev + Released on: 03 January 2018 10:51 IST + Author: Syed Faheel Ahmad (faheel@live.in) + Project on GitHub: https://github.com/faheel/BigInt + License: MIT +*/ + +/* + =========================================================================== + BigInt + =========================================================================== + Definition for the BigInt class. +*/ + +#ifndef BIG_INT_HPP +#define BIG_INT_HPP + +#include + +class BigInt { + std::string value; + char sign; + + public: + // Constructors: + BigInt(); + BigInt(const BigInt&); + BigInt(const long long&); + BigInt(const std::string&); + + // Assignment operators: + BigInt& operator=(const BigInt&); + BigInt& operator=(const long long&); + BigInt& operator=(const std::string&); + + // Unary arithmetic operators: + BigInt operator+() const; // unary + + BigInt operator-() const; // unary - + + // Binary arithmetic operators: + BigInt operator+(const BigInt&) const; + BigInt operator-(const BigInt&) const; + BigInt operator*(const BigInt&) const; + BigInt operator/(const BigInt&) const; + BigInt operator%(const BigInt&) const; + BigInt operator+(const long long&) const; + BigInt operator-(const long long&) const; + BigInt operator*(const long long&) const; + BigInt operator/(const long long&) const; + BigInt operator%(const long long&) const; + BigInt operator+(const std::string&) const; + BigInt operator-(const std::string&) const; + BigInt operator*(const std::string&) const; + BigInt operator/(const std::string&) const; + BigInt operator%(const std::string&) const; + + // Arithmetic-assignment operators: + BigInt& operator+=(const BigInt&); + BigInt& operator-=(const BigInt&); + BigInt& operator*=(const BigInt&); + BigInt& operator/=(const BigInt&); + BigInt& operator%=(const BigInt&); + BigInt& operator+=(const long long&); + BigInt& operator-=(const long long&); + BigInt& operator*=(const long long&); + BigInt& operator/=(const long long&); + BigInt& operator%=(const long long&); + BigInt& operator+=(const std::string&); + BigInt& operator-=(const std::string&); + BigInt& operator*=(const std::string&); + BigInt& operator/=(const std::string&); + BigInt& operator%=(const std::string&); + + // Increment and decrement operators: + BigInt& operator++(); // pre-increment + BigInt& operator--(); // pre-decrement + BigInt operator++(int); // post-increment + BigInt operator--(int); // post-decrement + + // Relational operators: + 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; + bool operator<(const long long&) const; + bool operator>(const long long&) const; + bool operator<=(const long long&) const; + bool operator>=(const long long&) const; + bool operator==(const long long&) const; + bool operator!=(const long long&) const; + bool operator<(const std::string&) const; + bool operator>(const std::string&) const; + bool operator<=(const std::string&) const; + bool operator>=(const std::string&) const; + bool operator==(const std::string&) const; + bool operator!=(const std::string&) const; + + // I/O stream operators: + friend std::istream& operator>>(std::istream&, BigInt&); + friend std::ostream& operator<<(std::ostream&, const BigInt&); + + // Conversion functions: + std::string to_string() const; + int to_int() const; + long to_long() const; + long long to_long_long() const; +}; + +#endif // BIG_INT_HPP + + +/* + =========================================================================== + Utility functions + =========================================================================== +*/ + +#ifndef BIG_INT_UTILITY_FUNCTIONS_HPP +#define BIG_INT_UTILITY_FUNCTIONS_HPP + +#include + + +/* + is_valid_number + --------------- + Checks whether the given string is a valid integer. +*/ + +bool is_valid_number(const std::string& num) { + for (char digit : num) + if (digit < '0' or digit > '9') + return false; + + return true; +} + + +/* + strip_leading_zeroes + -------------------- + Strip the leading zeroes from a number represented as a string. +*/ + +void strip_leading_zeroes(std::string& num) { + size_t i; + for (i = 0; i < num.size(); i++) + if (num[i] != '0') + break; + + if (i == num.size()) + num = "0"; + else + num = num.substr(i); +} + + +/* + add_leading_zeroes + ------------------ + Adds a given number of leading zeroes to a string-represented integer `num`. +*/ + +void add_leading_zeroes(std::string& num, size_t num_zeroes) { + num = std::string(num_zeroes, '0') + num; +} + + +/* + add_trailing_zeroes + ------------------- + Adds a given number of trailing zeroes to a string-represented integer `num`. +*/ + +void add_trailing_zeroes(std::string& num, size_t num_zeroes) { + num += std::string(num_zeroes, '0'); +} + + +/* + get_larger_and_smaller + ---------------------- + Identifies the given string-represented integers as `larger` and `smaller`, + padding the smaller number with leading zeroes to make it equal in length to + the larger number. +*/ + +std::tuple get_larger_and_smaller(const std::string& num1, + const std::string& num2) { + std::string larger, smaller; + if (num1.size() > num2.size() or + (num1.size() == num2.size() and num1 > num2)) { + larger = num1; + smaller = num2; + } + else { + larger = num2; + smaller = num1; + } + + // pad the smaller number with zeroes + add_leading_zeroes(smaller, larger.size() - smaller.size()); + + return std::make_tuple(larger, smaller); +} + +#endif // BIG_INT_UTILITY_FUNCTIONS_HPP + + +/* + =========================================================================== + Constructors + =========================================================================== +*/ + +#ifndef BIG_INT_CONSTRUCTORS_HPP +#define BIG_INT_CONSTRUCTORS_HPP + + + +/* + Default constructor + ------------------- +*/ + +BigInt::BigInt() { + value = "0"; + sign = '+'; +} + + +/* + Copy constructor + ---------------- +*/ + +BigInt::BigInt(const BigInt& num) { + value = num.value; + sign = num.sign; +} + + +/* + Integer to BigInt + ----------------- +*/ + +BigInt::BigInt(const long long& num) { + value = std::to_string(num); + if (num < 0) { + sign = '-'; + value = value.substr(1); // remove minus sign from value + } + else + sign = '+'; +} + + +/* + String to BigInt + ---------------- +*/ + +BigInt::BigInt(const std::string& num) { + if (num[0] == '+' or num[0] == '-') { // check for sign + std::string magnitude = num.substr(1); + if (is_valid_number(magnitude)) { + value = magnitude; + sign = num[0]; + } + else { + throw std::invalid_argument("Expected an integer, got \'" + num + "\'"); + } + } + else { // if no sign is specified + if (is_valid_number(num)) { + value = num; + sign = '+'; // positive by default + } + else { + throw std::invalid_argument("Expected an integer, got \'" + num + "\'"); + } + } + strip_leading_zeroes(value); +} + +#endif // BIG_INT_CONSTRUCTORS_HPP + + +/* + =========================================================================== + Conversion functions for BigInt + =========================================================================== +*/ + +#ifndef BIG_INT_CONVERSION_FUNCTIONS_HPP +#define BIG_INT_CONVERSION_FUNCTIONS_HPP + + +/* + to_string + --------- + Converts a BigInt to a string. +*/ + +std::string BigInt::to_string() const { + // prefix with sign if negative + return this->sign == '-' ? "-" + this->value : this->value; +} + + +/* + to_int + ------ + Converts a BigInt to an int. + NOTE: If the BigInt is out of range of an int, stoi() will throw an + out_of_range exception. +*/ + +int BigInt::to_int() const { + return std::stoi(this->to_string()); +} + + +/* + to_long + ------- + Converts a BigInt to a long int. + NOTE: If the BigInt is out of range of a long int, stol() will throw an + out_of_range exception. +*/ + +long BigInt::to_long() const { + return std::stol(this->to_string()); +} + + +/* + to_long_long + ------------ + Converts a BigInt to a long long int. + NOTE: If the BigInt is out of range of a long long int, stoll() will throw + an out_of_range exception. +*/ + +long long BigInt::to_long_long() const { + return std::stoll(this->to_string()); +} + +#endif // BIG_INT_CONVERSION_FUNCTIONS_HPP + + +/* + =========================================================================== + Assignment operators + =========================================================================== +*/ + +#ifndef BIG_INT_ASSIGNMENT_OPERATORS_HPP +#define BIG_INT_ASSIGNMENT_OPERATORS_HPP + + + +/* + BigInt = BigInt + --------------- +*/ + +BigInt& BigInt::operator=(const BigInt& num) { + value = num.value; + sign = num.sign; + + return *this; +} + + +/* + BigInt = Integer + ---------------- +*/ + +BigInt& BigInt::operator=(const long long& num) { + BigInt temp(num); + value = temp.value; + sign = temp.sign; + + return *this; +} + + +/* + BigInt = String + --------------- +*/ + +BigInt& BigInt::operator=(const std::string& num) { + BigInt temp(num); + value = temp.value; + sign = temp.sign; + + return *this; +} + +#endif // BIG_INT_ASSIGNMENT_OPERATORS_HPP + + +/* + =========================================================================== + Unary arithmetic operators + =========================================================================== +*/ + +#ifndef BIG_INT_UNARY_ARITHMETIC_OPERATORS_HPP +#define BIG_INT_UNARY_ARITHMETIC_OPERATORS_HPP + + + +/* + +BigInt + ------- + Returns the value of a BigInt. + NOTE: This function does not return the absolute value. To get the absolute + value of a BigInt, use the `abs` function. +*/ + +BigInt BigInt::operator+() const { + return *this; +} + + +/* + -BigInt + ------- + Returns the negative of a BigInt. +*/ + +BigInt BigInt::operator-() const { + BigInt temp; + + temp.value = value; + if (value != "0") { + if (sign == '+') + temp.sign = '-'; + else + temp.sign = '+'; + } + + return temp; +} + +#endif // BIG_INT_UNARY_ARITHMETIC_OPERATORS_HPP + + +/* + =========================================================================== + Relational operators + =========================================================================== + All operators depend on the '<' and/or '==' operator(s). +*/ + +#ifndef BIG_INT_RELATIONAL_OPERATORS_HPP +#define BIG_INT_RELATIONAL_OPERATORS_HPP + + + +/* + BigInt == BigInt + ---------------- +*/ + +bool BigInt::operator==(const BigInt& num) const { + return (sign == num.sign) and (value == num.value); +} + + +/* + BigInt != BigInt + ---------------- +*/ + +bool BigInt::operator!=(const BigInt& num) const { + return !(*this == num); +} + + +/* + BigInt < BigInt + --------------- +*/ + +bool BigInt::operator<(const BigInt& num) const { + if (sign == num.sign) { + if (sign == '+') { + if (value.length() == num.value.length()) + return value < num.value; + else + return value.length() < num.value.length(); + } + else + return -(*this) > -num; + } + else + return sign == '-'; +} + + +/* + BigInt > BigInt + --------------- +*/ + +bool BigInt::operator>(const BigInt& num) const { + return !((*this < num) or (*this == num)); +} + + +/* + BigInt <= BigInt + ---------------- +*/ + +bool BigInt::operator<=(const BigInt& num) const { + return (*this < num) or (*this == num); +} + + +/* + BigInt >= BigInt + ---------------- +*/ + +bool BigInt::operator>=(const BigInt& num) const { + return !(*this < num); +} + + +/* + BigInt == Integer + ----------------- +*/ + +bool BigInt::operator==(const long long& num) const { + return *this == BigInt(num); +} + + +/* + Integer == BigInt + ----------------- +*/ + +bool operator==(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) == rhs; +} + + +/* + BigInt != Integer + ----------------- +*/ + +bool BigInt::operator!=(const long long& num) const { + return !(*this == BigInt(num)); +} + + +/* + Integer != BigInt + ----------------- +*/ + +bool operator!=(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) != rhs; +} + + +/* + BigInt < Integer + ---------------- +*/ + +bool BigInt::operator<(const long long& num) const { + return *this < BigInt(num); +} + + +/* + Integer < BigInt + ---------------- +*/ + +bool operator<(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) < rhs; +} + + +/* + BigInt > Integer + ---------------- +*/ + +bool BigInt::operator>(const long long& num) const { + return *this > BigInt(num); +} + + +/* + Integer > BigInt + ---------------- +*/ + +bool operator>(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) > rhs; +} + + +/* + BigInt <= Integer + ----------------- +*/ + +bool BigInt::operator<=(const long long& num) const { + return !(*this > BigInt(num)); +} + + +/* + Integer <= BigInt + ----------------- +*/ + +bool operator<=(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) <= rhs; +} + + +/* + BigInt >= Integer + ----------------- +*/ + +bool BigInt::operator>=(const long long& num) const { + return !(*this < BigInt(num)); +} + + +/* + Integer >= BigInt + ----------------- +*/ + +bool operator>=(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) >= rhs; +} + + +/* + BigInt == String + ---------------- +*/ + +bool BigInt::operator==(const std::string& num) const { + return *this == BigInt(num); +} + + +/* + String == BigInt + ---------------- +*/ + +bool operator==(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) == rhs; +} + + +/* + BigInt != String + ---------------- +*/ + +bool BigInt::operator!=(const std::string& num) const { + return !(*this == BigInt(num)); +} + + +/* + String != BigInt + ---------------- +*/ + +bool operator!=(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) != rhs; +} + + +/* + BigInt < String + --------------- +*/ + +bool BigInt::operator<(const std::string& num) const { + return *this < BigInt(num); +} + + +/* + String < BigInt + --------------- +*/ + +bool operator<(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) < rhs; +} + + +/* + BigInt > String + --------------- +*/ + +bool BigInt::operator>(const std::string& num) const { + return *this > BigInt(num); +} + + +/* + String > BigInt + --------------- +*/ + +bool operator>(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) > rhs; +} + + +/* + BigInt <= String + ---------------- +*/ + +bool BigInt::operator<=(const std::string& num) const { + return !(*this > BigInt(num)); +} + + +/* + String <= BigInt + ---------------- +*/ + +bool operator<=(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) <= rhs; +} + + +/* + BigInt >= String + ---------------- +*/ + +bool BigInt::operator>=(const std::string& num) const { + return !(*this < BigInt(num)); +} + + +/* + String >= BigInt + ---------------- +*/ + +bool operator>=(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) >= rhs; +} + +#endif // BIG_INT_RELATIONAL_OPERATORS_HPP + + +/* + =========================================================================== + Math functions for BigInt + =========================================================================== +*/ + +#ifndef BIG_INT_MATH_FUNCTIONS_HPP +#define BIG_INT_MATH_FUNCTIONS_HPP + +#include + + + +/* + abs + --- + Returns the absolute value of a BigInt. +*/ + +BigInt abs(const BigInt& num) { + return num < 0 ? -num : num; +} + + +/* + big_pow10 + --------- + Returns a BigInt equal to 10^exp. + NOTE: exponent should be a non-negative integer. +*/ + +BigInt big_pow10(size_t exp) { + return BigInt("1" + std::string(exp, '0')); +} + + +/* + pow (BigInt) + ------------ + Returns a BigInt equal to base^exp. +*/ + +BigInt pow(const BigInt& base, int exp) { + if (exp < 0) { + if (base == 0) + throw std::logic_error("Cannot divide by zero"); + return abs(base) == 1 ? base : 0; + } + if (exp == 0) { + if (base == 0) + throw std::logic_error("Zero cannot be raised to zero"); + return 1; + } + + BigInt result = base, result_odd = 1; + while (exp > 1) { + if (exp % 2) + result_odd *= result; + result *= result; + exp /= 2; + } + + return result * result_odd; +} + + +/* + pow (Integer) + ------------- + Returns a BigInt equal to base^exp. +*/ + +BigInt pow(const long long& base, int exp) { + return pow(BigInt(base), exp); +} + + +/* + pow (String) + ------------ + Returns a BigInt equal to base^exp. +*/ + +BigInt pow(const std::string& base, int exp) { + return pow(BigInt(base), exp); + +} + + +/* + sqrt + ---- + Returns the positive integer square root of a BigInt using Newton's method. + NOTE: the input must be non-negative. +*/ + +BigInt sqrt(const BigInt& num) { + if (num < 0) + throw std::invalid_argument("Cannot compute square root of a negative integer"); + + // Optimisations for small inputs: + if (num == 0) + return 0; + else if (num < 4) + return 1; + else if (num < 9) + return 2; + else if (num < 16) + return 3; + + BigInt sqrt_prev = 0; + // The value for `sqrt_current` is chosen close to that of the actual + // square root. + // Since a number's square root has at least one less than half as many + // digits as the number, + // sqrt_current = 10^(half_the_digits_in_num - 1) + BigInt sqrt_current = big_pow10(num.to_string().size() / 2 - 1); + + while (abs(sqrt_current - sqrt_prev) > 1) { + sqrt_prev = sqrt_current; + sqrt_current = (num / sqrt_prev + sqrt_prev) / 2; + } + + return sqrt_current; +} + +#endif // BIG_INT_MATH_FUNCTIONS_HPP + + +/* + =========================================================================== + Binary arithmetic operators + =========================================================================== +*/ + +#ifndef BIG_INT_BINARY_ARITHMETIC_OPERATORS_HPP +#define BIG_INT_BINARY_ARITHMETIC_OPERATORS_HPP + +#include +#include +#include + + +const long long FLOOR_SQRT_LLONG_MAX = 3037000499; + + +/* + BigInt + BigInt + --------------- + The operand on the RHS of the addition is `num`. +*/ + +BigInt BigInt::operator+(const BigInt& num) const { + // if the operands are of opposite signs, perform subtraction + if (this->sign == '+' and num.sign == '-') { + BigInt rhs = num; + rhs.sign = '+'; + return *this - rhs; + } + else if (this->sign == '-' and num.sign == '+') { + BigInt lhs = *this; + lhs.sign = '+'; + return -(lhs - num); + } + + // identify the numbers as `larger` and `smaller` + std::string larger, smaller; + std::tie(larger, smaller) = get_larger_and_smaller(this->value, num.value); + + BigInt result; // the resultant sum + result.value = ""; // the value is cleared as the digits will be appended + short carry = 0, sum; + // add the two values + for (long i = larger.size() - 1; i >= 0; i--) { + sum = larger[i] - '0' + smaller[i] - '0' + carry; + result.value = std::to_string(sum % 10) + result.value; + carry = sum / (short) 10; + } + if (carry) + result.value = std::to_string(carry) + result.value; + + // if the operands are negative, the result is negative + if (this->sign == '-' and result.value != "0") + result.sign = '-'; + + return result; +} + + +/* + BigInt - BigInt + --------------- + The operand on the RHS of the subtraction is `num`. +*/ + +BigInt BigInt::operator-(const BigInt& num) const { + // if the operands are of opposite signs, perform addition + if (this->sign == '+' and num.sign == '-') { + BigInt rhs = num; + rhs.sign = '+'; + return *this + rhs; + } + else if (this->sign == '-' and num.sign == '+') { + BigInt lhs = *this; + lhs.sign = '+'; + return -(lhs + num); + } + + BigInt result; // the resultant difference + // identify the numbers as `larger` and `smaller` + std::string larger, smaller; + if (abs(*this) > abs(num)) { + larger = this->value; + smaller = num.value; + + if (this->sign == '-') // -larger - -smaller = -result + result.sign = '-'; + } + else { + larger = num.value; + smaller = this->value; + + if (num.sign == '+') // smaller - larger = -result + result.sign = '-'; + } + // pad the smaller number with zeroes + add_leading_zeroes(smaller, larger.size() - smaller.size()); + + result.value = ""; // the value is cleared as the digits will be appended + short difference; + long i, j; + // subtract the two values + for (i = larger.size() - 1; i >= 0; i--) { + difference = larger[i] - smaller[i]; + if (difference < 0) { + for (j = i - 1; j >= 0; j--) { + if (larger[j] != '0') { + larger[j]--; // borrow from the j-th digit + break; + } + } + j++; + while (j != i) { + larger[j] = '9'; // add the borrow and take away 1 + j++; + } + difference += 10; // add the borrow + } + result.value = std::to_string(difference) + result.value; + } + strip_leading_zeroes(result.value); + + // if the result is 0, set its sign as + + if (result.value == "0") + result.sign = '+'; + + return result; +} + + +/* + BigInt * BigInt + --------------- + Computes the product of two BigInts using Karatsuba's algorithm. + The operand on the RHS of the product is `num`. +*/ + +BigInt BigInt::operator*(const BigInt& num) const { + if (*this == 0 or num == 0) + return BigInt(0); + if (*this == 1) + return num; + if (num == 1) + return *this; + + BigInt product; + if (abs(*this) <= FLOOR_SQRT_LLONG_MAX and abs(num) <= FLOOR_SQRT_LLONG_MAX) + product = std::stoll(this->value) * std::stoll(num.value); + else { + // identify the numbers as `larger` and `smaller` + std::string larger, smaller; + std::tie(larger, smaller) = get_larger_and_smaller(this->value, num.value); + + size_t half_length = larger.size() / 2; + auto half_length_ceil = (size_t) ceil(larger.size() / 2.0); + + BigInt num1_high, num1_low; + num1_high = larger.substr(0, half_length); + num1_low = larger.substr(half_length); + + BigInt num2_high, num2_low; + num2_high = smaller.substr(0, half_length); + num2_low = smaller.substr(half_length); + + strip_leading_zeroes(num1_high.value); + strip_leading_zeroes(num1_low.value); + strip_leading_zeroes(num2_high.value); + strip_leading_zeroes(num2_low.value); + + BigInt prod_high, prod_mid, prod_low; + prod_high = num1_high * num2_high; + prod_low = num1_low * num2_low; + prod_mid = (num1_high + num1_low) * (num2_high + num2_low) + - prod_high - prod_low; + + add_trailing_zeroes(prod_high.value, 2 * half_length_ceil); + add_trailing_zeroes(prod_mid.value, half_length_ceil); + + strip_leading_zeroes(prod_high.value); + strip_leading_zeroes(prod_mid.value); + strip_leading_zeroes(prod_low.value); + + product = prod_high + prod_mid + prod_low; + } + strip_leading_zeroes(product.value); + + if (this->sign == num.sign) + product.sign = '+'; + else + product.sign = '-'; + + return product; +} + + +/* + divide + ------ + Helper function that returns the quotient and remainder on dividing the + dividend by the divisor, when the divisor is 1 to 10 times the dividend. +*/ + +std::tuple divide(const BigInt& dividend, const BigInt& divisor) { + BigInt quotient, remainder, temp; + + temp = divisor; + quotient = 1; + while (temp < dividend) { + quotient++; + temp += divisor; + } + if (temp > dividend) { + quotient--; + remainder = dividend - (temp - divisor); + } + + return std::make_tuple(quotient, remainder); +} + + +/* + BigInt / BigInt + --------------- + Computes the quotient of two BigInts using the long-division method. + The operand on the RHS of the division (the divisor) is `num`. +*/ + +BigInt BigInt::operator/(const BigInt& num) const { + BigInt abs_dividend = abs(*this); + BigInt abs_divisor = abs(num); + + if (num == 0) + throw std::logic_error("Attempted division by zero"); + if (abs_dividend < abs_divisor) + return BigInt(0); + if (num == 1) + return *this; + if (num == -1) + return -(*this); + + BigInt quotient; + if (abs_dividend <= LLONG_MAX and abs_divisor <= LLONG_MAX) + quotient = std::stoll(abs_dividend.value) / std::stoll(abs_divisor.value); + else if (abs_dividend == abs_divisor) + quotient = 1; + else { + quotient.value = ""; // the value is cleared as digits will be appended + BigInt chunk, chunk_quotient, chunk_remainder; + size_t chunk_index = 0; + chunk_remainder.value = abs_dividend.value.substr(chunk_index, abs_divisor.value.size() - 1); + chunk_index = abs_divisor.value.size() - 1; + while (chunk_index < abs_dividend.value.size()) { + chunk.value = chunk_remainder.value.append(1, abs_dividend.value[chunk_index]); + chunk_index++; + while (chunk < abs_divisor) { + quotient.value += "0"; + if (chunk_index < abs_dividend.value.size()) { + chunk.value.append(1, abs_dividend.value[chunk_index]); + chunk_index++; + } + else + break; + } + if (chunk == abs_divisor) { + quotient.value += "1"; + chunk_remainder = 0; + } + else if (chunk > abs_divisor) { + strip_leading_zeroes(chunk.value); + std::tie(chunk_quotient, chunk_remainder) = divide(chunk, abs_divisor); + quotient.value += chunk_quotient.value; + } + } + } + strip_leading_zeroes(quotient.value); + + if (this->sign == num.sign) + quotient.sign = '+'; + else + quotient.sign = '-'; + + return quotient; +} + + +/* + BigInt % BigInt + --------------- + Computes the modulo (remainder on division) of two BigInts. + The operand on the RHS of the modulo (the divisor) is `num`. +*/ + +BigInt BigInt::operator%(const BigInt& num) const { + BigInt abs_dividend = abs(*this); + BigInt abs_divisor = abs(num); + + if (abs_divisor == 0) + throw std::logic_error("Attempted division by zero"); + if (abs_divisor == 1 or abs_divisor == abs_dividend) + return BigInt(0); + + BigInt remainder; + if (abs_dividend <= LLONG_MAX and abs_divisor <= LLONG_MAX) + remainder = std::stoll(abs_dividend.value) % std::stoll(abs_divisor.value); + else if (abs_dividend < abs_divisor) + remainder = abs_dividend; + else { + BigInt quotient = abs_dividend / abs_divisor; + remainder = abs_dividend - quotient * abs_divisor; + } + strip_leading_zeroes(remainder.value); + + // remainder has the same sign as that of the dividend + remainder.sign = this->sign; + if (remainder.value == "0") // except if its zero + remainder.sign = '+'; + + return remainder; +} + + +/* + BigInt + Integer + ---------------- +*/ + +BigInt BigInt::operator+(const long long& num) const { + return *this + BigInt(num); +} + + +/* + Integer + BigInt + ---------------- +*/ + +BigInt operator+(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) + rhs; +} + + +/* + BigInt - Integer + ---------------- +*/ + +BigInt BigInt::operator-(const long long& num) const { + return *this - BigInt(num); +} + + +/* + Integer - BigInt + ---------------- +*/ + +BigInt operator-(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) - rhs; +} + + +/* + BigInt * Integer + ---------------- +*/ + +BigInt BigInt::operator*(const long long& num) const { + return *this * BigInt(num); +} + + +/* + Integer * BigInt + ---------------- +*/ + +BigInt operator*(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) * rhs; +} + + +/* + BigInt / Integer + ---------------- +*/ + +BigInt BigInt::operator/(const long long& num) const { + return *this / BigInt(num); +} + + +/* + Integer / BigInt + ---------------- +*/ + +BigInt operator/(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) / rhs; +} + + +/* + BigInt % Integer + ---------------- +*/ + +BigInt BigInt::operator%(const long long& num) const { + return *this % BigInt(num); +} + + +/* + Integer % BigInt + ---------------- +*/ + +BigInt operator%(const long long& lhs, const BigInt& rhs) { + return BigInt(lhs) % rhs; +} + + +/* + BigInt + String + --------------- +*/ + +BigInt BigInt::operator+(const std::string& num) const { + return *this + BigInt(num); +} + + +/* + String + BigInt + --------------- +*/ + +BigInt operator+(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) + rhs; +} + + +/* + BigInt - String + --------------- +*/ + +BigInt BigInt::operator-(const std::string& num) const { + return *this - BigInt(num); +} + + +/* + String - BigInt + --------------- +*/ + +BigInt operator-(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) - rhs; +} + + +/* + BigInt * String + --------------- +*/ + +BigInt BigInt::operator*(const std::string& num) const { + return *this * BigInt(num); +} + + +/* + String * BigInt + --------------- +*/ + +BigInt operator*(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) * rhs; +} + + +/* + BigInt / String + --------------- +*/ + +BigInt BigInt::operator/(const std::string& num) const { + return *this / BigInt(num); +} + + +/* + String / BigInt + --------------- +*/ + +BigInt operator/(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) / rhs; +} + + +/* + BigInt % String + --------------- +*/ + +BigInt BigInt::operator%(const std::string& num) const { + return *this % BigInt(num); +} + + +/* + String % BigInt + --------------- +*/ + +BigInt operator%(const std::string& lhs, const BigInt& rhs) { + return BigInt(lhs) % rhs; +} + +#endif // BIG_INT_BINARY_ARITHMETIC_OPERATORS_HPP + + +/* + =========================================================================== + Arithmetic-assignment operators + =========================================================================== +*/ + +#ifndef BIG_INT_ARITHMETIC_ASSIGNMENT_OPERATORS_HPP +#define BIG_INT_ARITHMETIC_ASSIGNMENT_OPERATORS_HPP + + + +/* + BigInt += BigInt + ---------------- +*/ + +BigInt& BigInt::operator+=(const BigInt& num) { + *this = *this + num; + + return *this; +} + + +/* + BigInt -= BigInt + ---------------- +*/ + +BigInt& BigInt::operator-=(const BigInt& num) { + *this = *this - num; + + return *this; +} + + +/* + BigInt *= BigInt + ---------------- +*/ + +BigInt& BigInt::operator*=(const BigInt& num) { + *this = *this * num; + + return *this; +} + + +/* + BigInt /= BigInt + ---------------- +*/ + +BigInt& BigInt::operator/=(const BigInt& num) { + *this = *this / num; + + return *this; +} + + +/* + BigInt %= BigInt + ---------------- +*/ + +BigInt& BigInt::operator%=(const BigInt& num) { + *this = *this % num; + + return *this; +} + + +/* + BigInt += Integer + ----------------- +*/ + +BigInt& BigInt::operator+=(const long long& num) { + *this = *this + BigInt(num); + + return *this; +} + + +/* + BigInt -= Integer + ----------------- +*/ + +BigInt& BigInt::operator-=(const long long& num) { + *this = *this - BigInt(num); + + return *this; +} + + +/* + BigInt *= Integer + ----------------- +*/ + +BigInt& BigInt::operator*=(const long long& num) { + *this = *this * BigInt(num); + + return *this; +} + + +/* + BigInt /= Integer + ----------------- +*/ + +BigInt& BigInt::operator/=(const long long& num) { + *this = *this / BigInt(num); + + return *this; +} + + +/* + BigInt %= Integer + ----------------- +*/ + +BigInt& BigInt::operator%=(const long long& num) { + *this = *this % BigInt(num); + + return *this; +} + + +/* + BigInt += String + ---------------- +*/ + +BigInt& BigInt::operator+=(const std::string& num) { + *this = *this + BigInt(num); + + return *this; +} + + +/* + BigInt -= String + ---------------- +*/ + +BigInt& BigInt::operator-=(const std::string& num) { + *this = *this - BigInt(num); + + return *this; +} + + +/* + BigInt *= String + ---------------- +*/ + +BigInt& BigInt::operator*=(const std::string& num) { + *this = *this * BigInt(num); + + return *this; +} + + +/* + BigInt /= String + ---------------- +*/ + +BigInt& BigInt::operator/=(const std::string& num) { + *this = *this / BigInt(num); + + return *this; +} + + +/* + BigInt %= String + ---------------- +*/ + +BigInt& BigInt::operator%=(const std::string& num) { + *this = *this % BigInt(num); + + return *this; +} + +#endif // BIG_INT_ARITHMETIC_ASSIGNMENT_OPERATORS_HPP + + +/* + =========================================================================== + Increment and decrement operators + =========================================================================== +*/ + +#ifndef BIG_INT_INCREMENT_DECREMENT_OPERATORS_HPP +#define BIG_INT_INCREMENT_DECREMENT_OPERATORS_HPP + + + +/* + Pre-increment + ------------- + ++BigInt +*/ + +BigInt& BigInt::operator++() { + *this += 1; + + return *this; +} + + +/* + Pre-decrement + ------------- + --BigInt +*/ + +BigInt& BigInt::operator--() { + *this -= 1; + + return *this; +} + + +/* + Post-increment + -------------- + BigInt++ +*/ + +BigInt BigInt::operator++(int) { + BigInt temp = *this; + *this += 1; + + return temp; +} + + +/* + Post-decrement + -------------- + BigInt-- +*/ + +BigInt BigInt::operator--(int) { + BigInt temp = *this; + *this -= 1; + + return temp; +} + +#endif // BIG_INT_INCREMENT_DECREMENT_OPERATORS_HPP + + +/* + =========================================================================== + I/O stream operators + =========================================================================== +*/ + +#ifndef BIG_INT_IO_STREAM_OPERATORS_HPP +#define BIG_INT_IO_STREAM_OPERATORS_HPP + + + +/* + BigInt from input stream + ------------------------ +*/ + +std::istream& operator>>(std::istream& in, BigInt& num) { + std::string input; + in >> input; + num = BigInt(input); // remove sign from value and set sign, if exists + + return in; +} + + +/* + BigInt to output stream + ----------------------- +*/ + +std::ostream& operator<<(std::ostream& out, const BigInt& num) { + if (num.sign == '-') + out << num.sign; + out << num.value; + + return out; +} + +#endif // BIG_INT_IO_STREAM_OPERATORS_HPP + +