将大数字乘以字符串 - 一切都很好,除非数字中有9

时间:2018-04-06 10:07:30

标签: c++ string multiplication largenumber

我必须在C ++中创建一个类--BigInteger - 它可以处理以字符串形式编写的非常大的数字。作为任务的一部分,我还必须预定义乘法,这就是我所做的:

BigInteger& BigInteger::operator*(const BigInteger& rhs)
{
    string tmp(num.length() + rhs.num.length(), '0');
    //a string in which I'll be temporarily storing the result
    char carry = '0';
    int d = 0;
    //I'll use this to move with one index to the left in the result 
    for (int i = num.length() - 1; i >= 0; --i)
    //start with the multiplying from the end of the first number
    {
        carry = '0';
        for (int j = rhs.num.length() - 1, z = tmp.length() - 1 - d; j >= 0; --j, --z)
        //start with the multiplying from the end of the second number and begin filling the result string (again from the end)
        {
            tmp[z] = ((tmp[z] - '0') + (num[i] - '0') * (rhs.num[j] - '0') + (carry - '0')) + '0';
            //basically add to the current number in the result the multiplication of the respective digits in the two original numbers, plus the carry from the previous mutiplication
            carry = ((tmp[z] - '0') / 10) + '0';
            tmp[z] = ((tmp[z] - '0') % 10) + '0';
            if (j == 0 && carry != '0')
            {
                tmp[z - 1] = carry;
            }
        }
        ++d;
    }
    if (carry != '0')
    {
        tmp[0] = carry;
    }
    else
    {
        tmp.erase(0, 1);
    }
    num = tmp;
    return *this;
}

即使是像123456788 * 887654321这样的大数字,一切正常,但是一旦我尝试将包含9的数字(包括6789 * 9876等较小的数字)相乘,不仅中间数字关闭,而且6789之间存在差异* 9876和9876 * 6789,包括“+”和撇号等符号在后一种情况下大致位于中心。

这里有没有人遇到过这样的问题或者有什么可能导致它的问题?

编辑: 这是预定义的<<操作者:

ostream& operator<<(ostream& out, const BigInteger& rhs)
{
    out << rhs.num;
    return out;
}

和我的“主要”:

#include "BigInteger.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
    BigInteger num3("123456788");
    BigInteger num4("887654321");
    cout << num3 * num4 << endl;
    //cout << num4 * num3 << endl;
}

和我的班级:

#ifndef H_BIGINTEGER
#define H_BIGINTEGER

#include <iostream>
#include <string>
using namespace std;
//I know I shouldn't have defined a namespace in the headers file, but left it for brevity's sake

class BigInteger
{
    friend ostream& operator<<(ostream&, const BigInteger&);

public:
    BigInteger();
    BigInteger(string);
    ~BigInteger();
    BigInteger(const BigInteger&);
    BigInteger& operator=(const BigInteger&);

    BigInteger& operator+(BigInteger&);
    BigInteger& operator-(BigInteger&);
    BigInteger& operator*(const BigInteger&);

private:
    string num;
};

我正在使用的构造函数只是:

BigInteger::BigInteger(string num)
    :num(num)
{}

1 个答案:

答案 0 :(得分:2)

std::string char已签名,当您添加'0'并且稍后将其用于carrytmp[z]时,它会变为否定,因此最好存储它在一个临时的ìnt

6789*9876
---------
           int(char(res + '0'))
-------------------------------
0+9*6+0=54 102
0+9*7+5=68 116
0+9*8+6=78 126
0+9*9+7=88 -120
8+8*6+0=56 104
8+8*7+5=69 117
8+8*8+6=78 126
8+8*9+7=87 -121
9+7*6+0=51 99
8+7*7+5=62 110
7+7*8+6=69 117
8+7*9+6=77 125
2+6*6+0=38 86
9+6*7+3=54 102
7+6*8+5=60 108
7+6*9+6=67 115

所以你可以改变你的代码:

    int res = ((tmp[z] - '0') + (num[i] - '0') * (rhs.num[j] - '0') + (carry - '0'));
    carry = (res / 10) + '0';
    tmp[z] = (res % 10) + '0';
    if (j == 0)
    {
        tmp[z - 1] = carry;
    }

Demo