BigInteger.h:
#ifndef _BIGINTEGER_H_
#define _BIGINTEGER_H_
#include <iostream>
#include <limits>
#include <string>
class BigInteger {
public:
BigInteger();
BigInteger(long long);
/**
* @brief 以8/10/16进制字符串为参数构造BigInteger
* ex: 070, 128, 0x1f
*/
BigInteger(const std::string &);
BigInteger(const BigInteger &);
BigInteger &operator+();
BigInteger operator-() const;
BigInteger &operator++();
BigInteger operator++(int);
BigInteger &operator--();
BigInteger operator--(int);
BigInteger &operator=(const BigInteger &);
BigInteger &operator+=(const BigInteger &);
friend BigInteger operator+(const BigInteger &, const BigInteger &);
BigInteger &operator-=(const BigInteger &);
friend BigInteger operator-(const BigInteger &, const BigInteger &);
BigInteger &operator*=(const BigInteger &);
friend BigInteger operator*(const BigInteger &, const BigInteger &);
BigInteger &operator/=(const BigInteger &);
friend BigInteger operator/(const BigInteger &, const BigInteger &);
BigInteger &operator%=(const BigInteger &);
friend BigInteger operator%(const BigInteger &, const BigInteger &);
friend std::istream &operator>>(std::istream &, const BigInteger &);
friend std::ostream &operator<<(std::ostream &, const BigInteger &);
friend bool operator==(const BigInteger &, const BigInteger &);
friend bool operator!=(const BigInteger &, const BigInteger &);
friend bool operator>(const BigInteger &, const BigInteger &);
friend bool operator>=(const BigInteger &, const BigInteger &);
friend bool operator<(const BigInteger &, const BigInteger &);
friend bool operator<=(const BigInteger &, const BigInteger &);
private:
bool isNegtive;
std::string mData;
};
#endif
BigInteger.cpp
#include "BigInteger.h"
#include <stdexcept>
#include <vector>
#include <cstring>
#include <deque>
#include <cassert>
using namespace std;
static bool convertBase(int base0, int base1, const char *from, std::string &to);
static int dexCompare(const std::string &a, const std::string &b);
static string Add(const std::string &a, const std::string &b);
static string Minus(const std::string &a, const std::string &b);
static string Multiply(const std::string &a, const std::string &b);
static string Divide(const std::string &a, const std::string &b);
BigInteger::BigInteger() : isNegtive(false), mData("0")
{
}
BigInteger::BigInteger(long long num) : isNegtive(num < 0), mData(to_string(abs(num)))
{
}
BigInteger::BigInteger(const std::string &sNum)
{
size_t b = sNum.find_first_not_of(' ');
if (b == string::npos)
goto error;
if (sNum[b] == '-') {
isNegtive = true;
b = sNum.find_first_not_of(' ', b + 1);
if (b == string::npos)
goto error;
} else if (isdigit(sNum[b]))
isNegtive = false;
else
goto error;
int base;
if (sNum[b] == '0') {
if (b + 1 == sNum.size()) {
isNegtive = false;
mData = "0";
return;
}
if (sNum[b + 1] == 'x' || sNum[b + 1] == 'X') {
base = 16;
b += 2;
} else {
base = 8;
++b;
}
if (b == sNum.size())
goto error;
} else
base = 10;
if (convertBase(base, 10, sNum.c_str() + b, mData))
return;
error:
throw invalid_argument(sNum);
}
BigInteger::BigInteger(const BigInteger &rhs) : isNegtive(rhs.isNegtive), mData(rhs.mData)
{
}
BigInteger &BigInteger::operator=(const BigInteger &rhs)
{
if (this != &rhs) {
isNegtive = rhs.isNegtive;
mData = rhs.mData;
}
return *this;
}
BigInteger &BigInteger::operator+()
{
return *this;
}
BigInteger BigInteger::operator-() const
{
BigInteger bi(*this);
if (mData != "0")
bi.isNegtive = !isNegtive;
return bi;
}
BigInteger &BigInteger::operator++()
{
*this += 1;
return *this;
}
BigInteger BigInteger::operator++(int)
{
BigInteger bi(*this);
bi += 1;
return bi;
}
BigInteger &BigInteger::operator--()
{
*this -= 1;
return *this;
}
BigInteger BigInteger::operator--(int)
{
BigInteger bi(*this);
bi -= 1;
return bi;
}
bool operator==(const BigInteger &a, const BigInteger &b)
{
return a.isNegtive == b.isNegtive && a.mData == b.mData;
}
bool operator!=(const BigInteger &a, const BigInteger &b)
{
return !(a == b);
}
bool operator>(const BigInteger &a, const BigInteger &b)
{
if (a.isNegtive != b.isNegtive)
return !a.isNegtive;
return a.isNegtive ? dexCompare(a.mData, b.mData) < 0 : dexCompare(a.mData, b.mData) > 0;
}
bool operator>=(const BigInteger &a, const BigInteger &b)
{
return a > b || a == b;
}
bool operator<(const BigInteger &a, const BigInteger &b)
{
return !(a >= b);
}
bool operator<=(const BigInteger &a, const BigInteger &b)
{
return !(a > b);
}
BigInteger &BigInteger::operator+=(const BigInteger &rhs)
{
if (isNegtive) {
if (rhs.isNegtive) {
mData = Add(mData, rhs.mData);
} else {
int cmp = dexCompare(mData, rhs.mData);
if (cmp == 0) {
isNegtive = false;
mData = "0";
} else if (cmp > 0) {
mData = Minus(mData, rhs.mData);
} else {
isNegtive = false;
mData = Minus(rhs.mData, mData);
}
}
} else {
if (!rhs.isNegtive)
mData = Add(mData, rhs.mData);
else {
int cmp = dexCompare(mData, rhs.mData);
if (cmp == 0) {
isNegtive = false;
mData = "0";
} else if (cmp > 0) {
mData = Minus(mData, rhs.mData);
} else {
isNegtive = true;
mData = Minus(rhs.mData, mData);
}
}
}
return *this;
}
BigInteger operator+(const BigInteger &a, const BigInteger &b)
{
BigInteger c(a);
return c += b;
}
BigInteger &BigInteger::operator-=(const BigInteger &rhs)
{
*this += -rhs;
return *this;
}
BigInteger operator-(const BigInteger &a, const BigInteger &b)
{
BigInteger c(a);
return c -= b;
}
BigInteger &BigInteger::operator*=(const BigInteger &rhs)
{
if (mData != "0") {
if (rhs.mData == "0") {
isNegtive = false;
mData = "0";
} else {
isNegtive = (isNegtive && !rhs.isNegtive) || (!isNegtive && rhs.isNegtive);
mData = Multiply(mData, rhs.mData);
}
}
return *this;
}
BigInteger operator*(const BigInteger &a, const BigInteger &b)
{
BigInteger c(a);
return c *= b;
}
BigInteger &BigInteger::operator/=(const BigInteger &rhs)
{
if (rhs.mData == "0")
throw invalid_argument("divided by zero");
if (mData != "0") {
mData = Divide(mData, rhs.mData);
if (mData == "0")
isNegtive = false;
else
isNegtive = (isNegtive && !rhs.isNegtive) || (!isNegtive && rhs.isNegtive);
}
return *this;
}
BigInteger operator/(const BigInteger &a, const BigInteger &b)
{
BigInteger c(a);
return c /= b;
}
BigInteger &BigInteger::operator%=(const BigInteger &rhs)
{
BigInteger r = *this / rhs;
*this -= r * rhs;
return *this;
}
BigInteger operator%(const BigInteger &a, const BigInteger &b)
{
BigInteger c(a);
return c %= b;
}
//BigInteger BigInteger::operator%(const BigInteger &rhs) const
//{
// BigInteger bi(*this);
// bi %= rhs;
// return bi;
//}
std::istream &operator>>(std::istream &is, BigInteger &bi)
{
string num;
is >> num;
try {
BigInteger x(num);
bi = x;
} catch (invalid_argument &ia) {
cerr << ia.what() << endl;
}
return is;
}
std::ostream &operator<<(std::ostream &os, const BigInteger &bi)
{
if (bi.isNegtive)
os << '-';
return os << bi.mData;
}
static inline int char2int(char c)
{
if (isdigit(c))
return c - '0';
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
if (c >= 'a' && c <= 'f')
return c - 'a';
return std::numeric_limits<int>::max();
}
static bool convertBase(int base0, int base1, const char *from, std::string &to)
{
if (base0 == base1) {
to.assign(from);
return true;
}
int len = strlen(from);
vector<int> a(len);
deque<char> dq;
for (int i = 0; i < len; ++i)
if ((a[len - i - 1] = char2int(from[i])) >= base0)
return false;
while (len) {
for (int i = len - 1; i; --i) {
a[i - 1] += a[i] % base1 * base0;
a[i] /= base1;
}
dq.push_front(a[0] % base1 + '0');
a[0] /= base1;
while (len && a[len - 1] == 0)
--len;
}
to.assign(dq.cbegin(), dq.cend());
return true;
}
/**
* @brief 比较两个十进制大数的大小
*
* @param a
* @param b
* @return int
*/
static int dexCompare(const std::string &a, const std::string &b)
{
if (a.size() != b.size())
return a.size() > b.size() ? 1 : -1;
return a.compare(b);
}
/**
* @brief 相加两个正的十进制大数
*
* @param a
* @param b
*/
static string Add(const std::string &a, const std::string &b)
{
int i = a.size() - 1, j = b.size() - 1, feed = 0;
deque<char> dq;
while (i >= 0 && j >= 0) {
int x = a[i--] - '0' + b[j--] - '0' + feed;
dq.push_front(x % 10 + '0');
feed = x / 10;
}
while (i >= 0) {
int x = a[i--] - '0' + feed;
dq.push_front(x % 10 + '0');
feed = x / 10;
}
while (j >= 0) {
int x = b[j--] - '0' + feed;
dq.push_front(x % 10 + '0');
feed = x / 10;
}
while (feed) {
dq.push_front(feed % 10 + '0');
feed /= 10;
}
return string(dq.begin(), dq.end());
}
static string Minus(const std::string &a, const std::string &b)
{
if (a == b)
return "0";
assert(dexCompare(a, b) > 0);
int i = a.size() - 1, j = b.size() - 1, borrow = 0;
deque<char> dq;
while (i >= 0 && j >= 0) {
int x = a[i--] - '0' - (b[j--] - '0') - borrow;
if (x < 0) {
borrow = 1;
x += 10;
} else
borrow = 0;
dq.push_front(x + '0');
}
while (i >= 0) {
int x = a[i--] - '0' - borrow;
if (x < 0) {
borrow = 1;
x += 10;
} else
borrow = 0;
dq.push_front(x + '0');
}
while (!dq.empty() && dq.front() == '0')
dq.pop_front();
return string(dq.begin(), dq.end());
}
static string Multiply(const std::string &a, int b)
{
if (a == "0" || b == 0)
return "0";
int i = a.size() - 1, feed = 0;
deque<char> dq;
while (i >= 0) {
int x = (a[i--] - '0') * b + feed;
dq.push_front(x % 10 + '0');
feed = x / 10;
}
while (feed) {
dq.push_front(feed % 10 + '0');
feed /= 10;
}
return string(dq.begin(), dq.end());
}
static string Multiply(const std::string &a, const std::string &b)
{
assert(a != "0" && b != "0");
string res = "0";
for (int j = b.size() - 1, n = 0; j >= 0; --j, ++n) {
string temp = Multiply(a, b[j] - '0');
if (temp != "0") {
temp += string(n, '0');
res = Add(res, temp);
}
}
return res;
}
static int tryDivide(const std::string &a, const std::string &b)
{
assert(dexCompare(a, b + "0") < 0);
int l = 0, r = 10;
while (l + 1 < r) {
int mid = (l + r) / 2;
dexCompare(Multiply(b, mid), a) > 0 ? r = mid : l = mid;
}
return l;
}
static string Divide(const std::string &a, const std::string &b)
{
assert(!b.empty() && b != "0");
if (dexCompare(a, b) < 0)
return "0";
string curr = b.size() == 1 ? "0" : a.substr(0, b.size() - 1), res;
size_t p = b.size() - 1;
while (p < a.size()) {
if (curr == "0")
curr = string(1, a[p++]);
else
curr.push_back(a[p++]);
int r = tryDivide(curr, b);
if (!res.empty() || r)
res.push_back(r + '0');
curr = Minus(curr, Multiply(b, r));
}
return res;
}