大数运算

计算机中的各种类型的数据都是有其表示上限的当进行很大的数据运算时可能产生溢出,这时就要用的大数运算
大数运算是将数据保存在数组或者string,vector的容器中进行运算这样就可以进行几十位甚至上百位的运算

#pragma once

#include 
#include 
#include 
#include 

enum FLAGS
{
    INT,
    DOUBLE
};


class BigNumber
{
public:
    BigNumber(const std::string& _num = "", FLAGS _flags = INT,bool _IsPositive = true);
    BigNumber(const BigNumber& big);

    ~BigNumber();

    BigNumber& operator=(const BigNumber& big);
    BigNumber operator+(BigNumber& big);
    BigNumber operator-(BigNumber& big);
    BigNumber operator*(BigNumber& big);
    BigNumber operator/(BigNumber& big);
    BigNumber operator%(BigNumber& big);
    BigNumber& operator+=(BigNumber& big);
    BigNumber& operator-=(BigNumber& big);
    BigNumber& operator*=(BigNumber& big);
    BigNumber& operator/=(BigNumber& big);
    BigNumber& operator%=(BigNumber& big);
    bool operator>(const BigNumber& big);
    bool operator<(const BigNumber& big);
    bool operator>=(const BigNumber& big);
    bool operator<=(const BigNumber& big);
    bool operator==(const BigNumber& big);
    bool operator!=(const BigNumber& big);
    BigNumber operator++(int);
    BigNumber& operator++();
    BigNumber operator--(int);
    BigNumber& operator--();
    void Print();

    friend std::ostream& operator<<(std::ostream& cout, const BigNumber& big);
private:
    BigNumber(const std::string _num, FLAGS _flags, int s, bool _IsPositive = true);
    int Addstr(size_t i, size_t j, std::string& str, std::string& str1, std::string& str2);
    void Substr(size_t i, size_t j, std::string& str, std::string str1, std::string str2,bool IsInt = true);
    void Mulstr(std::string& str, std::string& str1, std::string& str2);

public:
    bool IsPositive;
private:
    FLAGS flags;
    std::string num;
};
#include "bignumber.h"
#include 

BigNumber::BigNumber(const std::string& _num, FLAGS _flags, bool _IsPositive)
    : flags(_flags)
    , IsPositive(_IsPositive)
{
    int i = _num.length() - 1;
    for (i; i >= 0; i--)
    {
        num += _num[i];
    }
    int idx = num.find_first_of('.');
    if (idx > 0)
    {
        flags = DOUBLE;
    }
}
BigNumber::BigNumber(const std::string _num, FLAGS _flags, int s, bool _IsPositive)
    : flags(_flags)
    , num(_num)
    , IsPositive(_IsPositive)
{}

BigNumber::BigNumber(const BigNumber& big)
{
    flags = big.flags;
    num = big.num;
    IsPositive = big.IsPositive;
}

BigNumber::~BigNumber()
{}

BigNumber& BigNumber::operator=(const BigNumber& big)
{
    if (this == &big)
        return *this;

    flags = big.flags;
    num = big.num;
    IsPositive = big.IsPositive;
    return *this;
}

