C++ Large Number Arithmetic

2019-02-11 03:54发布

问题:

I'm developing a class for large number arithmetic, it now knows how to do addition, handle cin and cout.

It, however has very limited and basic subtraction functionality, and does not know how to handle negative. But that can be easily resolved.

My question is this, how to do multiplication.

I will detail how it handle cin and cout here.

For cin, it will save integers to value[500], for example, 50 will be saved to value[498] and value[499]. BUT NOT value[0] and value[1]

For cout, it will scan for the first non-zero value from value[0] to value[499], and then output from that non-zero value to the end. Also, if it finds no non-zero value, it will output 0.

Here's my code:

#include <iostream>

using namespace std;

class largeNumber {
public:
    int value[500];
    largeNumber()
    {
        for ( int i = 0 ; i < 500 ; ++ i )
        {
            value[i] = 0;
        }
    }
    //below are arithmetic operations
    largeNumber operator+(const largeNumber &ln) const
    {
        largeNumber result;
        for ( int i = 0 ; i < 500 ; ++ i )
        {
            result.value[i] = value[i] + ln.value[i];
        }
        for ( int i = 499 ; i >= 0 ; -- i )
        {
            if ( result.value[i] >= 10 )
            {
                result.value[i - 1] += ( result.value[i] / 10 );
                result.value[i] %= 10;
            }
        }
        return result;
    }
    largeNumber operator-(const largeNumber &ln) const
    {
        largeNumber result;

        for ( int i = 0 ; i < 500 ; ++ i )
        {
            result.value[i] = value[i] - ln.value[i];
        }
        for ( int i = 499 ; i >= 0 ; -- i )
        {
            if ( result.value[i] < 0 )
            {
                --result.value[i - 1];
                result.value[i] += 10;
            }
        }
        return result;
    }
    largeNumber operator*(const largeNumber &ln) const
    {
        largeNumber result;
        for ( int x = 499 ; x >= 0 ; -- x )
        {
            for ( int y = 499 ; y >= 0 ; -- y )
            {
                int dx = 499 - x;
                int dy = 499 - y;
                int dr = dx + dy;
                int r = 499 - dr;
                if ( r >= 0 && r <= 499 )
                {
                    result.value[r] = value[x] * ln.value[y];
                }
            }
        }
        for ( int i = 499 ; i >= 0 ; -- i )
        {
            if ( result.value[i] >= 10 )
            {
                result.value[i - 1] += ( result.value[i] / 10 );
                result.value[i] %= 10;
            }
        }
        return result;
    }
    //below are cin, cout operators
    friend ostream& operator<<(ostream& out, const largeNumber& ln)
    {
        bool valueFound = false;
        for ( int i = 0 ; i < 500 ; ++ i )
        {
            if ( ln.value[i] != 0 )
            {
                valueFound = true;
            }
            if ( valueFound == true )
            {
                out << ln.value[i];
            }
        }
        if ( valueFound == false )
        {
            out << "0";
        }
        return out;
    }
    friend istream& operator>>(istream& in, largeNumber& ln) // input
    {
        string str;
        in >> str;
        int length = str.length();
        for ( int i = 500 - length ; i < 500 ; ++ i )
        {
            ln.value[i] = (str[length-(500-i)] - 48);
        }
        return in;
    }
};

int main()
{
    largeNumber a, b;
    string op;
    cin >> a >> op >> b;
    cout << a * b;
    return 0;
}

I've included my way to do multiplication, however it is flawed.

By the way, the number given by teacher promised that the result of multiplication will be a number less than 500 digit.

回答1:

Lets start with simple multiplication(Long multiplication):

112 * 301

          1     1     2
          3     0     1
          ______________
          1     1     2
     0    0     0
 3   3    6
 _______________________
 3   3    7     1     2

So, this needs N by N matrix as rows to be added with shifting-n-times.

Where are you doing this addition and where is shifting?

For your question, it would need 500 x 500 multiplications and 500 x 500 additions. O(N*N)

Pro: each digit-multiplication can be done in a single byte so you can change the structure of digits that your compiler can vectorize the code and multiply 16 to 32 digits at once(unrolls quite good).

Con: too many computing(nearly 25-40 iteration per 500 digits-num)

Note: GPU-powered calculus could give it roughly 40x more speed. Such as OpenCL or Cuda.