Detailed analysis of big integer type BigInteger written in C + +

Keywords: less Java

subject

Detailed analysis of big integer type BigInteger written in C + +

Narration

Large integer class generally appears in the problem of accuracy in algorithm problems. Although there are large integer classes available in Java, and they are easy to use, we can also understand the implementation of large integer class. Then the next code and the implementation of the second version of the algorithm introduction competition are not much worse, but I have made a certain analysis of the whole algorithm

Code

struct BigInteger
{
    static const int BASE = 100000000;
    static const int WIDTH = 8;
    vector<int> s;

    // Constructor
    BigInteger(long long num = 0) 
    {
        // Call overload symbol for =
        *this = num;
    }

    // Overload = symbol
    // When the input is in the long long range
    BigInteger operator = (long long num)
    {
        s.clear();
        do {
            // Every 8 bits are stored, less than 8 bits are counted as one
            // Low to high storage
            // For example, 123456789
            // 23456789 1 in the order of stack out
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    // long long range exceeded
    BigInteger operator = (const string& str)
    {
        s.clear();
        // len = how many octets are there in the whole str, and the last octet is not included in the last set
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (int i = 0; i < len; ++i)
        {
            // Store from the last eight bits of the string
            // Low to high storage
            // For example, 123456789123456789
            // 23456789 34567891
            int end = str.length() - i * WIDTH;
            int start = max(0, end - WIDTH);
            // str gets eight bits, then converts to a c-type string, then uses sscanf to convert to the integer x, and finally stores it in s
            sscanf(str.substr(start, end - start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return *this;
    }
    // Overload output < symbol
    friend ostream& operator << (ostream& out, const BigInteger& x)
    {
        // First go out the first high position, so as not to use the 0 supplement if the middle position is less than eight
        // For example, 123
        // If it is put into the loop, the output is 00000123
        out << x.s.back();
        // Why is s.size()-2? Since the subscript starts from 0 and the last number is output in front, the remaining position is size()-2
        for (int i = x.s.size() - 2; i >= 0; i--)
        {
            // Character array for conversion
            char buf[20];
            // Convert the number in s[i] to an array of eight characters. If the number is less than eight, use 0 completion
            sprintf(buf, "%08d", x.s[i]);
            // Add each character in buf to the output stream
            for (int j = 0; j < strlen(buf); ++j) out << buf[j];
        }
        return out;
    }
    // Overload input < symbol
    friend istream& operator >> (istream& in, BigInteger& x)
    {
        string s;
        // If the input is empty, return in
        if (!(in >> s)) return in;
        // If it is not empty, it will be assigned to s and copied to x
        // The = symbol calling BigInteger
        x = s;
        return in;
    }
    // Four arithmetic symbols overload
    // Addition +
    BigInteger operator + (const BigInteger& b) const
    {
        // Addition involves out of carry
        BigInteger c;
        c.s.clear();
        for (int i = 0, g = 0; ; ++i)
        {
            // The condition for a loop to jump out is g == 0, when there is no number to store or add, that is, after the longest vector is traversed
            // I > = s.size() is after the current BigInteger traversal
            // I > = b.s.size() is after traversal of B
            // Only when all three conditions are satisfied can we say that they are all added completely
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            // x stores the number of last cycles over eight bits
            int x = g;
            // If i i s less than the number of elements in s or less than the number of elements in b.s, the value will be added to x for storage
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            // Process the number of current "bits". The remainder is to get the first 8 digits and put them into the new BigIntger
            c.s.push_back(x % BASE);
            // g is more than eight figures this time
            g = x / BASE;
        }
        return c;
    }
    // Subtraction - 
    BigInteger operator - (const BigInteger& b)
    {
        BigInteger c;
        c.s.clear();
        if (*this > b)
        {
            int i, g;
            for (i = 0, g = 0; ; ++i)
            {
                // The explanation of the same addition here
                if (g == 0 && i >= b.s.size()) break;
                int x = g;
                // If it's less than the latter, borrow 1 from the high position
                // Then the former is added to the basic BASE
                if (s[i] < b.s[i])
                {
                    s[i + 1] -= 1;
                    s[i] = s[i] + BASE;
                }
                if (i < s.size()) x += s[i];
                if (i < b.s.size()) x -= b.s[i];
                c.s.push_back(x%BASE);
                g = x / BASE;
            }

            // This place continues to copy s's to c
            for (int x = 0; i < s.size(); ++i)
            {
                x += s[i];
                c.s.push_back(x%BASE);
                x /= BASE;
            }
        }
        return c;
    }

    // Overload of comparison operators
    // After only one is less than the overload, we can deduce all the symbols according to the logical reasoning
    // Less than <
    bool operator < (const BigInteger& b) const
    {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        for (int i = s.size() - 1; i >= 0; --i)
        {
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        }
        return false;
    }
    // Greater than >
    bool operator > (const BigInteger& b) const
    {
        return b < *this;
    }
    // Less than or equal to<= 
    bool operator <= (const BigInteger& b) const
    {
        return !(b < *this);
    }
    // Greater than or equal to >=
    bool operator >= (const BigInteger& b) const
    {
        return !(*this < b);
    }
    // Not equal to!
    bool operator != (const BigInteger& b) const
    {
        return b < *this || *this < b;
    }
    // Equal to = =
    bool operator == (const BigInteger& b) const
    {
        return !(b < *this || *this < b);
    }
};

summary

Most of them are summarized, but multiplication, division and other power algorithms are not added. If there is a chance to implement them later, we will continue to analyze them. On annotation, almost every statement is explained

Reference material

The second edition of Liu Rujia's algorithm competition
Several implementation methods and analysis of c + + large integer class

Posted by jotgabbi on Mon, 30 Mar 2020 08:21:19 -0700