数学问题——大整数运算

Posted Just_for_Myself

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数学问题——大整数运算相关的知识,希望对你有一定的参考价值。

  大整数又称为高精度整数,其含义就是用基本数据类型无法储存其精度的整数。

 

一、大整数的存储

  很简单,使用数组即可。例如定义 int 型数组 d[1000],那么这个数组的每一位代表了存放整数的每一位。整数的高位储存在数组的高位,整数的低位储存在数组的低位

  而为了方便随时获取大整数的长度,一般都会定义一个 int 型变量 len 来记录其长度,结构体如下:

1 // 大整数 
2 struct bign {
3     int d[1000];
4     int len;
5 }; 

  在定义结构体变量后,需要马上初始化结构体,加上“构造函数”,代码如下:

// 大整数 
struct bign {
    int d[1000];
    int len;
    bign() {    // 构造函数 
        memset(d, 0, sizeof(d));
        len = 0;
    } 
}; 

 

 

  而输入大整数时,一般都是先用字符串读入,然后再把字符串另存为至 bign 结构体。由于使用 char 数组进行读入时,整数的高位会变成数组的低位,因此需要让字符串倒着赋给 d[] 数组:

 1 // 将字符串另存至 bign 结构体
 2 bign change(char str[]) {
 3     bign a;
 4     a.len = strlen(str);        // bign 的长度就是数组的长度 
 5     int i;
 6     for(i=0; i<a.len; ++i) {    // 倒着赋值 
 7         a.d[i] = str[a.len-1-i] - 0;
 8     }
 9     return a;
10 }

 

 

  如果要比较两个 bign 变量的大小,规则也很简单:先判断两者的 len 的大小,如果不相等,则以长的为大;如果相等,则从高位到低位进行比较,直到出现某一位不等,就可以判断两个数的大小。代码如下:

 1 // 比较两个大整数变量的大小
 2 // a 大、相等、小分别返回 1、0、-1 
 3 int compare(bign a, bign b) {
 4     if(a.len ? b.len)    return 1;        // a>b
 5     else if(a.len < b.len)    return -1;    // a<b
 6     else {
 7         int i;
 8         for(i=0; i<a.len; ++i) {                // 从高位到低位比较 
 9             if(a.d[i] > b.d[i])    return 1;        // a>b
10             else if(a.d[i] < b.d[i]) return -1;    // a<b
11         }
12         return 0;        // 两者相等 
13     }
14 } 

 

 

 

二、大整数的四则运算

  1. 高精度加法

  容易得到对其中一位进行加法的步骤:将该位上的两个数字与进位相加,得到的结果取个位数作为该位结果,取十位数作为新的进位。代码如下:

 1 // 高精度加法
 2 bign add(bign a, bign b) {
 3     bign c;
 4     int carry = 0;    // 进位
 5     int i;
 6     for(i=0; i<a.len || i<b.len; ++i) {            // 以较长的为界限 
 7         int temp = a.d[i] + b.d[i] + carry;        // 其中一位相加
 8         c.d[c.len++] = temp%10;                    // 取个位
 9         carry = temp/10;                        // 新的进位 
10     } 
11     if(carry != 0) {                // 有进位 
12         c.d[c.len++] = carry;
13     }
14     return c; 
15 } 

  测试一下加法代码,以下为 C 代码:

技术分享图片
 1 /*
 2     大整数运算 
 3 */
 4 
 5 #include <stdio.h>
 6 #include <string.h>
 7 #include <math.h>
 8 #include <stdlib.h>
 9 #include <time.h>