static bool CompareNum(const std::string& str1, const std::string& str2)
{
    std::string strint1;
    std::string strint2;
    std::string strfloat1;
    std::string strfloat2;
    int cutbit1 = str1.find_first_of('.');
    int cutbit2 = str2.find_first_of('.');
    if (cutbit1 > 0)
    {
        strint1 = str1.substr(cutbit1, str1.length() - 2);
        strfloat1 = str1.substr(cutbit1);
    }
    else
        strint1 = str1;
    if (cutbit2 > 0)
    {
        strint2 = str2.substr(cutbit2, str2.length() - 2);
        strfloat2 = str2.substr(cutbit2);
    }
    else
        strint2 = str2;
    int str1L = strint1.length() - 1;
    int str2L = strint2.length() - 1;
    while (str1L >= 0)                    //去除高位的0
    {
        if (strint1[str1L] == '0')
            str1L--;
        else
            break;

    }
    while (str2L >= 0)
    {
        if (strint2[str2L] == '0')
            str2L--;
        else
            break;
    }
    if (str1L > str2L)
    {
        return true;
    }
    else if (str1L < str2L)
    {
        return false;
    }

    if (strint1 == strint2)
    {
        if (strfloat2.empty() && !strfloat1.empty())
            return true;
        if (!strfloat2.empty() && strfloat1.empty())
            return false;
        int i = strfloat1.length() - 1;
        int j = strfloat2.length() - 1;
        while (i >= 0 && j >= 0)
        {
            if (strfloat1[i] != strfloat2[j])
            {
                if (strfloat1[i] > strfloat2[j])
                    return true;
                else
                    return false;
            }
            i--;
            j--;
        }
        if (i >= 0)
            return true;
        return false;
    }

    int i = strint1.length() - 1;
    while (i >= 0)
    {
        if (strint1[i] > strint2[i])
            return true;
        if (strint1[i]return false;
        i--;
    }
}

bool BigNumber::operator>(const BigNumber& big)
{
    if (IsPositive && !big.IsPositive)
        return true;
    if (!IsPositive && big.IsPositive) 
        return false;
    if (num == big.num)
    {
        if (IsPositive == big.IsPositive)
            return true;
        if (IsPositive)
            return true;
        return false;
    }
    if (IsPositive)
    {
        return CompareNum(num, big.num);
    }
    return !CompareNum(num, big.num);
}

bool BigNumber::operator<(const BigNumber& big)
{
    return !(*this >= big);
}

bool BigNumber::operator==(const BigNumber& big)
{
    if (IsPositive == big.IsPositive && num == big.num)
        return true;
    return false;
}

bool BigNumber::operator!=(const BigNumber& big)
{
    return !(*this == big);
}

BigNumber BigNumber::operator++(int)
{
    BigNumber tmp(*this);
    BigNumber tmp1("1", INT, true);
    *this += tmp1;
    return tmp;
}

BigNumber& BigNumber::operator++()
{
    BigNumber tmp1("1", INT, true);
    *this += tmp1;
    return *this;
}

BigNumber BigNumber::operator--(int)
{
    BigNumber tmp(*this);
    BigNumber tmp1("1", INT, true);
    *this -= tmp1;
    return tmp;
}

BigNumber& BigNumber::operator--()
{
    BigNumber tmp1("1", INT, true);
    *this -= tmp1;
    return *this;
}

bool BigNumber::operator>=(const BigNumber& big)
{
    return (*this > big || *this == big);
}

bool BigNumber::operator<=(const BigNumber& big)
{
    return (*this < big || *this == big);
}

int BigNumber::Addstr(size_t i, size_t j, std::string& str,std::string& str1,std::string& str2)
{
    int cy = 0;
    for (i, j; i < str1.length() && j < str2.length(); i++, j++)
    {
        int num1 = str1[i] - '0';
        int num2 = str2[j] - '0';
        int num3 = num1 + num2 + cy;
        cy = num3 / 10;
        str += (num3 % 10 + '0');
    }
    if (i < str1.length())
    {
        for (; i < str1.length(); i++)
        {
            int num1 = str1[i] - '0';
            int num2 = num1 + cy;
            cy = num2 / 10;
            str += (num2 % 10 + '0');
        }
    }
    if (j < str2.length())
    {
        for (; j < str2.length(); j++)
        {
            int num1 = str2[j] - '0';
            int num2 = num1 + cy;
            cy = num2 / 10;
            str += (num2 % 10 + '0');
        }
    }
    return cy;
}

void BigNumber::Mulstr(std::string& str, std::string& str1, std::string& str2)
{
    int cy = 0;
    size_t count = 1;
    for (size_t i =0; i < str1.length(); i++)
    {
        if (str1[i] == '.')
            continue;
        int num1 = str1[i] - '0';
        cy = 0;
        std::string tmp1,tmp2;
        for (size_t j = 0; j < str2.length(); j++)
        {
            if (str2[j] == '.')
                continue;
            int num2 = str2[j] - '0';
            int num3 = num1*num2 + cy;
            cy = num3 / 10;
            tmp1 += (num3 % 10 + '0');
        }
        if (cy != 0)
            tmp1 += (cy + '0');
        if (str.length() == 0)
            str = tmp1;
        else
        {
            std::string tmp;
            for (size_t k = 0; k < count; k++)
                tmp += '0';
            count++;
            tmp += tmp1;
            cy = Addstr(0, 0, tmp2, str, tmp);
            if (cy != 0)
                tmp2 += (cy + '0');
            str = tmp2;
        }
    }
}

void BigNumber::Substr(size_t i, size_t j, std::string& str, std::string str1, std::string str2, bool IsInt)
{
    int cy = 0;
    if (!IsInt)
    {
        int str1L = str1.length();
        int str2L = str2.length();
        if (str1L < str2L)
        {
            std::string tmp;
            for (size_t k = 0; k < str2L - str1L; k++)
                tmp += '0';
            tmp += str1;
            str1 = tmp;
        }
        if (str1L > str2L)
        {
            std::string tmp; 
            for (size_t k = 0; k < str1L - str2L; k++)
                tmp += '0';
            tmp += str2;
            str2 = tmp;
        }
    }
    for (i, j; i < str1.length() && j < str2.length(); i++, j++)
    {
        int num1 = str1[i] - '0';
        int num2 = str2[j] - '0';
        if (cy && num1 > 0)
        {
            cy = 0;
            num1--;
        }
        if (cy && num1 == 0)
            num1 = 9;
        if (num1 < num2)
        {
            cy = 1;
            num1 += 10;
        }
        int num3 = num1 - num2;
        str += (num3 + '0');
    }

    for (i; i < str1.length(); i++)
    {
        int num1 = str1[i] - '0';
        if (cy && num1 > 0)
        {
            cy = 0;
            num1--;
        }
        if (cy && num1 == 0)
            num1 = 9;
        str += (num1 + '0');
    }
    for (j; j < str2.length(); j++)
    {
        int num1 = str2[j] - '0';
        if (cy && num1 > 0)
        {
            cy = 0;
            num1--;
        }
        if (cy && num1 == 0)
            num1 = 9;
        str += (num1 + '0');
    }
}

BigNumber& BigNumber::operator+=(BigNumber& big)
{
    *this = *this + big;
    return *this;
}

BigNumber& BigNumber::operator-=(BigNumber& big)
{
    *this = *this - big;
    return *this;
}

BigNumber& BigNumber::operator*=(BigNumber& big)
{
    *this = *this*big;
    return *this;
}

BigNumber& BigNumber::operator/=(BigNumber& big)
{
    *this = *this / big;
    return *this;
}

BigNumber& BigNumber::operator%=(BigNumber& big)
{
    *this = *this%big;
    return *this;
}

BigNumber BigNumber::operator+(BigNumber& big)
{
    int start1 = 0;
    int start2 = 0;

    if (!IsPositive && big.IsPositive)
    {
        BigNumber tmp(*this);
        tmp.IsPositive = true;
        return big - tmp;
    }

    if (IsPositive&&!big.IsPositive)
    {
        BigNumber tmp(big);
        tmp.IsPositive = true;
        return *this - tmp;
    }
    if (!IsPositive && !big.IsPositive)
    {
        BigNumber tmp1(*this);
        BigNumber tmp2(big);
        tmp1.IsPositive = true;
        tmp2.IsPositive = true;
        tmp1 = tmp1 + tmp2;
        tmp1.IsPositive = false;
        return tmp1;
    }
    if (INT == flags && INT ==big.flags)
    {
        std::string str;
        int cy = Addstr(start1, start2, str, num, big.num);
        if (cy != 0)
            str += (cy + '0');
        return BigNumber(str, INT, 0);
    }
    if ((INT == flags && DOUBLE == big.flags) || (DOUBLE == flags && INT == big.flags))
    {
        std::string str;
        std::string strint;
        std::string strfloat;
        start1 = num.find_first_of('.');
        if (start1 < 0)
            start1 = 0;
        else
            start1++;

        start2 = big.num.find_first_of('.');
        if (start2 < 0)
            start2 = 0;
        else
            start2++;

        int cy = Addstr(start1, start2, strint, num, big.num);
        if (cy != 0)
            strint += (cy + '0');
        if (DOUBLE == flags)
            strfloat = num.substr(0,num.find_first_of('.'));
        if (DOUBLE == big.flags)
            strfloat = big.num.substr(0, big.num.find_first_of('.'));

        strfloat += '.';
        str = strfloat + strint;
        return BigNumber(str, DOUBLE, 0);
    }
    if (DOUBLE == flags && DOUBLE == big.flags)
    {
        start1 = num.find_first_of('.');
        start2 = big.num.find_first_of('.');
        std::string str;
        int cy = Addstr(start1 + 1, start2 + 1, str, num, big.num);
        if (cy != 0)
            str += (cy + '0');
        cy = 0;
        std::string str1 = num.substr(0, start1);
        std::string str2 = big.num.substr(0, start2);
        std::string str3;
        int str1L = str1.length();
        int str2L = str2.length();
        if (str1L > str2L)
        {
            int i = 0;
            for (; i < str1L - str2L; i++)
                str3 += str1[i];
            cy = Addstr(i, 0, str3, str1, str2);
        }
        else if (str2L == str1L)
        {
            cy = Addstr(0, 0, str3, str1, str2);
        }
        else
        {
            int i = 0;
            for (; i < str2L - str1L; i++)
                str3 += str2[i];
            cy = Addstr(0, i, str3, str1, str2);
        }
        if (cy != 0)
        {
            std::string str4;
            str4 += (cy + '0');
            std::string tmp;
            cy = Addstr(0, 0, tmp, str, str4);
            if (cy != 0)
                tmp += (cy + '0');
            str = tmp;
        }
        str3 += '.';
        str3 += str;
        return BigNumber(str3, DOUBLE, 0);
    }

    return BigNumber();
}

BigNumber BigNumber::operator-(BigNumber& big)
{
    if (*this == big)
    {
        std::string str;
        return BigNumber(str,INT,0,true);
    }
    if (!big.IsPositive)
    {
        BigNumber tmp(big);
        tmp.IsPositive = true;
        return *this + tmp;
    }
    std::string str;
    if (INT == flags && INT == big.flags)
    {
        if (*this > big)
        {
            Substr(0, 0, str, num, big.num);
            return BigNumber(str, INT, 0, true);
        }
        else
        {
            Substr(0, 0, str, big.num, num);
            return BigNumber(str, INT, 0, false);
        }
    } 

    if (INT == flags && DOUBLE == big.flags)
    {
        std::string strint = big.num.substr(big.num.find_first_of('.')+1, big.num.length());
        std::string strfloat = big.num.substr(0,big.num.find_first_of('.'));
        if (strint == num)
        {
            strfloat += ".0";
            return BigNumber(strfloat, DOUBLE, 0, false);
        }
        if (CompareNum(num, strint))
        {
            Substr(0, 0, str, num, strint);
            strfloat += '.';
            strfloat += str;
            return BigNumber(strfloat, DOUBLE, 0, true);
        }
        else
        {
            Substr(0, 0, str, strint, num);
            strfloat += ".";
            strfloat += str;
            return BigNumber(strfloat, DOUBLE, 0, false);
        }
    }
    if (DOUBLE == flags && INT == big.flags)
    {
        std::string strint = num.substr(num.find_first_of('.')+1, num.length());
        std::string strfloat = num.substr(0,num.find_first_of('.'));
        if (strint == big.num)
        {
            strfloat += ".0";
            return BigNumber(strfloat, DOUBLE, 0, true);
        }
        if (CompareNum(strint, big.num))
        {
            Substr(0, 0, str, strint, big.num);
            strfloat += '.';
            strfloat += str;
            return BigNumber(strfloat, DOUBLE, 0, true);
        }
        else
        {
            Substr(0, 0, str, big.num, strint);
            strfloat += '.';
            strfloat += str;
            return BigNumber(strfloat, DOUBLE, 0, false);
        }
    }
    int cutbit1 = num.find_first_of('.');
    int cutbit2 = big.num.find_first_of('.');
    std::string strint1 = num.substr(cutbit1 + 1, num.length());
    std::string strint2 = big.num.substr(cutbit2 + 1, big.num.length());
    std::string strfloat1 = num.substr(0, cutbit1);
    std::string strfloat2 = big.num.substr(0, cutbit2);
    if (*this < big)
    {
        BigNumber tmp = big - *this;
        tmp.IsPositive = false;
        return tmp;
    }
    if (strint1 == strint2)
    {
        Substr(0, 0, str, strfloat1, strfloat2);
        str += ".0";
        return BigNumber(str, DOUBLE, 0, true);
    }

    int i = strfloat1.length() - 1;
    int j = strfloat2.length() - 1;
    while (i >= 0 && j >= 0)
    {
        if (strfloat1[i] != strfloat2[j])
            break;
    }
    if (strfloat1[i] > strfloat2[j])
    {
        Substr(0, 0, str, strfloat1, strfloat2, false);
        str += '.';
    }
    else
    {
        std::string tmp;
        Substr(0, 0, tmp, str, "1");
        str = tmp;
        strfloat1 += '1';
        Substr(0, 0, str, strfloat1, strfloat2, false);
        str += '.';
    }

    Substr(0, 0, str, strint1, strint2);
    return BigNumber(str, DOUBLE, 0, true);
}

BigNumber BigNumber::operator*(BigNumber& big)
{
    int start1 = 0;
    int start2 = 0;
    std::string str;
    Mulstr(str, num, big.num);
    if (INT == flags && INT == big.flags)
    {
        if(IsPositive==big.IsPositive)
            return BigNumber(str, INT, 0);
        else
            return BigNumber(str, INT, 0,false);
    }
    if (DOUBLE == flags)
        start1 = num.find_first_of('.');
    if (DOUBLE == big.flags)
        start2 = big.num.find_first_of('.');
    std::string strfloat = str.substr(0, start1 + start2);
    std::string strint = str.substr(start2 + start1);
    strfloat += '.';
    str = strfloat + strint;
    if (IsPositive == big.IsPositive)
        return BigNumber(str, DOUBLE, 0);
    else
        return BigNumber(str,DOUBLE,0,false);
}

BigNumber BigNumber::operator/(BigNumber& big)
{
    if (big.num.empty())
    {
        std::cout << "被除数为0错误" << std::endl;
        //exit(1);
    }
    if (num.empty() || *this < big)
    {
        return BigNumber();
    }
    if (big.num.length() == 1 && big.num[0] == '1')
    {
        return *this;
    }
    if (*this == big)
    {
        return BigNumber("1", flags, 0, true);
    }
    BigNumber number1;
    BigNumber number2(*this);
    do 
    {
        ++number1;
        number2 = number2 - big;
    } while (number2 > big);
    return number1;
}

BigNumber BigNumber::operator%(BigNumber& big)
{
    if (DOUBLE == big.flags)
    {
        std::cout << "不能模小数" << std::endl;
        //exit(1);
    }
    if (big.num.empty())
    {
        std::cout << "不能模0" <<std::endl;
        //exit(1);
    }
    if (num.empty() || *this == big)
    {
        return BigNumber();
    }
    if (*this < big)
    {
        return *this;
    }
    BigNumber number1;
    BigNumber number2(*this);
    do
    {
        ++number1;
        number2 = number2 - big;
    } while (number2 > big);
    return number2;
}


std::ostream& operator<<(std::ostream& cout, const BigNumber& big)
{
    if (big.num.empty())
    {
        cout << 0;
        return cout;
    }

    int i = big.num.length() - 1;
    while (big.num[i] == '0')
        i--;
    if (!big.IsPositive)
        cout << '-';
    for (; i >= 0; --i)
    {
        cout << big.num[i];
    }
    return cout;
}

你可能感兴趣的:(C++,数据结构)