BigInt计算器吐出稍微错误的结果

BigInt calculator spitting out slightly wrong results

本文关键字:错误 结果 计算器 BigInt      更新时间:2023-10-16

因此,对于我的作业,我必须创建一个适用于长度不超过 256 个字符的大整数的计算器。我正在做的作业的当前部分是让它与更大的数字相乘一起工作。DIGITS 是每个 Bigint 类的数字限制,目前为了调试而设置为 20,但最高可达 256

当进行 25 * 137 这样的计算时,我得到答案 3285 时应该是 3425。当我查看我为调试而放置的 cout 时,i 循环的第一次迭代工作得很好,并将 685 加到总和,即 5 * 137,所以工作得很好。但是,当它到达必须进行 i 循环的第二次迭代(它是 20 * 137(的位时,它得到了错误的答案,我无法弄清楚为什么。我有一种暗示,这与进位是两位数(14(有关,但我仍然无法真正弄清楚如何解决它。

显然有问题的主要实现是在 bigint 类的 * 运算符中。我知道这与<<或>>运算符无关,因为它们非常适合加法和减法。

bigint 类的完整代码如下:

#include <iostream>
#include <string>
#include "Bigint.h"
#include <cmath>
using namespace std;
Bigint::Bigint()
{
for (int i = DIGITS-1; i >= 0; --i) {
digits_[i] = 0;
}
}
ostream& operator<< (ostream& out, const Bigint& n)
{
string s = "";
bool found = false;
for (int i = DIGITS - 1; i >= 0; --i) {
if(n.digits_[i] > 0) {
found = true;
}
if(n.digits_[i] != 0 || found == true) {
s += char(n.digits_[i] + '0');
}
}
if (s == "") {
s = "0";
}
return out << s;
}
istream& operator>> (istream& in, Bigint& n)
{
// Extracts full-length number (does not work for any other length).
// All characters are assumed to be valid digits.
//
string s;
if (in >> s) {
for (int i = 0; i < DIGITS; ++i) {
n.digits_[i] = i < s.length() ? s[s.length() - 1 - i] - '0' : 0;
}
}
return in;
}
Bigint operator+ (const Bigint& n1, const Bigint& n2)
{
Bigint ret;
int cur_carry = 0;
for(int i = 0; i < DIGITS; ++i) {
int n1_digit = n1.get(i);
int n2_digit = n2.get(i);
if(n1_digit < 0 || n1_digit > 9) {
n1_digit = 0;
}
if(n2_digit < 0 || n2_digit > 9) {
n2_digit = 0;
}
//printf("n1 : %dn", n1_digit);
//printf("n2 : %dn", n2_digit);
int sum = n1_digit + n2_digit + cur_carry;
//cout << "sum : " << sum << endl;
cur_carry = Bigint::getCarry(sum);
//cout << "new carry : " << cur_carry << endl;
ret.set(i, Bigint::getDigitValue(sum));
//cout << "Set : " << i << "," << Bigint::getDigitValue(sum) << endl;
}
return ret;
}
Bigint operator* (const Bigint& n1, const Bigint& n2)
{
Bigint ret;
//int borrowed = 0;
Bigint sum;
for(int i = 0; i < DIGITS ; i++){
int n1_digit = n1.get(i);
//cout << "n2: " << n2_digit << endl;
Bigint temp;
if(n1_digit < 0 || n1_digit > 9) {
n1_digit = 0;
}
int carry = 0;
for (int j = 0; j < DIGITS ; j++){
int val = n1_digit * (pow(10, i)) * n2.get(j);
cout << "n1: " << n1_digit << endl;
cout << "n2: " << n2.get(j) << endl;
if(carry != 0){
temp.set(j, (Bigint::getDigitValue(val)) + carry);
cout << "Carry was " << carry << ", now set 0" << endl;
cout << "value to set: " << (Bigint::getDigitValue(val)) + carry << endl;
carry = 0;
}
else if(carry == 0){
temp.set(j, Bigint::getDigitValue(val));
cout << "value to set: " << (Bigint::getDigitValue(val))<< endl;
}
carry = (Bigint::getCarry(val) + carry);
cout << "carry: " << carry << endl;
}
cout << "Sum before adding temp: " << sum << endl;
sum = sum + temp;
cout << "Sum after adding temp: " << sum << endl;

}
ret = sum;
return ret; // Only correct when n2 equals 1.
}
int Bigint::get(int pos) const {
//Return address of digit for reading
int ret = digits_[pos];
return ret;
}
void Bigint::set(int pos, int val) {
this->digits_[pos] = val;
}
int Bigint::getCarry(int val) {
//Integer division, always floors
return val/10;
}
int Bigint::getDigitValue(int val) {
return val % 10;
}

头文件:


#ifndef BIGINT_H_
#define BIGINT_H_
#define DIGITS 20
class Bigint
{
public:
/**
* Creates a Bigint initialised to 0.
*/
Bigint();
/**
* Inserts n into stream or extracts n from stream.
*/
friend std::ostream& operator<< (std::ostream &out, const Bigint& n);
friend std::istream& operator>> (std::istream &in, Bigint& n);
/**
* Returns the sum, difference, product, or quotient of n1 and n2.
*/
friend Bigint operator* (const Bigint& n1, const Bigint& n2);
friend Bigint operator+ (const Bigint& n1, const Bigint& n2);
int get(int pos) const;
void set(int pos, int val);
static int getCarry(int val);
static int getDigitValue(int val);
private:
int digits_[DIGITS];
};
#endif // BIGINT_H_

主要:


#include <iostream>
#include "Bigint.h"
using namespace std;
int main(int argc, char *argv[]) 
{
Bigint n1, n2;
char op;
while (cin >> n1 >> op >> n2) {
switch (op) {
case '+' :
cout << n1 + n2 << endl;
break;
case '*' :
cout << n1 * n2 << endl;
break;
}
}

return 0;
}
}

你不应该使用这一行int val = n1_digit * (pow(10, i)) * n2.get(j); 因为它会给出整数溢出,因为你正在使用 bigintger 而是使用乘数中的数字并在结果后面添加零。

要添加的零数将取决于乘数数字的位置,您可以在重载 * 函数for(int i = 0; i < DIGITS ; i++)从此循环中找到变量 i

存在一些潜在问题

for (int j = 0; j < DIGITS ; j++){
int val = n1_digit * (pow(10, i)) * n2.get(j); // val % 10 == 0 for i > 0
// You should also be adding the carry to val
cout << "n1: " << n1_digit << endl;
cout << "n2: " << n2.get(j) << endl;
if(carry != 0){
temp.set(j, (Bigint::getDigitValue(val)) + carry);
// This can set temp[j] to values above 9 depending on the carry
cout << "Carry was " << carry << ", now set 0" << endl;
cout << "value to set: " << (Bigint::getDigitValue(val)) + carry << endl;
carry = 0;
}
else if(carry == 0){
temp.set(j, Bigint::getDigitValue(val));
cout << "value to set: " << (Bigint::getDigitValue(val))<< endl;
}
carry = (Bigint::getCarry(val) + carry);
cout << "carry: " << carry << endl;
}

因为你乘以 10 的幂,getDigitValue 和 getCarry 并没有按照你期望的方式行事。最好将 temp.set 的索引移位 i 而不是乘以 pow(10, i(。

我还建议清理这些案例。在这种情况下,if 和 else if 实际上都在做相同的工作,重置进位不会做任何事情。因此,这将具有完全相同的行为:

for (int j = 0; j < DIGITS ; j++){
int val = n1_digit * (pow(10, i)) * n2.get(j);
temp.set(j, (Bigint::getDigitValue(val)) + carry);
// If the carry is 0, the addition doesn't do anything
// You don't need to reset the carry to 0, since it's assigned here anyway
carry = (Bigint::getCarry(val) + carry);
}

没有大小写和打印语句,它更容易阅读,但在这里使用方法(getCarry和getDigitValue(仍然很难通过将相关操作移动到类的底部来看到问题。 进行更改将得到:

for (int j = 0; j < DIGITS ; j++){
int val = n1_digit * n2.get(j) + carry;
temp.set(i + j, Bigint::getDigitValue(val));
carry = Bigint::getCarry(val);
// The carry just gets added to the value at the beginning
// Everything else just works that way
}

您还需要更改 get 和 set 函数,以便它们不会越界工作:

int Bigint::get(int pos) const {
//Return address of digit for reading
if (pos >= DIGITS)
return 0;
int ret = digits_[pos];
return ret;
}
void Bigint::set(int pos, int val) {
if (pos >= DIGITS)
return ;
this->digits_[pos] = val;
}

使用此代码,我得到 3425 * 25 的 137。