10 #include <stdbool.h>
11 
12 // 大整数 
13 typedef struct{
14     int d[1000];
15     int len;
16     // C 中 struct 不能有函数 
17     /*bign() {    // 构造函数 
18         memset(d, 0, sizeof(d));
19         len = 0;
20     }*/ 
21 } bign; 
22 
23 // 大整数初始化 
24 bign init() {
25     bign temp = { {0},0 };
26     return temp;
27 }
28 
29 // 将字符串另存至 bign 结构体
30 bign change(char str[]) {
31     bign a = init();
32     a.len = strlen(str);        // bign 的长度就是数组的长度 
33     int i;
34     for(i=0; i<a.len; ++i) {    // 倒着赋值 
35         a.d[i] = str[a.len-1-i] - 0;
36     }
37     return a;
38 } 
39 
40 // 比较两个大整数变量的大小
41 // a 大、相等、小分别返回 1、0、-1 
42 int compare(bign a, bign b) {
43     if(a.len > b.len)    return 1;        // a>b
44     else if(a.len < b.len)    return -1;    // a<b
45     else {
46         int i;
47         for(i=0; i<a.len; ++i) {                // 从高位到低位比较 
48             if(a.d[i] > b.d[i])    return 1;        // a>b
49             else if(a.d[i] < b.d[i]) return -1;    // a<b
50         }
51         return 0;        // 两者相等 
52     }
53 } 
54 
55 // 高精度加法
56 bign add(bign a, bign b) {
57     bign c = init();
58     int carry = 0;    // 进位
59     int i;
60     for(i=0; i<a.len || i<b.len; ++i) {            // 以较长的为界限 
61         int temp = a.d[i] + b.d[i] + carry;        // 其中一位相加
62         c.d[c.len++] = temp%10;                    // 取个位
63         carry = temp/10;                        // 新的进位 
64     } 
65     if(carry != 0) {                // 有进位 
66         c.d[c.len++] = carry;
67     }
68     return c; 
69 } 
70 
71 // 输出大整数 
72 void print(bign a) {
73     int i;
74     for(i=a.len-1; i>=0; --i) {
75         printf("%d", a.d[i]);
76     }
77     printf("\n");
78 }
79 
80 int main() {
81     char str1[1000], str2[1000];
82     scanf("%s%s", str1, str2);
83     bign a = change(str1);
84     bign b = change(str2);
85     print(add(a, b));
86 
87     return 0;
88 }
测试加法

 

 

  2. 高精度减法

  同样,对其中一位进行减法的步骤:比较被减位和减位,如果不够减,则令被减位的高位减 1、被减位加 10 再进行减法;如果够减,则直接减。最后一步要注意减法后高位可能有多余的 0,要去除它们,但也要保证结果至少有一位数。代码如下:

 1 // 高精度减法 
 2 bign sub(bign a, bign b) { 
 3     bign c = init();
 4     int i;
 5     for(i=0; i<a.len || i<b.len; ++i) {    // 以较长的为界限 
 6         if(a.d[i] < b.d[i]) {            // 不够减 
 7             a.d[i+1]--;
 8             a.d[i] += 10;
 9         }
10         c.d[c.len++] = a.d[i] - b.d[i];
11     }
12     while(c.len-1 >= 1 && c.d[c.len-1] == 0) {
13         c.len--;    // 去除高位的0,同时至少保留一位最低位 
14     }
15     return c;
16 }

 

 

 

 

  最后需要指出,使用 sub 函数前要比较两个数的大小,如果被减数小于减数,需要交换两个变量,然后输出负号,再使用 sub 函数。

 

  3. 高精度与低精度的乘法

  所谓的低精度就是可以用基本数据类型存储的数据,例如 int 型。对某一步来说就是这么一个步骤:取 bign 的某位与 int 型整体相乘,再与进位相加,所得结果的个位数作为该位结果,高位部分作为新的进位。代码如下:

 1 // 高精度与低精度的乘法
 2 bign multi(bign a, int b) {
 3     bign c = init();
 4     int carry = 0;            // 进位
 5     int i;
 6     for(i=0; i<a.len; ++i) {
 7         int temp = a.d[i] * b + carry;
 8         c.d[c.len++] = temp%10;        // 取低位 
 9         carry = temp/10;            // 取高位作为新的进位 
10     } 
11     while(carry != 0) {        // carry 可能不止一位 
12         c.d[c.len++] = carry%10;
13         carry /= 10; 
14     }
15     return c;
16 } 

 

 

 

 

  另外,如果 a 和 b 中存在负数,需要先记录下其负号,然后取它们的绝对值代入函数。

 

  4. 高精度与低精度的除法

  其中某一步的步骤:上一步的余数乘以 10 加上该步的位,得到该步的临时被除数,将其与除数相除,商为对应的商,余数作为新的余数留作下一步用。代码如下:

 1 // r 可以用来储存余数 
 2 int r = 0;
 3 // 高精度与低精度的除法
 4 bign divide(bign a, int b) {
 5     bign c = init();
 6     c.len = a.len;        // 商的每一位与被除数对应 
 7     int i;    
 8     for(i=a.len-1; i>=0; --i) {
 9         r = r*10 + a.d[i];
10         c.d[i] = r/b;    //
11         r %= b;            // 新的余数 
12     } 
13     while(c.len-1 >= 1 && c.d[c.len-1]==0) {    
14         c.len--;    // 去除高位 0,并保证至少有一位 
15     } 
16     return c; 
17 } 

 

 

 

 

  完整的代码如下:

