欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【大数据】大数据字符串的加减乘除

程序员文章站 2022-06-25 18:02:24
...

在日常计算中,一般来说,数据不会太大,即使再大long long 8个字节也够用,但是现在来说数据很大,一般的数据类型都表示不了,那么就用字符串来表示数据。

那么就有字符串数据的加减乘除运算。

基本结构BigData.h

有两种成员变量;
long long _value;
string _strData;

两种构造函数:字符串,int
构造函数已经处理过字符串,正数的字符串是,”+…….”,负数的字符串是”-……….”。

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
using namespace std;

typedef long long INT64;


class BigData
{
public:

    BigData(INT64 data);
    BigData(const string& str);
    BigData operator+(const BigData& b);
    BigData operator-(const BigData& b);
    BigData operator*(const BigData& b);
    BigData operator/(const BigData& b);
    BigData& operator=(const BigData& b);
    friend ostream& operator<<(ostream& out, const BigData& bigdata);

private:
    //判断是否越界
    bool IsINT64Overflow()const;

    //Add  这些函数的参数 肯定都带符号,
    string Add(string left, string right);

    string Sub(string left, string right);

    string Mul(string left, string right);

    string Div(string left, string right);

    //判断被除数大于除数
    bool isLeftBig(char* left, size_t Lsize, char* right, size_t Rsize);//left前面不为0

    //计算商值,并且返回余数
    char loopsub(char*& left, size_t& Lsize, char*& right, size_t Rsize);

private:
    INT64 _value;
    string _strData;
};

构造函数以及输出运算符重载

INT64 UN_INT = 0xcccccccccccccccc;
const INT64 MaxValue = 9223372036854775807;
const INT64 MinValue = -9223372036854775807;

ostream& operator<<(ostream& out, const BigData& bigdata)
{
    char* pData = (char*)bigdata._strData.c_str();
    if (*pData == '+')
        pData++;
    out << pData;
    return out;
}

BigData::BigData(INT64 data = UN_INT)
:_value(data)
{
    //数字放入字符串中
    _strData = "+";
    INT64 temp = _value;
    if (temp < 0)
    {
        _strData[0] = '-';
        temp = 0 - temp;
    }
    else if (temp == 0)
        _strData = "+0";
    while (temp != 0)
    {
        _strData += temp % 10 + '0';
        temp /= 10;
    }
    reverse(_strData.begin() + 1, _strData.end());
}

//模拟atoi
BigData::BigData(const string& strData)
: _value(0)
, _strData("+0")
{
    // "123456789" "+123456890"  "12345asdfg123456"
    // "000001234567"  "      12345678"
    // "aa12345689" "000000000000000000"  "             "
    if (strData.empty())
        return;

    char* pData = (char*)strData.c_str();
    char symbol = *pData;
    if (*pData == '-' || *pData == '+')
        pData++;    


    //处理前置空格
    while (isspace(*pData))
        pData++;
    if ('\0' == *pData)
        return;

    //处理 前置0
    while ('0' == *pData)
        pData++;
    if ('\0' == *pData)
        return;
    //处理前置非数字
    if (*pData > '9' || *pData < '0')
        return;

    //处理剩余部分
    size_t Length = strlen(pData);
    _strData.resize(Length + 1);//多加一个符号位
    if (symbol == '-')
        _strData[0] = '-';
    size_t count = 1;
    while (*pData >= '0' && *pData <= '9')
    {
        _value = _value * 10 + *pData - '0';
        _strData[count++] = *pData++;
    }
    _strData.resize(count);

    if (symbol == '-')
        _value = 0 - _value;
}

//判断是否越界
bool BigData::IsINT64Overflow()const
{
    std::string strTemp("+9223372036854775807");
    if (_strData[0] == '-')
        strTemp = "-9223372036854775808";

    if (_strData.size() < strTemp.size())
        return false;
    else if (_strData.size() == strTemp.size() && _strData < strTemp)
        return false;

    return true;
}

BigData& BigData::operator=(const BigData& b)
{
    if (this != &b)
    {
        BigData temp(b);
        std::swap(_value, temp._value);
        std::swap(_strData, temp._strData);
    }
    return *this;
}

加法
只有当符号位相同时,才进行加法。

字符串相加,比较容易实现,
(1)结果的字符串的位数要最大的那位,要多加一位,防止最后一位进位。
(1) 将字符串 位数大的 放在外面,
(2)设置一个进位累加器,相加。

