加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

大数运算(高精度运算)——通用解决方案

发布时间:2020-12-14 02:01:05 所属栏目:大数据 来源:网络整理
导读:核心思想:自定义大数类型(结构体或类),重载运算符。 最简单的大数运算模板: const int maxn = 1000;struct Bign{ int s[maxn],len; Bign() { memset(s,sizeof(s)); len = 1; } Bign operator = (const char* num) { len = strlen(num); for(int i = len

核心思想:自定义大数类型(结构体或类),重载运算符。


最简单的大数运算模板:

const int maxn = 1000;
struct Bign
{
    int s[maxn],len;

    Bign()
    {
        memset(s,sizeof(s));
        len = 1;
    }

    Bign operator = (const char* num)
    {
        len = strlen(num);
        for(int i = len-1,j = 0; i>=0; i--) s[j++] = num[i] - '0';
        return *this;
    }

    Bign operator + (const Bign& b)const
    {
        Bign result;
        result.len = 0;

        int c = 0;
        for(int i = 0; i < max(len,b.len); i++)
        {
            if(i < len && i < b.len)
            {
                c += s[i] + b.s[i];
            }
            else
            {
                if(i < len)
                {
                    c += s[i];
                }

                if(i < b.len)
                {
                    c += b.s[i];
                }
            }

            result.s[result.len ++] = c % 10;
            c = c / 10;
        }

        if(c != 0) result.s[result.len ++] = c;

        return result;
    }
};


若用到其他运算,重载其他运算符即可。具体可参照《算法竞赛入门经典——刘汝佳 编著》中的5.2.3 高精度运算类bign


调用示例:

#include<iostream>
#include<cstring>
#define max(a,b) (a>b ? a : b)
#define min(a,b) (a<b ? a : b)

using namespace std;

const int maxn = 1000;
struct Bign
{
    int s[maxn],b.len); i++)
        {
            if(i < len && i < b.len)
            {
                c += s[i] + b.s[i];
            }
            else
            {
                if(i < len)
                {
                    c += s[i];
                }

                if(i < b.len)
                {
                    c += b.s[i];
                }
            }

            result.s[result.len ++] = c % 10;
            c = c / 10;
        }

        if(c != 0) result.s[result.len ++] = c;

        return result;
    }
};

int main()
{
    Bign a;
    a = "123456";

    Bign b;
    b = "123456";

    Bign c = a + b;

    for(int i=0; i<c.len; i++) cout<<c.s[i]<<" ";

    return 0;
}

====================================================================================

《拓展》

参考网站:大数相乘

在如下程序中包含了编程时的大部分思路,不当之处,敬请指正。


#include<iostream>
#include<cstring>
#define max(a,b) (a>b ? a : b) //表达式宏的最外面 最好 用一个括号括起来
#define min(a,b) (a<b ? a : b)

using namespace std;

