C++ 整型大数运算项目
- 一、项目介绍
- 二、项目变量成员
- 三、项目实现
- 四、项目源代码展示
-
- [在 Big_integer.h 中:](#在 Big_integer.h 中:)
- [在 Big_integer.cpp 中:](#在 Big_integer.cpp 中:)
- 五、测试准确性
- 六、优化方向
一、项目介绍
整型大数运算,也就是大整数运算,是为了计算数据大小超过 long long 类型表示范围 [ -2 ^ 63, 2 ^ 63 - 1 ] 的整型数据。
整个项目最核心的目标是实现 四则运算 与 取模 ,外加 输入输出 与 两个大整数的大小判断。
这里实现的四则运算借用的是小学时候使用的竖式计算,将思想转化为实际的代码。
以下代码环境为 VS 2022 C++。
二、项目变量成员
cpp
namespace my
{
class Big_integer
{
private:
enum Big_integer_sign // 使用枚举体,防止赋值错误
{
positive = '+',
negative = '-',
};
std::string _nums; // 使用 string 存储具体数据
Big_integer_sign _sign; // 将符号单独列出,便于判断
};
}
-
存储数字的容器使用 string ,方便其他数据转换为 string 再转为 Big_integer 。
-
将符号单独列出是因为用 string 存储符号会导致后面运算的附加判断很麻烦。
-
使用枚举体,防止赋值其他符号出现错误。
三、项目实现
构造函数
因为使用的是 string 存储数据,我们可以使用 to_string 函数将内置类型全部转换为 string 类型,不过要对 string 中的符号判断,例如出现 "-10" 这种数字前出现负号的 string 需要设计函数将符号与数字分离。
cpp
Big_integer(const std::string& str = "0")
:_sign(signExpressSolve(str))
,_nums(str, signLastIndex(str) + 1)
{
;
}
Big_integer(const Big_integer& number)
{
_nums = number._nums;
_sign = number._sign;
}
Big_integer(const long double number)
{
*this = Big_integer(std::to_string((long long)number));
}
Big_integer(const double number)
{
*this = Big_integer(std::to_string((long long)number));
}
Big_integer(const float number)
{
*this = Big_integer(std::to_string((int)number));
}
Big_integer(const unsigned long long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const long long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const unsigned long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const unsigned int number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const int number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const unsigned short number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const short number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const char* str)
{
*this = Big_integer(std::string(str));
}
cpp
static Big_integer_sign signExpressSolve(const std::string& str)
{
signed char sign = 1;
for (auto e : str)
{
if (e == negative)
{
sign = -sign;
}
else if (e == positive)
{
;
}
else
{
break;
}
}
return sign == 1 ? positive : negative;
}
static size_t signLastIndex(const std::string& str)
{
size_t index = -1;
for (auto e : str)
{
if (e == negative || e == positive)
{
++index;
}
else
{
break;
}
}
return index;
}
加法
加法计算时只需模拟进位即可:
不过要注意符号,如下图:
正数 + 正数 和 负数 + 负数 在加法中不受影响,但是 正数 + 负数 和 负数 + 正数 需要转为减法,这意味其中一个数要 变号 。
这里先对 += 进行重载,因为返回的是 引用 ,会少一次拷贝。
每位数计算后应该倒序存储,因为 string 空间是连续的,头插消耗大:
cpp
Big_integer& Big_integer::operator+=(const Big_integer& number)
{
if (_sign == positive && number._sign == negative) // 正数 + 负数
{ // number 变号使用减法,再变回来
number.signChange();
*this -= number;
number.signChange();
return *this;
}
if (_sign == negative && number._sign == positive) // 负数 + 正数
{ // this 变号使用减法,再变回来
signChange();
*this -= number;
signChange();
return *this;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int next = 0; // 高位存储
std::string copy;
copy.reserve((len1 > len2 ? len1 : len2) + 5);
while (len1 >= 0 || len2 >= 0 || next > 0)
{
int num1 = len1 >= 0 ? _nums[len1--] - '0' : 0;
int num2 = len2 >= 0 ? number._nums[len2--] - '0' : 0;
int ret = num1 + num2 + next; // 当前位数计算
next = ret / 10; // 进高位
ret = ret % 10; // 保留低位
copy += (ret + '0'); // 存进结果
}
reverse(copy.begin(), copy.end()); // 翻转
_nums = std::move(copy); // 获取结果
return *this;
}
cpp
void signChange() const
{
int* change = (int*)(&_sign);
*change = (_sign == positive ? negative : positive);
}
另外,与 内置类型 相加时会将 内置类型 隐式类型转换为 Big_integer,不用再写其他转换的函数。
接下来关于加法相关的函数都可以复用 += 运算符:
-
- 重载运算符直接放在全局,等价于 大数 + 内置类型 和 内置类型 + 大数 。
-
后置 和 前置 ++ 复用 += 即可。
cpp
Big_integer operator++(int) // 后置 ++
{
Big_integer temp = *this;
++(*this);
return temp;
}
Big_integer& operator++() // 前置 ++
{
return *this += 1;
}
Big_integer operator+() const // +数 等于一个表达式,这里只是闲的事不多加上的
{
return *this;
}
Big_integer operator+(const Big_integer& number1, const Big_integer& number2)
{ // 为方便使用,将 + 放在全局
return Big_integer(number1) += number2;
}
减法
使用减法模拟时要注意谁的绝对值最大谁在前 ,保证 大 - 小,不然会出错:
同加法一样要注意符号,如下图:
正数 - 正数 和 负数 - 负数 在减法中不受影响,但是 正数 - 负数 和 负数 - 正数 需要转为加法,这意味其中一个数要 变号 。
注意,上面视图中的 9 - 12 是要将绝对值大的当 被减数,小的当 减数,意味着要额外判断:
cpp
Big_integer& Big_integer::operator-=(const Big_integer& number)
{
if (_sign == positive && number._sign == negative)
{
number.signChange();
*this += number;
number.signChange();
return *this;
}
if (_sign == negative && number._sign == positive)
{
signChange();
*this += number;
signChange();
return *this;
}
int change = 1; // this 是否变号
int compare = justThanSize(number); // 绝对值比较
if (compare < 0)
{
change = -1; // this 的值小于 number,则 this 需要变号
}
else if (compare == 0) // 特判解决当相减为零时出现负号情况,如:-3 + 3 = -0
{
return *this = 0;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int next = 0; // 借位
std::string copy;
copy.reserve((len1 > len2 ? len1 : len2) + 5);
while (len1 >= 0 || len2 >= 0)
{
int num1 = len1 >= 0 ? _nums[len1--] - '0' : 0;
int num2 = len2 >= 0 ? number._nums[len2--] - '0' : 0;
int ret = change * (num1 - num2) + next;
if (ret < 0) // 当前位为负数,向上借 1
{
next = -1; // 上一位被借 1,需要 -1
ret += 10; // 上一位借的 1 ,在当前位为 10
}
else // 不为负数则不用借
{
next = 0;
}
copy += (ret + '0');
}
//最高位去零
while (copy.size() > 1 && copy[copy.size() - 1] == '0')
{
copy.pop_back();
}
if (change == -1) // 变号
{
signChange();
}
reverse(copy.begin(), copy.end());
_nums = std::move(copy);
return *this;
}
cpp
int justThanSize(const Big_integer& number) const
{
int len1 = (int)_nums.size() - 1;
int len2 = (int)number._nums.size() - 1;
if (len1 != len2)
{
return len1 - len2;
}
for (int i = 0; i <= len1; ++i)
{
if (_nums[i] != number._nums[i])
{
return _nums[i] - number._nums[i];
}
}
return 0;
}
接下来处理于减法相关函数:
cpp
Big_integer operator--(int)
{
Big_integer temp = *this;
--(*this);
return temp;
}
Big_integer& operator--()
{
return *this -= 1;
}
Big_integer operator-() const // -数 表示变号
{
Big_integer temp = *this;
temp.signChange();
return temp;
}
// 同理于 + 运算符函数
Big_integer operator-(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) -= number2;
}
乘法
乘法竖式计算有两种,第一种先将各位数结果保存,后进位。第二种是边乘边进位:
另外,对于结果存储位数大小是根据两个相乘的数的位数个数决定的:
所以两个不等于 0 的整数,其中一个位数为 x,另一个为 y,两者相乘时位数是相加的,则结果的位数 z 范围为 [ x + y - 1,x + y]。
这里为了保证计算,位数空间开到 x + y ,若位数数量为 x + y - 1,只需一次最高位去零即可。
对于符号的处理,因为先实现的是 *= 运算符函数,需要注意对 this 变号:
先计算再进位
cpp
Big_integer& Big_integer::operator*=(const Big_integer& number)
{
if (*this == 0 || number == 0) // 有 0 时直接返回 0
{ // 注意这里还没有实现大数的判断
return *this = 0;
}
// 符号问题只需关注*this
if (_sign == positive && number._sign == negative)
{
_sign = negative;
}
else if (_sign == negative && number._sign == negative)
{
_sign = positive;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int maxN = (len1 + 1) + (len2 + 1);
int index = maxN - 1;
std::vector<int> copy(maxN, 0); // signed char 存储会有溢出风险
// 乘法
while (len1 >= 0) // 先将相乘结果存储
{
int i = maxN - index - 1;
int num1 = len1 >= 0 ? _nums[len1] - '0' : 0;
for (int line = len2; line >= 0; --line)
{
int num2 = line >= 0 ? number._nums[line] - '0' : 0;
copy[i] += num1 * num2;
++i;
}
--index;
--len1;
}
for (int i = 0; i < copy.size(); ++i) // 后进位
{
if (copy[i] > 9)
{
copy[i + 1] += copy[i] / 10;
copy[i] %= 10;
}
copy[i] += '0';
}
// 最高位去零
if (copy[copy.size() - 1] == '0')
{
copy.pop_back();
}
reverse(copy.begin(), copy.end());
_nums = std::string(copy.begin(), copy.end());
return *this;
}
边计算边进位
cpp
Big_integer& Big_integer::operator*=(const Big_integer& number)
{
//if (*this == 0 || number == 0) // 有 0 时直接返回 0
//{
// return *this = 0;
//}
// 符号问题只需关注*this
if (_sign == positive && number._sign == negative)
{
_sign = negative;
}
else if (_sign == negative && number._sign == negative)
{
_sign = positive;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int maxN = (len1 + 1) + (len2 + 1);
int index = maxN - 1;
std::string copy(maxN, '0');
// 乘法
while (len1 >= 0)
{
int next = 0;
int i = maxN - index - 1;
int num1 = len1 >= 0 ? _nums[len1] - '0' : 0;
for (int line = len2; line >= 0; --line)
{
int num2 = line >= 0 ? number._nums[line] - '0' : 0;
int ret = num1 * num2 + next;
next = ret / 10;
ret = ret % 10;
next += ((copy[i] - '0') + ret) / 10;
copy[i] = ((copy[i] - '0') + ret) % 10 + '0';
++i;
}
if (next > 0)
{
copy[i] += next;
}
--index;
--len1;
}
// 最高位去零
if (copy[copy.size() - 1] == '0')
{
copy.pop_back();
}
reverse(copy.begin(), copy.end());
_nums = std::move(copy);
return *this;
}
接下来处理 * 号:
cpp
Big_integer operator*(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) += number2;
}
除法与取模
除法与取模计算效率比较低下:
注意试乘方法从 0 到 9 ,可用二分进行小优化,要注意借用乘法、加法、减法时会将数字变号,所以将符号留到最后再判断:
cpp
Big_integer& Big_integer::operator/=(const Big_integer& number)
{
// 除数不能为零
assert(number != 0);
// 除数大于被除数直接为零
if (justThanSize(number) < 0)
{
return *this = 0;
}
Big_integer_sign sign1 = _sign;
Big_integer_sign sign2 = number._sign;
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int condition = len1 - len2; // 对齐
int count = 0;
std::string copy;
copy.reserve(len1);
while (len1 - len2 - count >= 0)
{
int left = -1;
int right = 10;
while (left + 1 < right) // 二分试乘
{
int mid = left + (right - left) / 2;
if (justThanSize(number * mid * _pow(10, condition)) >= 0)
{
left = mid;
}
else
{
right = mid;
}
}
if (left != 0) // 结果减(加)去试乘的数
{
if (_sign == number._sign)
{
*this -= (left * number) * _pow(10, condition);
}
else
{
*this += (left * number) * _pow(10, condition);
}
}
copy += (left + '0');
++count;
--condition;
}
// 除后符号放后面,防止加减乘过程中为零负号变为正号
if (sign1 == positive && sign2 == negative)
{
_sign = negative;
}
else if (sign1 == negative && sign2 == negative)
{
_sign = positive;
}
else
{
_sign = sign1;
}
if (copy[0] == '0') // 最高位去零
{
copy.erase(copy.begin());
}
_nums = std::move(copy);
return *this;
}
_pow 函数是位数对齐防止溢出,取模运算直接复用除乘减法即可:
cpp
Big_integer Big_integer::_pow(const Big_integer& number, const int& index)
{
if (index == 0)
{
return 1;
}
Big_integer temp = _pow(number, index / 2);
if (index % 2 == 0)
{
return temp * temp;
}
else
{
return temp * temp * number;
}
}
Big_integer& Big_integer::operator%=(const Big_integer& number)
{
Big_integer temp = *this;
temp /= number;
return *this -= temp * number;
}
Big_integer operator/(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) /= number2;
}
Big_integer operator%(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) %= number2;
}
判断
判断只需写好 == 与 < ,其他复用两者:
cpp
bool operator!(const Big_integer& number)
{
return number == 0;
}
bool operator!=(const Big_integer& number1, const Big_integer& number2)
{
return !(number1 == number2);
}
bool operator>=(const Big_integer& number1, const Big_integer& number2)
{
return !(number1 < number2);
}
bool operator> (const Big_integer& number1, const Big_integer& number2)
{
return !(number1 <= number2);
}
bool operator<=(const Big_integer& number1, const Big_integer& number2)
{
return number1 < number2 || number1 == number2;
}
bool operator==(const Big_integer& number1, const Big_integer& number2)
{
if (number1._sign == number2._sign && number1._nums == number2._nums)
{
return true;
}
else
{
return false;
}
}
bool operator< (const Big_integer& number1, const Big_integer& number2)
{
if (number1._sign == Big_integer::negative && number2._sign == Big_integer::positive)
{
return true;
}
if (number1._sign == Big_integer::positive && number2._sign == Big_integer::negative)
{
return false;
}
int lessNum = number1.justThanSize(number2);
if (lessNum < 0)
{
return number1._sign == Big_integer::positive ? true : false;
}
if (lessNum > 0)
{
return number1._sign == Big_integer::positive ? false : true;
}
return false;
}
输入输出
cpp
std::ostream& my::operator<<(std::ostream& out, const my::Big_integer& number)
{
if (number._sign == my::Big_integer::negative)
{
out << '-';
}
out << number._nums;
return out;
}
std::istream& my::operator>>(std::istream& in, my::Big_integer& number)
{
std::string temp;
in >> temp;
number = temp;
return in;
}
四、项目源代码展示
在 Big_integer.h 中:
cpp
#pragma once
#include <iostream>
#include <string>
namespace my
{
class Big_integer
{
private:
enum Big_integer_sign // 使用枚举体,防止赋值错误
{
positive = '+',
negative = '-',
};
std::string _nums; // 使用 string 存储具体数据
Big_integer_sign _sign; // 将符号单独列出,便于判断
public: // 构造函数
Big_integer(const std::string& str = "0")
:_sign(signExpressSolve(str))
,_nums(str, signLastIndex(str) + 1)
{
;
}
Big_integer(const Big_integer& number)
{
_nums = number._nums;
_sign = number._sign;
}
Big_integer(const long double number)
{
*this = Big_integer(std::to_string((long long)number));
}
Big_integer(const double number)
{
*this = Big_integer(std::to_string((long long)number));
}
Big_integer(const float number)
{
*this = Big_integer(std::to_string((int)number));
}
Big_integer(const unsigned long long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const long long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const unsigned long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const long number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const unsigned int number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const int number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const unsigned short number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const short number)
{
*this = Big_integer(std::to_string(number));
}
Big_integer(const char* str)
{
*this = Big_integer(std::string(str));
}
public: // 加法
Big_integer operator++(int) // 后置 ++
{
Big_integer temp = *this;
++(*this);
return temp;
}
Big_integer& operator++() // 前置 ++
{
return *this += 1;
}
Big_integer operator+() const // +数 等于一个表达式,这里只是闲的事不多加上的
{
return *this;
}
Big_integer& operator+= (const Big_integer& number);
public: // 减法
Big_integer operator--(int)
{
Big_integer temp = *this;
--(*this);
return temp;
}
Big_integer& operator--()
{
return *this -= 1;
}
Big_integer operator-() const // -数 表示变号
{
Big_integer temp = *this;
temp.signChange();
return temp;
}
Big_integer& operator-=(const Big_integer& number);
public:
Big_integer& operator*=(const Big_integer& number);
Big_integer& operator/=(const Big_integer& number);
Big_integer& operator%=(const Big_integer& number);
friend std::ostream& operator<<(std::ostream& out, const Big_integer& number);
friend std::istream& operator>>(std::istream& in, Big_integer& number);
public: // 判断
friend bool operator==(const Big_integer& number1, const Big_integer& number2);
friend bool operator< (const Big_integer& number1, const Big_integer& number2);
public:
void swap(Big_integer& number)
{
std::swap(_nums, number._nums);
std::swap(_sign, number._sign);
}
private:
static Big_integer _pow(const Big_integer& number, const int& index);
void signChange() const
{
int* change = (int*)(&_sign);
*change = (_sign == positive ? negative : positive);
}
int justThanSize(const Big_integer& number) const;
static Big_integer_sign signExpressSolve(const std::string& str);
static size_t signLastIndex(const std::string& str);
};
bool operator!(const Big_integer& number);
bool operator!=(const Big_integer& number1, const Big_integer& number2);
bool operator>=(const Big_integer& number1, const Big_integer& number2);
bool operator> (const Big_integer& number1, const Big_integer& number2);
bool operator<=(const Big_integer& number1, const Big_integer& number2);
Big_integer operator+(const Big_integer& number1, const Big_integer& number2);
Big_integer operator-(const Big_integer& number1, const Big_integer& number2);
Big_integer operator*(const Big_integer& number1, const Big_integer& number2);
Big_integer operator/(const Big_integer& number1, const Big_integer& number2);
Big_integer operator%(const Big_integer& number1, const Big_integer& number2);
typedef Big_integer bint;
}
在 Big_integer.cpp 中:
cpp
#include "Big_integer.h"
#include <cassert>
namespace my
{
int Big_integer::justThanSize(const Big_integer& number) const
{
int len1 = (int)_nums.size() - 1;
int len2 = (int)number._nums.size() - 1;
if (len1 != len2)
{
return len1 - len2;
}
for (int i = 0; i <= len1; ++i)
{
if (_nums[i] != number._nums[i])
{
return _nums[i] - number._nums[i];
}
}
return 0;
}
Big_integer::Big_integer_sign Big_integer::signExpressSolve(const std::string& str)
{
signed char sign = 1;
for (auto e : str)
{
if (e == negative)
{
sign = -sign;
}
else if (e == positive)
{
;
}
else
{
break;
}
}
return sign == 1 ? positive : negative;
}
size_t Big_integer::signLastIndex(const std::string& str)
{
size_t index = -1;
for (auto e : str)
{
if (e == negative || e == positive)
{
++index;
}
else
{
break;
}
}
return index;
}
Big_integer Big_integer::_pow(const Big_integer& number, const int& index)
{
if (index == 0)
{
return 1;
}
Big_integer temp = _pow(number, index / 2);
if (index % 2 == 0)
{
return temp * temp;
}
else
{
return (temp * temp) * number;
}
}
Big_integer& Big_integer::operator+=(const Big_integer& number)
{
if (_sign == positive && number._sign == negative) // 正数 + 负数
{ // number 变号使用减法,再变回来
number.signChange();
*this -= number;
number.signChange();
return *this;
}
if (_sign == negative && number._sign == positive) // 负数 + 正数
{ // this 变号使用减法,再变回来
signChange();
*this -= number;
signChange();
return *this;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int next = 0; // 高位存储
std::string copy;
copy.reserve((len1 > len2 ? len1 : len2) + 5);
while (len1 >= 0 || len2 >= 0 || next > 0)
{
int num1 = len1 >= 0 ? _nums[len1--] - '0' : 0;
int num2 = len2 >= 0 ? number._nums[len2--] - '0' : 0;
int ret = num1 + num2 + next; // 当前位数计算
next = ret / 10; // 进高位
ret = ret % 10; // 保留低位
copy += (ret + '0'); // 存进结果
}
reverse(copy.begin(), copy.end()); // 翻转
_nums = std::move(copy); // 获取结果
return *this;
}
Big_integer& Big_integer::operator-=(const Big_integer& number)
{
if (_sign == positive && number._sign == negative)
{
number.signChange();
*this += number;
number.signChange();
return *this;
}
if (_sign == negative && number._sign == positive)
{
signChange();
*this += number;
signChange();
return *this;
}
int change = 1; // this 是否变号
int compare = justThanSize(number); // 绝对值比较
if (compare < 0)
{
change = -1; // this 的值小于 number,则 this 需要变号
}
else if (compare == 0) // 特判解决当相减为零时出现负号情况,如:-3 + 3 = -0
{
return *this = 0;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int next = 0; // 借位
std::string copy;
copy.reserve((len1 > len2 ? len1 : len2) + 5);
while (len1 >= 0 || len2 >= 0)
{
int num1 = len1 >= 0 ? _nums[len1--] - '0' : 0;
int num2 = len2 >= 0 ? number._nums[len2--] - '0' : 0;
int ret = change * (num1 - num2) + next;
if (ret < 0) // 当前位为负数,向上借 1
{
next = -1; // 上一位被借 1,需要 -1
ret += 10; // 上一位借的 1 ,在当前位为 10
}
else // 不为负数则不用借
{
next = 0;
}
copy += (ret + '0');
}
//最高位去零
while (copy.size() > 1 && copy[copy.size() - 1] == '0')
{
copy.pop_back();
}
if (change == -1) // 变号
{
signChange();
}
reverse(copy.begin(), copy.end());
_nums = std::move(copy);
return *this;
}
Big_integer& Big_integer::operator*=(const Big_integer& number)
{
if (*this == 0 || number == 0) // 有 0 时直接返回 0
{
return *this = 0;
}
// 符号问题只需关注*this
if (_sign == positive && number._sign == negative)
{
_sign = negative;
}
else if (_sign == negative && number._sign == negative)
{
_sign = positive;
}
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int maxN = (len1 + 1) + (len2 + 1);
int index = maxN - 1;
std::string copy(maxN, '0');
// 乘法
while (len1 >= 0)
{
int next = 0;
int i = maxN - index - 1;
int num1 = len1 >= 0 ? _nums[len1] - '0' : 0;
for (int line = len2; line >= 0; --line)
{
int num2 = line >= 0 ? number._nums[line] - '0' : 0;
int ret = num1 * num2 + next;
next = ret / 10;
ret = ret % 10;
next += ((copy[i] - '0') + ret) / 10;
copy[i] = ((copy[i] - '0') + ret) % 10 + '0';
++i;
}
if (next > 0)
{
copy[i] += next;
}
--index;
--len1;
}
// 最高位去零
if (copy[copy.size() - 1] == '0')
{
copy.pop_back();
}
reverse(copy.begin(), copy.end());
_nums = std::move(copy);
return *this;
}
Big_integer& Big_integer::operator/=(const Big_integer& number)
{
// 除数不能为零
assert(number != 0);
// 除数大于被除数直接为零
if (justThanSize(number) < 0)
{
return *this = 0;
}
Big_integer_sign sign1 = _sign;
Big_integer_sign sign2 = number._sign;
int len1 = _nums.size() - 1;
int len2 = number._nums.size() - 1;
int condition = len1 - len2; // 对齐
int count = 0;
std::string copy;
copy.reserve(len1);
while (len1 - len2 - count >= 0)
{
int left = -1;
int right = 10;
while (left + 1 < right) // 二分试乘
{
int mid = left + (right - left) / 2;
if (justThanSize(number * mid * _pow(10, condition)) >= 0)
{
left = mid;
}
else
{
right = mid;
}
}
if (left != 0) // 结果减去试乘的数
{
if (_sign == number._sign)
{
*this -= (left * number) * _pow(10, condition);
}
else
{
*this += (left * number) * _pow(10, condition);
}
}
copy += (left + '0');
++count;
--condition;
}
// 除后符号放后面,防止加减乘过程中为零负号变为正号
if (sign1 == positive && sign2 == negative)
{
_sign = negative;
}
else if (sign1 == negative && sign2 == negative)
{
_sign = positive;
}
else
{
_sign = sign1;
}
if (copy[0] == '0') // 最高位去零
{
copy.erase(copy.begin());
}
_nums = std::move(copy);
return *this;
}
Big_integer& Big_integer::operator%=(const Big_integer& number)
{
Big_integer temp = *this;
temp /= number;
return *this -= temp * number;
}
Big_integer operator+(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) += number2;
}
Big_integer operator-(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) -= number2;
}
Big_integer operator*(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) *= number2;
}
Big_integer operator/(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) /= number2;
}
Big_integer operator%(const Big_integer& number1, const Big_integer& number2)
{
return Big_integer(number1) %= number2;
}
bool operator! (const Big_integer& number)
{
return number == 0;
}
bool operator!=(const Big_integer& number1, const Big_integer& number2)
{
return !(number1 == number2);
}
bool operator>=(const Big_integer& number1, const Big_integer& number2)
{
return !(number1 < number2);
}
bool operator> (const Big_integer& number1, const Big_integer& number2)
{
return !(number1 <= number2);
}
bool operator<=(const Big_integer& number1, const Big_integer& number2)
{
return number1 < number2 || number1 == number2;
}
bool operator==(const Big_integer& number1, const Big_integer& number2)
{
if (number1._sign == number2._sign && number1._nums == number2._nums)
{
return true;
}
else
{
return false;
}
}
bool operator< (const Big_integer& number1, const Big_integer& number2)
{
if (number1._sign == Big_integer::negative && number2._sign == Big_integer::positive)
{
return true;
}
if (number1._sign == Big_integer::positive && number2._sign == Big_integer::negative)
{
return false;
}
int lessNum = number1.justThanSize(number2);
if (lessNum < 0)
{
return number1._sign == Big_integer::positive ? true : false;
}
if (lessNum > 0)
{
return number1._sign == Big_integer::positive ? false : true;
}
return false;
}
std::ostream& my::operator<<(std::ostream& out, const my::Big_integer& number)
{
if (number._sign == my::Big_integer::negative)
{
out << '-';
}
out << number._nums;
return out;
}
std::istream& my::operator>>(std::istream& in, my::Big_integer& number)
{
std::string temp;
in >> temp;
number = temp;
return in;
}
}
五、测试准确性
如有错误或Bug,可以评论区提出,谢谢!!!
在 test.cpp 中:
cpp
#include "Big_integer.h"
using namespace std;
void testAddSub()
{
long long a = 0;
long long b = 0;
my::bint c = 0;
my::bint d = 0;
int count1 = 0;
int count2 = 0;
for (int i = 0; i < 100000; ++i)
{
a = ((rand() % 10000) * 100 + (rand() % 10000)) * 1000 + (rand() % 10000);
b = ((rand() % 10000) * 100 + (rand() % 10000)) * 1000 + (rand() % 10000);
c = a;
d = b;
if (c + d == a + b)
{
++count1;
}
else
{
cout << "a = " << a << " " << "b = " << b << endl;
cout << "c = " << c << " " << "d = " << d << endl;
cout << "a + b == " << a + b << endl;
cout << "c + d == " << c + d << endl;
}
if (c - d == a - b)
{
++count2;
}
else
{
cout << "a = " << a << " " << "b = " << b << endl;
cout << "c = " << c << " " << "d = " << d << endl;
cout << "a - b == " << a - b << endl;
cout << "c - d == " << c - d << endl;
}
}
cout << "count1 == " << count1 << endl;
cout << "count2 == " << count2 << endl;
}
void testMul()
{
int a = 0;
int b = 0;
my::bint c = 0;
my::bint d = 0;
int count = 0;
for (int i = 0; i < 100000; ++i)
{
int getSign1 = rand() % 2;
int getSign2 = rand() % 2;
a = rand();
b = rand();
if (getSign1 == 1)
{
a = -a;
}
if (getSign2 == 1)
{
b = -b;
}
c = a;
d = b;
if (c * d == a * b)
{
++count;
}
else
{
cout << "a = " << a << " " << "b = " << b << endl;
cout << "c = " << c << " " << "d = " << d << endl;
cout << "a * b == " << a * b << endl;
cout << "c * d == " << c * d << endl;
}
}
cout << "count == " << count << endl;
}
void testdiv()
{
long long a = 0;
long long b = 0;
my::bint c = 0;
my::bint d = 0;
int count = 0;
for (int i = 0; i < 10000; ++i)
{
int getSign = rand() % 2;
int getSign2 = rand() % 2;
a = ((rand() % 10000) * 100 + (rand() % 10000)) * 1000 + (rand() % 10000);;
b = ((rand() % 10000) * 100 + (rand() % 10000)) * 1000 + (rand() % 10000);;
if (getSign == 1)
{
a = -a;
}
if (getSign2 == 1)
{
b = -b;
}
c = a;
d = b;
if (c / d == a / b)
{
++count;
}
else
{
cout << "a = " << a << " " << "b = " << b << endl;
cout << "c = " << c << " " << "d = " << d << endl;
cout << "a / b == " << a / b << endl;
cout << "c / d == " << c / d << endl;
}
}
cout << "count == " << count << endl;
}
void testImp()
{
long long a = 0;
long long b = 0;
my::bint c = 0;
my::bint d = 0;
int count = 0;
for (int i = 0; i < 100000; ++i)
{
int getSign = rand() % 2;
int getSign2 = rand() % 2;
a = ((rand() % 10000) * 100 + (rand() % 10000)) * 1000 + (rand() % 10000);
b = ((rand() % 10000) * 100 + (rand() % 10000)) * 1000 + (rand() % 10000);
if (getSign == 1)
{
a = -a;
}
if (getSign2 == 1)
{
b = -b;
}
c = a;
d = b;
if (c % d == a % b)
{
++count;
}
else
{
cout << "a = " << a << " " << "b = " << b << endl;
cout << "c = " << c << " " << "d = " << d << endl;
cout << "a % b == " << a % b << endl;
cout << "c % d == " << c % d << endl;
}
}
cout << "count == " << count << endl;
}
int main()
{
srand((unsigned int)time(NULL));
testAddSub();
testMul();
testdiv();
testImp();
return 0;
}
六、优化方向
-
将数据倒着存储,可以减少每次计算后翻转效率的损失。
-
乘除使用更优的算法。
-
使用内置类型进行计算,提高计算速度,减少储存的浪费。