string Add(string left, string right)
    {
        size_t Lsize = left.size();
        size_t Rsize = right.size();
        string res;
        char symbol = 0;
        //正常调用add的为同号,
        //当为-时候,异号调用Add,位数相同时,符号位为left[0],位数不同时,符号位交换之前的left[0]
        if (Lsize < Rsize) //使left的位数大
        {
            if (left[0] != right[0]) //异号
                symbol = left[0];
            std::swap(Lsize, Rsize);
            std::swap(left, right);
        }   
        res.resize(Lsize + 1); //可能最后产生进位
        if (symbol != 0)
            res[0] = symbol;
        else 
            res[0] = left[0];
        char takeover = 0;//进位
        for (size_t idx = 1; idx < Lsize; ++idx)
        {
            char temp = left[Lsize - idx] - '0' + takeover;
            if (Rsize > idx)
                temp += right[Rsize - idx] - '0';
            takeover = temp / 10;
            res[Lsize + 1 - idx] = temp % 10 + '0';
        }
        res[1] = takeover + '0';
        return res;
    }
    BigData BigData::operator+(const BigData& b)
{
    if (!IsINT64Overflow() && !b.IsINT64Overflow())
    {
        //没有超出范围
        if (_strData[0] != b._strData[0])//异号
            return BigData(_value + b._value);
        else
        {
            //10 - 2 = 8, 7
            //-10 - -2 = -8,-7
            //同号 但是没有超出范围
            if ((_strData[0] == '+' && MaxValue - _value >= b._value) ||
                (_strData[0] == '-' && MinValue - _value <= b._value))
                return BigData(_value + b._value);
        }
    }
    if (_strData[0] == b._strData[0]) //同号
        return BigData(Add(_strData, b._strData));
    return BigData(Sub(_strData, b._strData));
}

减法
(1) 位数大的放在外面,
(2)在减法过程中,注意借位问题。

string Sub(string left, string right)
    {
        size_t Lsize = left.size();
        size_t Rsize = right.size();        
        char symbol  = 0;
        if (Lsize < Rsize || (Lsize == Rsize && strcmp(left.c_str() + 1, right.c_str() + 1) < 0))
        {
            std::swap(Lsize, Rsize);
            std::swap(left, right);
            if (left[0] == right[0] && left[0] == '+')//小的减去大的,且同号的话,比如left = 5,right = 10,
                symbol = '-';

            if (left[0] == right[0] && left[0] == '-')//比如left = -5,right = -10,
                symbol = '+';
        }
        string res;
        res.resize(Lsize);// 减去不可能产生进位
        if (symbol != 0)
            res[0] = symbol;
        else
            res[0] = left[0];

        for (size_t idx = 1; idx < Lsize; ++idx)
        {
            char temp = left[Lsize - idx] - '0';
            if (Rsize > idx)
                temp -= right[Rsize - idx] - '0';
            if (temp < 0)
            {
                int step = 1;//向前step位借位
                while ((Lsize >(idx + step)) && left[Lsize - idx - step] == 0)
                {
                    left[Lsize - idx - step] = '9';
                    step++;
                }
                left[Lsize - idx - step]--; //不为0时 要-1
                temp += 10;
            }
            res[Lsize - idx] = temp % 10 + '0';
        }
        return res;
    }
BigData BigData::operator-(const BigData& b)
{
    if (!IsINT64Overflow() && !b.IsINT64Overflow())
    {
        //没有超出范围
        if (_strData[0] == b._strData[0])//同号号
            return BigData(_value - b._value);
        else
        {
            // [10,-10]  2和 -7
            // -10 +2 = -8
            // 10 + -7 = 3
            //异号 但是没有超出范围
            if ((_strData[0] == '+' && MinValue + _value <= b._value) ||
                (_strData[0] == '-' && MaxValue + _value >= b._value))
                return BigData(_value - b._value);
        }
    }
    if (_strData[0] == b._strData[0]) //同号
        return BigData(Sub(_strData, b._strData));
    return BigData(Add(_strData, b._strData));
}

乘法
(1) 同样大的放在外层left
(2)内层的每个位于外层left相乘,然后与res中相加,

