[位压] 高精度加法

这算是本BLOG的第一篇文章吧,算法这一块荒废了很长时间,,这份代码刚开始写的时候,刚输完main时,整个人都是蒙的,不知该如何往下走。

好在成功写完了。由于没啥状态,所以这个高精+功能非常简单,只能+,不支持负数。

 

这里说一下位压的思想,一般的评测机都是32位的,所以一个int能储存32位数据。

再来看一看0 ~ 9,二进制分别对应0000~1001,所以一个4位二进制正好可以存储,所以这里就4位存一个数字,32位正好8个。

首先来设计输入函数:

inline bool read (int & ret, int bit) {//存到一个32位整数里
    int c = getchar();
    if (c < '0' || c > '9') return 0;
    c = c - '0';
    c <<= (bit << 2); //bit * 4
    ret |= c;
    return 1;//该数是否读取成功,用于while的结束
}

返回一个bool,表示当前输入是否成功,一般返回也就代表一行输入完了。
函数思想和快速读入差不多,也是getchar,然后变成整数。一个int可以存8个数字,其中参数bit(新京报命名)表示存为第几位数字。

读写好了,接下来就是取,取数字的话分为两种:

  1. 对于一个单独的int取数
  2. 对于一整个(高精度)数组取数

第一种比较好实现,但是会出一小点点问题:

inline void get_num (int n_arr, int bit, int & ret) {//取数字
    ret = (n_arr >> (bit << 2)) & 15;
}

 因为我们存数字是从高位开始读取的,高位的数字优先存储在int中的低位
比如我输入1234,读取函数返回的int为171855,二进制为0100 0011 0010 0001,十六进制为4321

可以看到正好反过来了,所以我们搞不清楚某一个int中到底存储了多少个有效数字。

这种存储方式中,1234和12340的int值是相等的,不过我们可以通过记录每一个高精度数字的总位数来避免这种情况,理由是:

  1. 只要不是高精数的最后几位不满8个数的,其他高位上的int都能存储8位整数
  2. 当某个int存储了不到8个数时,往前(高位)的位都是全0填充

所以只要单开两个变量存储数字的总位数即可。

先讲讲第二种取数字

inline void get_arr_num(int * arr, int bit, int & ret) {//对一个高精度数字取出某一位
    -- bit;
    int a = bit / 8, b = bit - a * 8;
    get_num (arr[a], b, ret);
}

这里数字位数是从1开始的,注意。。

参数的解释:arr数组表示某一个高精度数,bit是取这个高精度数字的第几位,最高位是1,依次往下。ret就是返回。。。

a代表要取的数字在第几个数组里,向下取整,因为高位数字在数组中的下标更小,b表示该位数字存储在32位int中的第几个。

最后最后,就是main了,主函数中包含了这几个部分:

  1. 读入两个高精度操作数
  2. 循环开始从这两个数字的最低位相加,一直加到最大的那个数的最高位
  3. 保存结果,输出

这里直接放全部的代码吧。。

#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;

int num_a [505];
int num_b [505];

inline bool read (int & ret, int bit) {//存到一个32位整数里
    int c = getchar();
    if (c < '0' || c > '9') return 0;
    c = c - '0';
    c <<= (bit << 2); //bit * 4
    ret |= c;
    return 1;//该数是否读取成功,用于while的结束
}

inline void get_num (int n_arr, int bit, int & ret) {//取数字
    ret = (n_arr >> (bit << 2)) & 15;
}

/*inline int get_num_long (int n) {//查询一个数字中的有效数字存储个数
    int r = 8,z = 15 << 28;
    while (!(n & z)) {
        -- r;
        z >>= 4;
    }
    return r;
}*/

inline void get_arr_num(int * arr, int bit, int & ret) {//对一个高精度数字取出某一位
    -- bit;
    int a = bit / 8, b = bit - a * 8;
    get_num (arr[a], b, ret);
}

int main () {
    int b_p = 0, l_p = 0;
    int a_l = 0, b_l = 0;
    while (read (num_a [b_p], l_p)) {//读取数字a
        ++ l_p; a_l ++;
        if (l_p == 8) {
            l_p = 0;
            ++ b_p;
        }
    }
    b_p = 0, l_p = 0;
    while (read (num_b [b_p], l_p)) {//读取数字b
        ++ l_p; b_l ++;
        if (l_p == 8) {
            l_p = 0;
            ++ b_p;
        }
    }

    string OP;//OutPut
    int Cin = 0;//进位
    int a, b, c;//a的某位,b的某位,c=a+b
    for (int i = a_l,j = b_l; (i > 0) | (j > 0); -- i, -- j) {//最低位开始相加
        if (i > 0) {
            get_arr_num (num_a, i, a);
        } else { //判断是否超出最高位
            a = 0;
        }
        if (j > 0) {
            get_arr_num (num_b, j, b);
        } else {
            b = 0;
        }
        c = a + b + Cin;
        if (c >= 10) {//是否进位
            Cin = 1;
            OP = (char) (c - 10 + '0') + OP;
        } else {
            Cin = 0;
            OP = (char) (c + '0') + OP;
        }
    }
    if (Cin) cout << '1';//判断最高位是否进位
    cout << OP;
    return 0;
}

当然,所有的思想都是自己想出来的,这份代码也只是临时起意,并没有经过评测,仅供参考,如有BUG,也算正常,还请指点

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值