大数之四则运算

目录

1. 大数之四则运算总结

1.1 加法

1.2 减法

1.3 乘法

1.4 除法

2. 加法

3. 减法

4. 乘法

5. 除法

6. 参考文献


1. 大数之四则运算总结

1.1 加法

从后往前算(即由低位向高位运算),计算的结果依次添加到结果中去,最后将结果字符串反转。

1.2 减法

原理同加法,将进位改为借位

1.3 乘法

第一个数据的第i位与第二个数据的第j位相乘存放在结果的第[i+j]个元素中,因为结果的每一位不是顺序得出,所以不方便用字符串存储,转而用数组存储。另一方面,第一步不考虑进位的问题,先将相乘的结果保存在数组中,然后对数组中的元素需要进位的按进位规则处理。

1.4 除法

利用了前面的大数相减的部分,主要思路为:以999除以9为例,两数相差两位,想让9*100=900,999可以减去9个100,然后9*10=90,余下的99可以减10个90,然后余下的9可以减去1个9,那么从前往后依次拼接每阶段得到的结果,最终得到111。

2. 加法

#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>

using namespace std;

string add(string& data1, string &data2){
    int len1 = data1.length();
    int len2 = data2.length();
    int len = min(len1,len2);
    string res = "";
    int carry = 0;  //进位
    int cur = 0;   //当前位
    string tmp;

    size_t i = 0;
    for (; i < len; i++)
    {
        cur = data1[len1-i-1] + data2[len2-i-1] - 2*'0' + carry;  //计算当前位 从后往前算

        carry = cur/10;  //计算进位

        cur = cur%10;   //计算当前位
        
        stringstream ss;
        ss<<cur;

        tmp = ss.str();

        res += tmp;   //添加到结果中

        // cout<<res<<endl;
    }

    if (len1 < len2)
    {
        data1 = data2;  //直接把较长的数给data1
    }

    for (; i < data1.length(); i++)
    {
        cur = data1[data1.length() - i - 1] - '0' + carry;  //将较长的数的剩下部分添加到结果中

        carry = cur/10;

        cur = cur % 10;

        stringstream ss;
        ss<<cur;

        tmp = ss.str();

        res += tmp;
    }

    if (carry > 0)
    {
        res += carry;
    }

    // cout<<"res:"<<res<<endl;

    reverse(res.begin(), res.end());  //将结果反转

    // cout<<"res:"<<res<<endl;

    return res;

}

int main()
{
    string data1 = "123456";
    string data2 = "1234567";

    string res = add(data1,data2);

    cout<<"res:"<<res<<endl;

    return 0;
}

3. 减法

基本思路和加法类似,进位变为借位,在运算之前需要判断正负,将大的数放在被减数上,因此,在需要的时候将被减数和减数调换一下位置。

#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>

using namespace std;

string sub(string &data1, string &data2)
{
    int len1 = data1.length();
    int len2 = data2.length();
    bool isNeg = false; //判断是否为负
    int cur = 0;  // 当前位
    int carry = 0; //借位
    string res = "";

    if (len1 < len2)  //很重要,在做运算前,将大的数作为被减数,这样可以避免很多问题
    {
        isNeg = true;
        string tmp = data1;  //被减数小于减数,则调换位置,数据和长度都要调换
        data1 = data2;
        data2 = tmp;
        len1 = data1.length();
        len2 = data2.length();
    }else if (len1 == len2)   //当两个字符串的长度相等时,怎么判断哪个字符串比较大,这个逻辑比较有意思
    {
        for (size_t i = 0; i < len1; i++)
        {
            if (data1[i] < data2[i])
            {
                isNeg = true;
                string tmp = data1;
                data1 = data2;
                data2 = tmp;
                break;
            }else if (data1[i] > data2[i])
            {
                isNeg = false;
            }
            
            
        }
        
    }

    int len = min(len1, len2);

    size_t i = 0;

    for (; i < len; i++)
    {
        cur = data1[len1 - i - 1] - data2[len2 - i - 1] - carry;  //字符相减与整数相减一样,不用减'0'

        if (cur < 0)
        {
            cur = cur + 10;
            carry = 1;
        }else
        {
            carry = 0;
        }

        stringstream ss;

        ss<<cur;
        string tmp = ss.str();
        
        res += tmp;

        
    }

    for (; i < len1; i++) //将最长的字符串的剩余部分添加到结果当中
    {
        cur = data1[len1 - i - 1] - '0' - carry; //减去借位, 这里必须减‘0’,容易忽略

        if (cur < 0)
        {
            cur = cur + 10;
            carry = 1;
        }else
        {
            carry = 0;
        }

        stringstream ss;

        ss<<cur;
        string tmp = ss.str();
        
        res += tmp;
    }

    int index = len1 - 1;

    while (res[index] == '0')  //从后面开始的“0”全部去掉,找到不为0的第一个下标
    {
        index --;
    }

    res = res.substr(0,index+1); 

    if (res.length() == 0)  //特殊情况,为零则返回“0”,避免-0的情况出现
    {
        return "0";
    }
    

    if (isNeg) //负数则加负号
    {
        res += "-";
    }

    reverse(res.begin(), res.end());  //与加法一样,反转

    return res;
    
    
}

int main()
{
    string data1 = "1234567";
    string data2 = "1234567";

    string res = sub(data1,data2);

    cout<<"res:"<<res<<endl;

    return 0;
}

4. 乘法

第一个数据的第i位与第二个数据的第j位相乘存放在结果的第[i+j]个元素中,因为结果的每一位不是顺序得出,所以不方便用字符串存储,转而用数组存储。另一方面,第一步不考虑进位的问题,先将相乘的结果保存在数组中,然后对数组中的元素需要进位的按进位规则处理。

