大整数运算——存储、比较、加减乘除,附带代码实现

版权声明:转载留名即可 ^_^ https://blog.csdn.net/qq_33375598/article/details/88751942

1 大整数的存储

大整数:高精度整数,其含义是基本数据类型无法存储其精度的整数。

整数的高位存储在数组的高位,整数的低位存储在数组的低位,不反过来的原因是,在运算的时候都是从整数的低位到高位进行枚举,顺位存储和这种思维相合。

例如:235813 存储在数组中,即有d[0] = 3,d[1]= 1,d[2] = 8, d[3] = 5, d[4] =3, d[5] = 2;

⚠️: 把整数按字符串%s读入的时候,实际上是逆位存储的,即str[0] =‘2', str[3] = ‘3’,str[5]= ‘3’,因此在读入的之后,需要另存为至d[]数组的时候反转一下。

为了方便获取大整数的长度,一般会定义一个int类变量len来记录其长度,并和d数组合成结构体:

struct bign{
    int d[1000];
    int len;
    bign(){
        memset(d,0, sizeof(d));
        len = 0;
    }
};

初始化结构体,是为了减少在世纪输入代码时,总是忘记初始化的问题。

在输入大整数的时,一般都是先用字符串读入,然后再把字符串另存至bign结构体。

bign change(char str[]){//将整数转为bign
    bign a;
    a.len = strlen(str);//bign的长度,就是字符串的长度
    for (int i = 0; i < a.len; ++i) {
        a.d[i] = str[a.len - 1 - i] -'0';//逆着赋值
    }
    return a;
}
比较两个bign变量的大小:
先判断两者的len大小,如果不想等,则以长的为大,如果相等,则从高位到低位进行比较,直到出现某一位不相等,就可以判断两个数的大小。
 
int compare(bign a, bign b){//比较a和b的大小,a大、相等、小分别对应着1,0,-1
if(a.len > b.len) return 1;
else if(a.len < b. len) return -1;
else{
for (int i = a.len - 1; i >= 0; ++i) {//从高位往低位比,
if(a.d[i] > b.d[i]) return 1;//只要有一位a大,则a大
else if(a.d[i] < b.d[i]) return -1;
}
}
return 0;
}
 
2,大整数的四则运算
2.1,高精度的加法
根据整数的加法,可以得知:
对其中一位进行加法的步骤:将该位上的数组和进位相加,得到的结果取个位作为该位结果,取十位数作为新的进位。
bign add(bign a, bign b){
bign c;
int carry = 0;//进位
for (int i = 0; i < a.len || i < b.len; ++i) {//以较长的为界
int temp = a.d[i] + b.d[i] + carry;//两个对应位和进位相加
c.d[c.len++] = temp % 10;//个位数为该位的结果
carry = temp / 10;//十位数为新的进位
}

if(carry!= 0){//如果最后结果不为0,直接赋给结果的最高位
c.d[c.len++] = carry;
}
return c;
}
输出:
void print(bign a){
    for (int i = a.len - 1; i >= 0; --i) {
        printf("%d",a.d[i]);
    }
}
⚠️:这样的写法条件:是两个对象都是非负数,如果有一方时负数,可以在转换到数组这一步时去掉符号,然后采用高精度减法;
如果两者都是负的,就都去掉负号后用高精度加法,最后再把负数加回去即可。
2.2 高精度减法
通过整数的减法可知:
对于某部,比较被减位和减位,如果不够减,则令被减位的高位减1、被减位加10再进行减法;如果够减,则直接减。
最后一步要注意减法后高位可能有多余的0,要除去它们,但也要保证结果至少有一位。

bign sub(bign a, bign b){
    bign c;
    for (int i = 0; i < a.len ||i < b .len; ++i) {
        if(a.d[i] - b.d[i] < 0){//如果不够减
            a.d[i+1]--;//向高位借位
            a.d[i] += 10;//向前一位加10
        }
        c.d[c.len++] = a.d[i] - b.d[i];//减法结果为当前位结果
    }
    while (c.len - 1 >= 1 && c.d[c.len - 1] == 0){
            c.len--;//除去高位的零,并至少保留一位
    }
    return c;
}
⚠️:使用sub函数前要比较两个数的大小,如果被减数小于减数,需要交换两个变量,然后输出负号,在使用sub函数。

2.3高精度的乘法