const int maxn = 1000;
struct Bign //存储 数字的逆序数组 + 长度
{
    int s[maxn],sizeof(s));//头文件是<string.h>或<memory.h>
        len = 0;//没赋值之前没有值,故位数为0
    }


    /*
    赋值运算
    */
    Bign operator = (const char* num)
    {
        len = strlen(num);
        for(int i = len-1,j = 0; i>=0; i--) s[j++] = num[i] - '0'; //逆序存储
        return *this; //需要改变对象自身 (注意与下面的'+'、'-'、'*'、'/'区分)
    }


    /*
    赋值运算
    */
    Bign operator = (const Bign& b){
        len = b.len;

        for(int i=0;i<len;i++){
            s[i] = b.s[i];
        }

        return *this;
    }


    /*
    加法运算
    */
    Bign operator +(const Bign& b)const
    {
        Bign result;
        result.len = 0;

        int c = 0;//进位标志
        for(int i = 0; i < max(len,b.len); i++)
        {
            /*
            if(i < len && i < b.len)
            {
                c += s[i] + b.s[i];
            }
            else
            {
                if(i < len)
                {
                    c += s[i];
                }

                if(i < b.len)
                {
                    c += b.s[i];
                }
            }*/
            //上面的注释部分可以简化为:
            if(i < len) c += s[i]; //如果当前位未超过该数值的最大位数,就加上该数值的当前位。
            if(i < b.len) c += b.s[i];//...

            result.s[result.len ++] = c % 10;
            c = c / 10;
        }

        if(c != 0) result.s[result.len ++] = c;

        return result; //不改变对象自身,而是重建了一个对象。
    }


    /*
    减法运算
    */
    Bign operator -(const Bign& b)const
    {
        Bign a = *this;
        Bign result;

        int c = 0;//上一位的计算向当前位借位了吗
        for(int i=0;i<max(a.len,b.len);i++){

            //给上一位的计算  收拾摊子
            if(c == 1) {//上一位的计算向当前位借位过
                a.s[i] -= 1;
                c = 0;
            }

            //做当前位计算的工作
            if(a.s[i] < b.s[i]){ //当前位的计算需要向更高位借位
                c = 1;
                result.s[result.len ++] = a.s[i] + 10 - b.s[i]; //在此处隐藏着一个小Bug,在高位可能出现多余的0
            }else{
                result.s[result.len ++] = a.s[i] - b.s[i];
            }
        }

        //做完减法之后,高位可能会有多余的0存留
        result.reduceExtraZero();

        return result;
    }

    /*
    去除Bign中高位的多余的0
    */
    void reduceExtraZero(){
        while(len >= 1){
            if(s[len-1] == 0) len --;
            else break;
        }
    }

    /*
    乘法运算:参考网站:http://blog.sina.com.cn/s/blog_7496d1d601010o4e.html
    */
    Bign operator *(const Bign& b) const
    {
        Bign a = *this;
        Bign result;

        result.len = a.len + b.len;
        memset(result.s,sizeof(result.s));//注意一定要进行初始化,否则,虽然程序不会崩溃,但结果会出错。

        if(result.len > maxn) cout<<"结果溢出";
        else{
            cout<<"aaa"<<endl;
            //逐位相乘
            for(int i=0;i<a.len;i++)
            for(int j=0;j<b.len;j++) result.s[i + j] += a.s[i] * b.s[j];

            cout<<"bbb"<<endl;
            //处理进位
            int c = 0;//进位的数值
            for(int i=0;i<result.len;i++){
                int temp = (result.s[i] + c) % 10;
                c = (result.s[i] + c) / 10;
                result.s[i] = temp;
            }
            if(c) result.s[result.len ++] = c;

            cout<<"ccc"<<endl;
            //去除多余的0
            result.reduceExtraZero();

            return result;

            cout<<"eee"<<endl;
        }
    }
};

void print(const Bign& bign){ //可重载输入输出运算符实现
    for(int i = bign.len -1; i >= 0;i --)
        cout << bign.s[i];
}

int main()
{
    Bign a;
    a = "1234578";

    Bign b;
    b = "1234567";

    Bign result;

    result = a + b;
    print(a); cout<<" + "; print(b); cout<<" = "; print(result);
    cout<<endl;

    result = a - b;
    print(a); cout<<" - "; print(b); cout<<" = "; print(result);
    cout<<endl;

    result = a * b;
    cout<<"ddd"<<endl;
    print(a); cout<<" * "; print(b); cout<<" = "; print(result);
    cout<<endl;
    return 0;
}

运行结果:



对上述高精度乘法进行分析如下:


1. 高精度乘法的实现原理

(1)?前期准备

a.将两个因子逆序存入字符串中。

b.初始化结果:

? ? ? ?b1:位数 ——?result.len = a.len + b.len;

解析:

结果的位数最多为两因子位数之和 ? ? ?:result.len = a.len + b.len; 最大的例子:99*99=9791. 2 2 ——>4??...? ? 最少为两因子位数之和减1: 最小的例子:10*10=100. 2 * 2 ——>3

? ? ? ?b2:将各位置0。

(2)?逐位计算

result.s[i + j] = a.s[i]*b.s[j];

(3)处理进位

现就上一步的方法进行举例:

原数值: 12*26

a = (2,1)

b = (6,2)

? ? ? ? ? ? ? ? result = (12,10,1)

将上一步得到的结果,各位依次为:(12,1)

? ? ? ??故需要使用除10和余10处理进位:结果为(2,1,2)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读