string Mul(string left, string right)
    {
        size_t LSize = left.size();
        size_t RSize = right.size();
        if (LSize > RSize) //位数小的放到外层循环
        {
            std::swap(LSize, RSize);
            std::swap(left, right);
        }
        char takeover = 0; //进位

        size_t resSize = LSize + RSize - 1;
        string res(resSize, '0');//全都初始化'0';
        size_t offset = 0;//结果移位
        for (size_t i = 1; i < LSize; ++i)
        {
            char cleft = left[LSize - i] - '0';// 外层循各个位的值
            takeover = 0;
            for (size_t j = 1; j < RSize; ++j)
            {
                char resBit = res[resSize - offset - j] - '0';
                char mulBit = (right[RSize - j] - '0') * cleft + takeover + resBit;
                takeover = mulBit / 10;
                res[resSize - offset - j] = mulBit % 10 + '0';
            }
            offset++;
        }
        //最后一次进位没有写入到结果中
        res[1] = takeover + '0';
        //符号
        if (left[0] == right[0])
            res[0] = '+';
        else
            res[0] = '-';
        return res;
    }
BigData BigData::operator*(const BigData& b)
{
    if (_value == 0 || b._value == 0)
        return BigData(0);
    else if (strcmp(_strData.c_str() + 1, "1") == 0)
        return BigData(b._strData);
    else if (strcmp(b._strData.c_str() + 1, "1") == 0)
        return BigData(_strData);
    return BigData(Mul(_strData, b._strData));
}

除法
借助两个函数,
isLeftBig:判断左边的数据是否大于右边的数据
loopsub:循环减去右边的值,计算差值。直到需要借位。

    //判断被除数大于除数
    bool isLeftBig(char* left, size_t Lsize, char* right, size_t Rsize)//left前面不为0
    {
        if (Lsize == Rsize && strncmp(left, right, Rsize) >= 0)
            return true;
        else if (Lsize > Rsize)
            return true;

        return false;
    } 
    //计算商值,并且返回余数
    char loopsub(char*& left, size_t& Lsize, char*& right, size_t Rsize)
    {
        char count = '0';//相当于商值    
        while (isLeftBig(left, Lsize, right, Rsize))
        {
            for (size_t i = 0; i < Lsize; ++i)
            {
                char temp = left[Lsize - 1 - i] - '0';
                if (i < Rsize)
                    temp -= (right[Rsize - 1 - i] - '0');
                if (temp < 0)
                {
                    //向前借位
                    size_t step = 1;//借的步数
                    while ((1 + i + step < Lsize) && left[Lsize - 1 - i - step] == 0) //肯定可以借到,因为左边大于右边
                    {
                        left[Lsize - 1 - i - step] = '9';
                        step++;
                    }
                    left[Lsize - 1 - i - step]--;
                    temp += 10;
                }
                left[Lsize - 1 - i] = temp + '0';
            }
            count++;
            while (Lsize > 0 && *left == '0') //去除前面的0
            {
                left++;
                Lsize--;
            }
            if (Lsize == 0)
                break;
        }
        return count;

    }
        string Div(string left, string right)
    {
        char symbol = '+';
        if (left[0] != right[0])
            symbol = '-';
        string res;
        res.append(1, symbol);
        char* pleft = (char*)left.c_str() + 1;
        char* pright = (char*)right.c_str() + 1;
        size_t Lsize = left.size() - 1;
        size_t Rsize = right.size() - 1;
        size_t len = Rsize;

        while (*(pleft + len - 1) != '\0') //感觉这可能越界
        {
            if (!isLeftBig(pleft, len, pright, Rsize))
            {           
                if (*pleft == '0')
                    pleft++;
                else 
                    len++;
                res.append(1, '0');
                continue;
            }
            else
            {
                res.append(1, loopsub(pleft, len, pright, Rsize));
                len++;
            }
        }
        return res;
    }
    BigData BigData::operator/(const BigData& b)
{
    //商值为0,1,-1
    char* left = (char *)_strData.c_str();
    char* right = (char *)b._strData.c_str();
    //除数不能为0
    if (b._value == 0)
    {
        cout << "除数不能为0" << endl;
        return BigData(0);
    }
    //商值为0
    if (_strData.size() < b._strData.size())
        return BigData(0);
    else if (_strData.size() == b._strData.size() && strcmp(_strData.c_str() + 1, b._strData.c_str() + 1) < 0)
        return BigData(0);
    //商值为 1 
    if (strcmp(left, right) == 0)
        return BigData(1);
    //商值为-1
    if (strcmp(_strData.c_str() + 1, b._strData.c_str() + 1) == 0 && *left != *right)
        return BigData(-1);
    else if (b._value == 1) //被除数为1
        return BigData(_strData);
    else if (b._value == -1) //被除数为-1
        return BigData(b._strData);

    return BigData(Div(_strData, b._strData));
}
相关标签: 大数据加减乘除

上一篇: 基于UDP协议的Socket编程

下一篇: JVM