技术分享图片
  1 /*
  2     大整数运算 
  3 */
  4 
  5 #include <stdio.h>
  6 #include <string.h>
  7 #include <math.h>
  8 #include <stdlib.h>
  9 #include <time.h>
 10 #include <stdbool.h>
 11 
 12 // 大整数 
 13 typedef struct{
 14     int d[1000];
 15     int len;
 16     // C 中 struct 不能有函数 
 17     /*bign() {    // 构造函数 
 18         memset(d, 0, sizeof(d));
 19         len = 0;
 20     }*/ 
 21 } bign; 
 22 
 23 // 大整数初始化 
 24 bign init() {
 25     bign temp = { .d={0},.len=0 };
 26     return temp;
 27 }
 28 
 29 // 将字符串另存至 bign 结构体
 30 bign change(char str[]) {
 31     bign a = init();
 32     a.len = strlen(str);        // bign 的长度就是数组的长度 
 33     int i;
 34     for(i=0; i<a.len; ++i) {    // 倒着赋值 
 35         a.d[i] = str[a.len-1-i] - 0;
 36     }
 37     return a;
 38 } 
 39 
 40 // 比较两个大整数变量的大小
 41 // a 大、相等、小分别返回 1、0、-1 
 42 int compare(bign a, bign b) {
 43     if(a.len > b.len)    return 1;        // a>b
 44     else if(a.len < b.len)    return -1;    // a<b
 45     else {
 46         int i;
 47         for(i=0; i<a.len; ++i) {                // 从高位到低位比较 
 48             if(a.d[i] > b.d[i])    return 1;        // a>b
 49             else if(a.d[i] < b.d[i]) return -1;    // a<b
 50         }
 51         return 0;        // 两者相等 
 52     }
 53 } 
 54 
 55 // 高精度加法
 56 bign add(bign a, bign b) {
 57     bign c = init();
 58     int carry = 0;    // 进位
 59     int i;
 60     for(i=0; i<a.len || i<b.len; ++i) {            // 以较长的为界限 
 61         int temp = a.d[i] + b.d[i] + carry;        // 其中一位相加
 62         c.d[c.len++] = temp%10;                    // 取个位
 63         carry = temp/10;                        // 新的进位 
 64     } 
 65     if(carry != 0) {                // 有进位 
 66         c.d[c.len++] = carry;
 67     }
 68     return c; 
 69 } 
 70 
 71 // 高精度减法 
 72 bign sub(bign a, bign b) { 
 73     bign c = init();
 74     int i;
 75     for(i=0; i<a.len || i<b.len; ++i) {    // 以较长的为界限 
 76         if(a.d[i] < b.d[i]) {            // 不够减 
 77             a.d[i+1]--;
 78             a.d[i] += 10;
 79         }
 80         c.d[c.len++] = a.d[i] - b.d[i];
 81     }
 82     while(c.len-1 >= 1 && c.d[c.len-1] == 0) {
 83         c.len--;    // 去除高位的0,同时至少保留一位最低位 
 84     }
 85     return c;
 86 } 
 87 
 88 // 高精度与低精度的乘法
 89 bign multi(bign a, int b) {
 90     bign c = init();
 91     int carry = 0;            // 进位
 92     int i;
 93     for(i=0; i<a.len; ++i) {
 94         int temp = a.d[i] * b + carry;
 95         c.d[c.len++] = temp%10;        // 取低位 
 96         carry = temp/10;            // 取高位作为新的进位 
 97     } 
 98     while(carry != 0) {        // carry 可能不止一位 
 99         c.d[c.len++] = carry%10;
100         carry /= 10; 
101     }
102     return c;
103 } 
104 
105 // r 可以用来储存余数 
106 int r = 0;
107 // 高精度与低精度的除法
108 bign divide(bign a, int b) {
109     bign c = init();
110     c.len = a.len;        // 商的每一位与被除数对应 
111     int i;    
112     for(i=a.len-1; i>=0; --i) {
113         r = r*10 + a.d[i];
114         c.d[i] = r/b;    //
115         r %= b;            // 新的余数 
116     } 
117     while(c.len-1 >= 1 && c.d[c.len-1]==0) {    
118         c.len--;    // 去除高位 0,并保证至少有一位 
119     } 
120     return c; 
121 } 
122 
123 // 输出大整数 
124 void print(bign a) {
125     int i;
126     for(i=a.len-1; i>=0; --i) {
127         printf("%d", a.d[i]);
128     }
129     printf("\n");
130 }
131 
132 int main() {
133     char str1[1000], str2[1000];
134     scanf("%s%s", str1, str2);
135     bign a = change(str1);
136     bign b = change(str2);
137     print(add(a, b));
138     print(sub(a, b));
139     print(multi(a, 11));
140     print(divide(a, 10));
141     printf("r = %d\n", r); 
142 
143     return 0;
144 }
大整数运算

 

以上是关于数学问题——大整数运算的主要内容,如果未能解决你的问题,请参考以下文章

带有数学运算符的字符串到整数 [重复]

整数除法的数学运算

NO.5章 入门(数学问题)

输入两个整数,进行加减乘除四则运算的c语言程序怎么写啊,拜托了~

第49题常用的数学工具类6-高精度整数运算

Numpy/Python 中基本数学运算的速度:为啥整数除法最慢?