#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>

using namespace std;

string multi(string &data1, string &data2)
{
    int len1 = data1.length();
    int len2 = data2.length();
    int cur = 0;  // 当前位
    int carry = 0; //借位
    string result = "";
    
    int res[5000] = {0};  //借用数组暂时存储,因为第一步不考虑进位,所以每一次相乘的结果可能大于0

    for (size_t i = 0; i < len1; i++)
    {
        for (size_t j = 0; j < len2; j++)
        {
            res[i+j] += (data1[len1 - i - 1] - '0') * (data2[len2 - j - 1] - '0'); //第一个数据的第i个元素和第二个数据的第j和元素相乘存到结果的第【i+j】个元素中
                                                                                   //暂时不考虑进位
        }
        
    }

    for (size_t i = 0; i < len1+len2+1; i++)  //依次往后进位,len1长度和len2长度的数据相乘,结果的长度不超过len1+len2
    {
        cur = (res[i] + carry) % 10;
        carry = (res[i] + carry) / 10;
        res[i] = cur;
    }
    

    size_t index = len1+len2;
    for (; index >=0; index--)
    {
        if (res[index] != 0)
        {
            break;
        }
        
    }

    for (int i = index; i >= 0; i--)
    {
        stringstream ss;
        ss<<res[i];
        string tmp = ss.str();
        result += tmp;
    }
    
    
    return result;

    
    
}

int main()
{
    string data1 = "999";
    string data2 = "99";

    string res = multi(data1,data2);

    cout<<"res:"<<res<<endl;

    return 0;
}

5. 除法

利用了前面的大数相减的部分,主要思路为:以999除以9为例,两数相差两位,想让9*100=900,999可以减去9个100,然后9*10=90,余下的99可以减10个90,然后余下的9可以减去1个9,那么从前往后依次拼接每阶段得到的结果,最终得到111。

#include <string>
#include <iostream>
#include <sstream>
#include <algorithm>

using namespace std;

bool sub(string &data1, string &data2)
{
    int len1 = data1.length();
    int len2 = data2.length();
    bool isNeg = false; //判断是否为负
    int cur = 0;  // 当前位
    int carry = 0; //借位
    string res = "";

    if (len1 < len2)  //很重要,在做运算前,将大的数作为被减数,这样可以避免很多问题
    {
        return false;
    }else if (len1 == len2)   //当两个字符串的长度相等时,怎么判断哪个字符串比较大,这个逻辑比较有意思
    {
        for (size_t i = 0; i < len1; i++)
        {
            if (data1[i] < data2[i])
            {
               return false;
            }else if (data1[i] > data2[i])
            {
                isNeg = false;
            }
            
            
        }
        
    }

    int len = min(len1, len2);

    size_t i = 0;

    for (; i < len; i++)
    {
        cur = data1[len1 - i - 1] - data2[len2 - i - 1] - carry;  //字符相减与整数相减一样,不用减'0'

        if (cur < 0)
        {
            cur = cur + 10;
            carry = 1;
        }else
        {
            carry = 0;
        }

        stringstream ss;

        ss<<cur;
        string tmp = ss.str();
        
        res += tmp;

        
    }

    for (; i < len1; i++) //将最长的字符串的剩余部分添加到结果当中
    {
        cur = data1[len1 - i - 1] - '0' - carry; //减去借位, 这里必须减‘0’,容易忽略

        if (cur < 0)
        {
            cur = cur + 10;
            carry = 1;
        }else
        {
            carry = 0;
        }

        stringstream ss;

        ss<<cur;
        string tmp = ss.str();
        
        res += tmp;
    }

    int index = len1 - 1;

    while (res[index] == '0')  //从后面开始的“0”全部去掉,找到不为0的第一个下标
    {
        index --;
    }

    res = res.substr(0,index+1); 

    if (res.length() == 0)  //特殊情况,为零则返回“0”,避免-0的情况出现
    {
        data1 = res;
        return true;
    }
    

    if (isNeg) //负数则加负号
    {
        res += "-";
    }

    reverse(res.begin(), res.end());  //与加法一样,反转

    data1 = res;

    return !isNeg;
    
    
}

string div(string &data1, string &data2)
{
    int len1 = data1.length();
    int len2 = data2.length();
    int cur = 0;  // 当前位
    int carry = 0; //借位
    string result = "";
    

    if (len1 < len2)  //如果被除数小于除数则直接返回“0”
    {
        return "0";
    }else if (len1 == len2)   
    {
        for (size_t i = 0; i < len1; i++)
        {
            if (data1[i] < data2[i])
            {
                return "0";
            }else if (data1[i] > data2[i])
            {
                break;
            }
            
            
        }
        
    }

    int count = len1 - len2;  //两个数相差几位
    int res[100] = {0};
    for (int i = count; i >=0; i--)
    {
        string data2_copy = data2;
        for (size_t j = 0; j < i; j++)
        {
            data2_copy += "0";  //后面补0,如果补两个0则为100倍
        }
        while (sub(data1,data2_copy))
        {
            res[count - i] ++;  //能减多少个,从能减的最大数开始减起,直到不能减
        }

        stringstream ss;
        ss<< res[count - i];
        string tmp = ss.str();
        result += tmp;    //依次将能减的数拼接,利用前面写的大数相减
        
        
    }
    
    
    return result;

    
    
}

int main()
{
    string data1 = "999";
    string data2 = "99999";

    string res = div(data1,data2);

    cout<<"res:"<<res<<endl;

    return 0;
}

6. 参考文献

1. https://www.cnblogs.com/wuqianling/p/5387099.html (大数的四则运算(加法、减法、乘法、除法)

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值