bign multi(bign a, int b){//高精度与低精度的乘法
    bign c;
    int carry = 0;
    for (int i = 0; i < a.len; ++i) {
        int temp = a.d[i] * b + carry;
        c.d[c.len++] = temp % 10;//个位作为该位的结果
        carry = temp / 10;//高位作为新的进位
    }
    while (carry != 0){//和加法不一样,乘法的进位不止一位
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}

 2.4高精度的除法

void i2s(int i, string& s){
    stringstream stream;
    stream << i;
    stream >> s;
}

int cmp(string a, string b){//比较大小
    int i1 = a.find_first_not_of('0');
    int i2 = b.find_first_not_of('0');

    if(i1 == string::npos) a = "0";
    else a = a.substr(i1);
    if(i2 == string::npos) b = "0";
    else b = b.substr(i2);

    if(a.length() > b.length()) return 1;
    else if(a.length() < b.length()) return -1;
    else{
        if(a > b) return 1;
        else if(a < b) return -1;
        else return 0;
    }
}

string subtract(string a, string b){//减法:前提:a大于b
    reverse(a.begin(), a.end());
    reverse(a.begin(), b.end());
//'0'为基准,char——int:减'0',int——char:加'0'
    for (int i = 0; i < b.length(); ++i) {
        if(a[i] > b[i]){
            a[i] = a[i] -b[i] + '0';
        }else{
            int k = 1;
            while(a[i+k] == '0'){
                a[i+k] = '9';
                k++;
            }
            a[i+k] = a[i+k] -'1' +'0';
            a[i] = (a[i] -'0' + 10) - (b[i] - '0') + '0';
        }
    }
    reverse(a.begin(), a.end());
    if(a.find_first_not_of('0') == string::npos) return "0";
    return a.substr(a.find_first_not_of('0'));
}

string devide(string a, string b){
    string ans = "0.";
    int n = 101;
    for (int i = 0; i < n; ++i) {
        a.append("0");
        int t =0;
        while(cmp(a,b) >= 0){
            a = subtract(a,b);
            t++;
        }
        string t_str;
        i2s(t,t_str);
        ans.append(t_str);
    }
    return ans;
}
bign divide(bign a, int b, int &r){//高精度与低精度的除法,余数为r
    bign c;
    c.len = a.len;//被除数的每一位和商的每一位一一对应,因此先令长度相等
    for (int i = a.len - 1; i >= 0 ; --i) {//从高位开始
         r = r * 10 + a.d[i];//和上一位的遗留的余数组合
        if(r < b) c.d[i] = 0;
        else{//够除
            c.d[i] = r / b;//商
            r = r % b;//获得新的余数
        }
    }
    while(c.len - 1>=1 && c.d[c.len -1] == 0){//去除高位的零,至少保留一位
        c.len--;
    }
    return c;
}

高精度的除法(a小于b,带小数):

void i2s(int i, string& s){
    stringstream stream;
    stream << i;
    stream >> s;
}

int cmp(string a, string b){//比较大小
    int i1 = a.find_first_not_of('0');
    int i2 = b.find_first_not_of('0');

    if(i1 == string::npos) a = "0";
    else a = a.substr(i1);
    if(i2 == string::npos) b = "0";
    else b = b.substr(i2);

    if(a.length() > b.length()) return 1;
    else if(a.length() < b.length()) return -1;
    else{
        if(a > b) return 1;
        else if(a < b) return -1;
        else return 0;
    }
}

string subtract(string a, string b){//减法:前提:a大于b
    reverse(a.begin(), a.end());
    reverse(a.begin(), b.end());
//'0'为基准,char——int:减'0',int——char:加'0'
    for (int i = 0; i < b.length(); ++i) {
        if(a[i] > b[i]){
            a[i] = a[i] -b[i] + '0';
        }else{
            int k = 1;
            while(a[i+k] == '0'){
                a[i+k] = '9';
                k++;
            }
            a[i+k] = a[i+k] -'1' +'0';
            a[i] = (a[i] -'0' + 10) - (b[i] - '0') + '0';
        }
    }
    reverse(a.begin(), a.end());
    if(a.find_first_not_of('0') == string::npos) return "0";
    return a.substr(a.find_first_not_of('0'));
}

string devide(string a, string b){
    string ans = "0.";
    int n = 101;
    for (int i = 0; i < n; ++i) {
        a.append("0");
        int t =0;
        while(cmp(a,b) >= 0){
            a = subtract(a,b);
            t++;
        }
        string t_str;
        i2s(t,t_str);
        ans.append(t_str);
    }
    return ans;
}

猜你喜欢

转载自blog.csdn.net/qq_33375598/article/details/88751942