Created
December 3, 2015 09:53
-
-
Save zxteloiv/64d0eb45b474f46574c1 to your computer and use it in GitHub Desktop.
An integer class with high precision support using strings
This file contains hidden or 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
// test2.cpp : Defines the entry point for the console application. | |
// | |
#include "stdafx.h" | |
#include <iostream> | |
#include <string> // 用字符串来表示HugeInt,方便输出 | |
using namespace std; | |
// HugeInt的每一位 | |
struct HugeIntDigit | |
{ | |
int data; // 每一位可取 0 ~ 9,用int表示 | |
HugeIntDigit* next; // 更高一位 | |
HugeIntDigit* front; // 更低一位 | |
HugeIntDigit() { | |
next = NULL; | |
front = NULL; | |
data = 0; | |
} | |
}; | |
typedef const HugeIntDigit* CONST_LPDIGIT; | |
class HugeIntList | |
{ | |
HugeIntDigit* head; | |
int bit_count; | |
public: | |
HugeIntList() { | |
head = new HugeIntDigit; | |
head->next = head; | |
head->front = head; | |
bit_count = 0; | |
} | |
~HugeIntList() { | |
Clean(); | |
} | |
void PushBack(int new_digit) { | |
HugeIntDigit* pNewDigit = new HugeIntDigit; | |
pNewDigit->data = new_digit; | |
pNewDigit->front = head->front; | |
head->front->next = pNewDigit; | |
head->front = pNewDigit; | |
pNewDigit->next = head; | |
bit_count++; | |
} | |
void PushFront(int new_digit) { | |
HugeIntDigit* pNewDigit = new HugeIntDigit; | |
pNewDigit->data = new_digit; | |
pNewDigit->next = head->next; | |
head->next->front = pNewDigit; | |
head->next = pNewDigit; | |
pNewDigit->front = head; | |
bit_count++; | |
} | |
int GetDigitCount() const { return bit_count; } | |
const HugeIntDigit* Begin() const { return head->next; } | |
const HugeIntDigit* End() const { return head; } | |
const HugeIntDigit* rBegin() const { return head->front; } | |
const HugeIntDigit* rEnd() const { return head; } | |
// 直接返回指针将可以修改链表值,这两个函数仅为了使用乘法方便 | |
HugeIntDigit* mutable_begin() { return head->next; } | |
HugeIntDigit* mutable_end() { return head; } | |
void Clean() { | |
HugeIntDigit* p = head->next; | |
while (p != head) { | |
HugeIntDigit* old_p = p; | |
p = p->next; | |
old_p->front->next = old_p->next; | |
old_p->next->front = old_p->front; | |
delete old_p; | |
} | |
bit_count = 0; | |
} | |
}; | |
//declare the class of HugeInt | |
class HugeInt | |
{ | |
// 构造函数 | |
public: | |
HugeInt(); | |
HugeInt(int lNum); // 使用一个普通int构造HugeInt 默认值为0 | |
HugeInt(const char *szNum); // 使用一个形如"12345...67890"的超大字符串构造HugeInt | |
// 拷贝构造函数 | |
HugeInt(const HugeInt &other); // 使用另一个HugeInt来复制出一个HugeInt对象 | |
// 赋值 | |
HugeInt& operator=(const HugeInt& other); // 把other的值赋予本HugeInt | |
// 计算操作 | |
HugeInt operator+(const HugeInt& other) const; // 加上一个HugeInt | |
HugeInt operator-(const HugeInt& other) const; // 减去一个HugeInt | |
HugeInt operator*(const HugeInt& other) const; // 乘以一个HugeInt | |
// 比较操作 | |
bool operator<(const HugeInt& other) const; // 是否比other值小 | |
bool operator==(const HugeInt& other) const; // 是否与other相等 | |
bool operator>(const HugeInt& other) const; // 是否比other值大 | |
const char* ToString(); // 把HugeInt的值用字符串表示出来 | |
private: | |
HugeIntList m_data; | |
std::string m_str; | |
bool m_negative; // 是否为负数 | |
}; | |
HugeInt::HugeInt() { | |
m_negative = false; | |
} | |
HugeInt::HugeInt(int lNum) | |
{ | |
int s = 0; // 绝对值 | |
if (lNum < 0) { // lNum为负数 | |
s = -lNum; | |
m_negative = true; | |
} else { | |
s = lNum; | |
m_negative = false; | |
} | |
if (0 == s) { // 待转换的整数为0 | |
m_data.PushBack(0); | |
return; | |
} | |
// 挨个取出s每一位的值,添加到HugeInt对应的list里 | |
int remain = s % 10; // 余数 | |
while (remain != 0) { | |
m_data.PushBack(remain); | |
s /= 10; | |
remain = s % 10; | |
} | |
} | |
HugeInt::HugeInt(const char *szNum) | |
{ | |
int pos = 0; | |
if ('-' == szNum[pos]) { // 负数 | |
m_negative = true; | |
pos++; | |
} else if ('+' == szNum[pos]) { // 正数 | |
m_negative = false; | |
pos++; | |
} else { // 没有标明,默认为正数 | |
m_negative = false; | |
} | |
while (szNum[pos] == '0'){ // 跳过前面多个连续的0 | |
pos++; | |
} | |
for ( ; szNum[pos] != '\0'; pos++) { | |
m_data.PushFront(szNum[pos] - '0'); // 因为字符串从高位开始数起,每次取出一位要加到链表最前 | |
} | |
} | |
//拷贝构造函数 | |
HugeInt::HugeInt(const HugeInt &other) | |
{ | |
// 挨个遍历other的每一位,加到自己的bit链表最后 | |
for (const HugeIntDigit* pDigit = other.m_data.Begin(); pDigit != other.m_data.End(); pDigit = pDigit->next) { | |
m_data.PushBack(pDigit->data); | |
} | |
m_negative = other.m_negative; | |
} | |
HugeInt& HugeInt::operator =(const HugeInt &other) { | |
m_data.Clean(); | |
// 挨个遍历other的每一位,加到自己的bit链表最后 | |
for (const HugeIntDigit* pDigit = other.m_data.Begin(); pDigit != other.m_data.End(); pDigit = pDigit->next) { | |
m_data.PushBack(pDigit->data); | |
} | |
m_negative = other.m_negative; | |
return (*this); | |
} | |
HugeInt HugeInt::operator +(const HugeInt& other) const | |
{ | |
// 异号整数相加,将后者变号,再做同号减法 | |
if (m_negative != other.m_negative) { | |
HugeInt inverse(other); | |
inverse.m_negative = !(inverse.m_negative); | |
return ((*this) - inverse); | |
} | |
HugeInt sum; // 返回值 | |
sum.m_negative = m_negative; | |
const HugeIntDigit* p1 = m_data.Begin(); // 取出自己的个位数 | |
const HugeIntDigit* p2 = other.m_data.Begin(); // 取出other的个位数 | |
int add_up = 0; // 保存进位 | |
while (p1 != m_data.End() && p2 != other.m_data.End()) { | |
int n = p1->data + p2->data + add_up; // 两位相加,加上进位 | |
add_up = n / 10; | |
n = n % 10; | |
sum.m_data.PushBack(n); | |
p1 = p1->next; | |
p2 = p2->next; | |
} | |
while (p1 != m_data.End()) { // 如果自己还有没加完的高位 | |
int n = p1->data + add_up; | |
add_up = n / 10; | |
n = n % 10; | |
sum.m_data.PushBack(n); | |
p1 = p1->next; | |
} | |
while (p2 != other.m_data.End()) { // 如果other还有没加完的高位 | |
int n = p2->data + add_up; | |
add_up = n / 10; | |
n = n % 10; | |
sum.m_data.PushBack(n); | |
p2 = p2->next; | |
} | |
// 自己和other相等,并且最高位需要进位 | |
if (add_up > 0) { | |
sum.m_data.PushBack(add_up); | |
} | |
return sum; | |
} | |
bool HugeInt::operator <(const HugeInt &other) const { | |
// 负数一定小于正数 | |
if (m_negative && !(other.m_negative)) { | |
return true; | |
} | |
if (!m_negative && other.m_negative) { | |
return false; | |
} | |
if (m_data.GetDigitCount() > other.m_data.GetDigitCount()) // 位数大的,负数则小,正数则大 | |
return m_negative; | |
if (m_data.GetDigitCount() < other.m_data.GetDigitCount()) // 位数小的,正数则小,负数则大 | |
return (!m_negative); | |
// 符号相同,位数也相同,从最高位挨个比较 | |
const HugeIntDigit* p1 = m_data.rBegin(); | |
const HugeIntDigit* p2 = other.m_data.rBegin(); | |
while (p1 != m_data.rEnd() && p2 != other.m_data.rEnd()) { | |
if (p1->data < p2->data) // 最高位小,正数则小负数则大 | |
return !m_negative; | |
if (p1->data > p2->data) // 最高位大,正数则大负数则小 | |
return m_negative; | |
p1 = p1->next; | |
p2 = p2->next; | |
} | |
return false; // 相等 | |
} | |
bool HugeInt::operator ==(const HugeInt &other) const { | |
if (m_negative == other.m_negative) { // 符号相同 | |
const HugeIntDigit* p1 = m_data.Begin(); | |
const HugeIntDigit* p2 = other.m_data.Begin(); | |
while (p1 != m_data.End() && p2 != other.m_data.End()) { | |
if (p1->data != p2->data) | |
return false; | |
p1 = p1->next; | |
p2 = p2->next; | |
} | |
if (p1 == m_data.End() && p2 == other.m_data.End()) { | |
return true; | |
} | |
} | |
return false; | |
} | |
bool HugeInt::operator >(const HugeInt& other) const { | |
// 正数大于负数 | |
if (m_negative && !(other.m_negative)) { | |
return false; | |
} | |
if (!m_negative && other.m_negative) { | |
return true; | |
} | |
if (m_data.GetDigitCount() > other.m_data.GetDigitCount()) // 位数大的,负数则小,正数则大 | |
return !m_negative; | |
if (m_data.GetDigitCount() < other.m_data.GetDigitCount()) // 位数小的,正数则小,负数则大 | |
return m_negative; | |
// 符号相同,位数也相同,从最高位挨个比较 | |
const HugeIntDigit* p1 = m_data.rBegin(); | |
const HugeIntDigit* p2 = other.m_data.rBegin(); | |
while (p1 != m_data.rEnd() && p2 != other.m_data.rEnd()) { | |
// p1, p2分别为当前最高位 | |
if (p1->data < p2->data) // 最高位小,正数则小负数则大 | |
return m_negative; | |
if (p1->data > p2->data) // 最高位大,正数则大负数则小 | |
return !m_negative; | |
} | |
return false; // 相等 | |
} | |
HugeInt HugeInt::operator -(const HugeInt& other) const | |
{ | |
// 异号整数相减,将后者变号,再做同号加法 | |
if (m_negative != other.m_negative) { // 负-正 | |
HugeInt inverse(other); | |
inverse.m_negative = !(inverse.m_negative); | |
return ((*this) + inverse); | |
} | |
if (*this == other) { | |
return 0; | |
} | |
HugeInt val; // 返回值 | |
const HugeIntDigit* p1 = NULL; | |
const HugeIntDigit* p1end = NULL; | |
const HugeIntDigit* p2 = NULL; | |
const HugeIntDigit* p2end = NULL; | |
if ((*this) > other) { | |
val.m_negative = false; | |
if (m_negative) { // 大负-小负 | |
p1 = other.m_data.Begin(); | |
p1end = other.m_data.End(); | |
p2 = m_data.Begin(); | |
p2end = m_data.End(); | |
} else { // 大正数-小正数 | |
p1 = m_data.Begin(); | |
p1end = m_data.End(); | |
p2 = other.m_data.Begin(); | |
p2end = other.m_data.End(); | |
} | |
} else { | |
val.m_negative = true; | |
if (m_negative) { // 小负-大负 | |
p1 = m_data.Begin(); | |
p1end = m_data.End(); | |
p2 = other.m_data.Begin(); | |
p2end = other.m_data.End(); | |
} else { // 小正数-大正数 | |
p1 = other.m_data.Begin(); | |
p1end = other.m_data.End(); | |
p2 = m_data.Begin(); | |
p2end = m_data.End(); | |
} | |
} | |
int borrow = 0; // 借位 | |
while (p1 != p1end && p2 != p2end) { | |
HugeIntDigit* pDigit = new HugeIntDigit; | |
int n = p1->data - borrow - p2->data; | |
if (n >= 0) { | |
borrow = 0; | |
} else { | |
borrow = 1; | |
n += 10; | |
} | |
val.m_data.PushBack(n); | |
val.ToString(); | |
p1 = p1->next; | |
p2 = p2->next; | |
} | |
while (p1 != p1end) { | |
int n = p1->data - borrow; | |
if (n >= 0) { | |
borrow = 0; | |
} else { | |
borrow = 1; | |
n += 10; | |
} | |
val.m_data.PushBack(n); | |
p1 = p1->next; | |
} | |
return val; | |
} | |
HugeInt HugeInt::operator *(const HugeInt& other) const { | |
HugeInt res; | |
if (m_negative == other.m_negative) { // 同号相乘为正 | |
res.m_negative = false; | |
} else { | |
res.m_negative = true; | |
} | |
const HugeIntDigit* p1 = m_data.Begin(); // 自己是被乘数 | |
const HugeIntDigit* p1end = m_data.End(); | |
const HugeIntDigit* p2 = other.m_data.Begin(); // other是乘数 | |
const HugeIntDigit* p2end = other.m_data.End(); | |
// 记录结果与当前乘数对应的前一位,例如当前用乘数的第2位做乘法,则此指针指向计算结果的第1位 | |
HugeIntDigit* p_start = res.m_data.mutable_begin(); | |
HugeIntDigit* p = p_start; // 记录乘的结果应该加在已有结果的哪一位上 | |
int mul_up = 0; // 乘法进位 | |
while (p2 != p2end) { | |
p = p_start->next; // 加在下一位上 | |
while (p1 != p1end) { | |
int n = p2->data * p1->data + mul_up; | |
mul_up = n / 10; | |
n = n % 10; | |
if (p == res.m_data.mutable_end()) { | |
res.m_data.PushBack(n); | |
} else { // 该位已存在 | |
n += p->data; // 加上已有的值 | |
mul_up += n / 10; // 增加新的进位 | |
n = n % 10; // 该位的新值 | |
p->data = n; | |
p = p->next; | |
} | |
p1 = p1->next; | |
} | |
while (mul_up > 0) { // 如果还有没有进位没有加上 | |
int n = mul_up; | |
mul_up = n / 10; | |
n = n % 10; | |
if (p == res.m_data.mutable_end()) { | |
res.m_data.PushBack(n); | |
} else { // 该位已经存在 | |
n += p->data; | |
mul_up += n / 10; | |
n = n % 10; | |
p->data = n; | |
p = p->next; | |
} | |
} | |
p2 = p2->next; // 取出乘数的高一位 | |
p_start = p_start->next; // 对应地应该加在高一位上 | |
p1 = m_data.Begin(); // 被乘数重新从最低位开始 | |
} | |
return res; | |
} | |
const char* HugeInt::ToString() | |
{ | |
const HugeIntDigit* pDigit = m_data.rBegin(); | |
while (pDigit != m_data.rEnd() && 0 == pDigit->data) { // 跳过前导多个0 | |
pDigit = pDigit->front; | |
} | |
if (pDigit == m_data.rEnd()) { // 已经到最后了,即这个数字只有多个0组成 | |
m_negative = false; // 强制改为正数 | |
m_str.assign("0"); | |
return m_str.c_str(); | |
} | |
m_str.clear(); | |
if (m_negative) | |
m_str.append("-"); // 加上负号 | |
char temp_str[2] = { '0', '\0' }; | |
while (pDigit != m_data.rEnd()) { | |
temp_str[0] = pDigit->data + '0'; | |
m_str.append(temp_str); // 把数字转换为字符串 | |
pDigit = pDigit->front; | |
} | |
return m_str.c_str(); | |
} | |
int main() { | |
cout << "Input the arithmetic formular: (like 1 + 2, -12 - -5, 0 * 999)" << endl; | |
string s1, s2; | |
char op; | |
cin >> s1 >> op >> s2; | |
HugeInt h1(s1.c_str()); | |
HugeInt h2(s2.c_str()); | |
HugeInt result; | |
cout << h1.ToString() << endl; | |
cout << h2.ToString() << endl; | |
switch (op) { | |
case '+': | |
result = h1 + h2; | |
break; | |
case '-': | |
result = h1 - h2; | |
break; | |
case '*': | |
result = h1 * h2; | |
break; | |
default: | |
cout << "Input error, calculation failed." << endl; | |
return -1; | |
} | |
cout << s1 << " " << op << " " << s2 << " = " << result.ToString() << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment