高精四则运算(正数)
郑重声明:这篇博客是我的第一篇博客,那时候刚学C语言,所以有很大问题,但又不舍得删除。一年的总结发现,关于含有小数的高精运算其实基本上不会出现,所以只要掌握高精整数四则即可,今年大一结束,再次进行总结,请移步高精四则运算整数,谢谢~
一.正整数部分
(1)加法运算
(2)减法运算
(3)乘法运算
(4)除法运算
因为考虑到位数为上百位的大数会超过所有类型变量,故全部利用字符数组进行运算,以每一个单位存放一位数为思想,后对其进行进位处理,为了方便,全部采用倒序的方式,注意体会其好处
代码如下
(1)大数加法
#include <stdio.h>
#include <string.h>
#define N 1000
int main(void)
{
char t[N+1] = {0}, a[N+1] = {0}, b[N+1] = {0};//定义数组并初始化
long int i, j, k, temp;//定义长整型变量确保后面累计相加在范围内
printf("请输入一个加数:\n");
scanf("%s",t);//t字符数组用来接受未处理的字符串
for(j=0,i=strlen(t)-1; i>=0; i--)
a[j++] = t[i] - '0';//对t字符数组进行倒序,并处理为"数字数组"
printf("请再输入一个加数:\n");
scanf("%s",t);//同上
for(j=0,i=strlen(t)-1; i>=0; i--)
b[j++] = t[i] - '0';
for(i=0,k=0; i<N; i++)//a、b数组每一项进行相加,k表示进位
{
temp = a[i] + b[i] + k;
a[i] = temp % 10;
k = temp / 10;
}
printf("加法计算结果为:\n");
for(i=N; i>=0; i--)//倒序输出,恢复原位
if(a[i] != 0)
for(; i>=0; i--)
printf("%d",a[i]);
return 0;
}
(2)大数减法
#include <stdio.h>
#include <string.h>
#define N 1000
int max(char a[],char b[],int x1,int x2);//max函数帮助判断"数字"a,b的大小
int main(void)
{
char t[N+1]={0}, a[N+1]={0}, b[N+1]={0};
int i, j, k, m, x1, x2;
printf("请输入被减数:\n");
scanf("%s",t);
x1 = strlen(t);
for(j=0,i=strlen(t)-1; i>=0; i--)
a[j++] = t[i] - '0';
printf("请输入减数:\n");
scanf("%s",t);
x2 = strlen(t);
for(j=0,i=strlen(t)-1; i>=0; i--)
b[j++] = t[i] - '0';
//上述部分与加法如出一辙,即:将数组倒序
m = max(a, b, x1, x2);
printf("减法计算结果为:\n");
if(m == 1)//a > b时,差 = a - b
{
for(i=0,k=0; i<N; i++)
{
if(a[i]+k>=b[i])
{
a[i] = a[i] - b[i] + k;
k = 0;
}
else
{
a[i] = 10 + a[i] - b[i] + k;
k = -1;
}
}
for(i=N; i>=0; i--)
if(a[i] != 0)
for(; i>=0; i--)
printf("%d",a[i]);
}
else if(m == 0)//a < b时,差 = b - a;
{
printf("-");
for(i=0,k=0; i<N; i++)
{
if(b[i]+k>=a[i])
{
b[i] = b[i] - a[i] + k;
k = 0;
}
else
{
b[i] = 10 + b[i] - a[i] + k;
k = -1;
}
}
for(i=N; i>=0; i--)
if(b[i] != 0)
for(; i>=0; i--)
printf("%d",b[i]);
}
else
printf("0\n");
return 0;
}
int max(char a[],char b[],int x1,int x2)
{
int i, m = 0;
if(x1 > x2)
m = 1;
else if(x1 == x2)
{
for(i=x1; i>=0; i--)
{
if(a[i] > b[i])
{
m = 1;
break;
}
else if(a[i] < b[i])
break;
}
if(i == -1)
m = 2;
}
return m;
}
(3)大数乘法
#include <stdio.h>
#include <string.h>
#define N 10000
int main(void)
{
char t[N+1]={0}, a[N+1]={0}, b[N+1]={0};
long int c[2*N+1]={0}, d[2*N+1]={0};
int i, j, k, m, x1, x2;
printf("请输入一个正整数:\n");
scanf("%s",t);
x1 = strlen(t);
for(j=0,i=strlen(t)-1; i>=0; i--)
a[j++] = t[i] - '0';
printf("请输入另一个正整数:\n");
scanf("%s",t);
x2 = strlen(t);
for(j=0,i=strlen(t)-1; i>=0; i--)
b[j++] = t[i] - '0';//开始与之前两个一致
for(i=0; i<x1; i++)
for(j=0; j<x2; j++)
c[i+j] += a[i]*b[j];
for(i=m=0; i<2*N; i++)
{
c[i] += m;
d[i] = c[i] % 10;
m = c[i] / 10;
}
printf("乘法计算结果为:\n");
for(i=2*N; i>=0; i--)
if(d[i] != 0)
for(; i>=0; i--)
printf("%d",d[i]);
return 0;
}
(4)大数除法
#include <stdio.h>
#include <string.h>
#define N 1000
//注意!这种方法计算比较慢,当两数差距较大时
//核心思路:将除法运算化为减法运算
int max(char a[],char b[]);
int main(void)
{
char t[N+1]={0}, a[N+1]={0}, b[N+1]={0};
long int c[N], d[N];
int i, j, k, m, n = 0;
printf("请输入被除数:\n");
scanf("%s",t);
for(j=0,i=strlen(t)-1; i>=0; i--)
a[j++] = t[i] - '0';
printf("请输入除数:\n");
scanf("%s",t);
for(j=0,i=strlen(t)-1; i>=0; i--)
b[j++] = t[i] - '0';
m = max(a,b);//开始与之前两个一致
while(m == 1)
{
n++;
for(i=0,k=0; i<N; i++)
{
if(a[i]+k>=b[i])
{
a[i] = a[i] - b[i] + k;
k = 0;
}
else
{
a[i] = 10 + a[i] - b[i] + k;
k = -1;
}
}
m = max(a,b);
}
printf("除法计算结果为:\n");
if(m == 2)
printf("%d\n", n+1);
else
{
printf("商为:\n%d\n余数为:\n",n);
for(i=N; i>=0; i--)
if(a[i] != 0)
for(; i>=0; i--)
printf("%d",a[i]);
printf("\n");
}
return 0;
}
int max(char a[],char b[])
{
int x1, x2, i, m = 0;
for(i=N; i>=0; i--)
if(a[i] != 0)
{
x1 = i;
break;
}
for(i=N; i>=0; i--)
if(b[i] != 0)
{
x2 = i;
break;
}
if(x1 > x2)
m = 1;
else if(x1 == x2)
{
for(i=x1; i>=0; i--)
{
if(a[i] > b[i])
{
m = 1;
break;
}
else if(a[i] < b[i])
break;
}
if(i == -1)
m = 2;
}
return m;
}
最后注意一点
本例中比较两个数大小,用到了自定义函数max,先比较位数即字符数组长度,谁长谁大,若相等长度,再比最高位,依次往低位进行比较。
思考🤔:
考虑max形参为什么不直接用两个数组如:int max(char a[], char b[]),然后在max函数里面用strlen()函数求出字符数组a和b的长度x1,x2
原因:
a, b数组是处理之后的数据,并非原始数据
例如:
刚开始输入t为100,,则a为001
然后再输入t为10,则b为01
这时候strlen(a)和strlen(b)相等
(因为处理之后字符0减去0的ascii码为’\0’,所以a数组和b数组里面能被strlen()函数测得的,只有1,所以a和b长度相等,实际上长度不等,001长度为3而01长度为2)
实际上100不等于10。所以max函数要有四个参数,字符数组长度x1,x2应在输入后(也就是倒序处理之前就应该计算长度)立即计算,也就解释了int max(char a[],char b[], int x1, int x2)中有四个参数的原因,也就是x1和x2不能在max函数内部计算。
二.带小数部分
(1)带小数的大数加法
(2)带小数的大数减法
(3)带小数的大数乘法
(4)带小数的大数除法
注 : 可以不带小数
代码如下
(1)思路: 对带小数的数(假设有小数)分开处理。没有小数的数,“小数部分”即整数后面不处理 。
#include <stdio.h>
#include <string.h>
#define N 1000
int max(int a, int b)
{
return (a>b)? a:b;
}
int main(void)
{
char t[N+1], a[N+1] = {0}, b[N+1] = {0};
char c[N+1] = {0}, d[N+1] = {0};
long int i, j, k, x1, x2, y1, y2, m, temp, flag = 0;
scanf("%s", t);
y1 = strlen(t) - 1;
for(i=y1; i>=0; i--)
if(t[i] == '.')
{
x1 = i;
flag = 1;
}
if(flag != 1)//判断是否带小数,如果没有小数,则无小数点,计算时不考虑小数部分
x1 = y1 + 1;//就主动放弃对数组a的赋值,此时a里面全是0
for(j=0,i=x1-1; i>=0; i--)
a[j++] = t[i] - '0';
for(j=0,i=x1+1; i<=y1; i++)
c[j++] = t[i] - '0';
//重复上面操作,完成两次输入
scanf("%s",t);
y2 = strlen(t) - 1;
for(i=y2; i>=0; i--)
if(t[i] == '.')
{
x2 = i;
flag = -1;
}
if(flag != -1)
x2 = y2 + 1;
for(j=0,i=x2-1; i>=0; i--)
b[j++] = t[i] - '0';
for(j=0,i=x2+1; i<=y2; i++)
d[j++] = t[i] - '0';
m = max(y1-x1,y2-x2);
// printf("%d\n",m);
for(i=m, k=0; i>=0; i--)
{
temp = c[i] + d[i] + k;
c[i] = temp % 10;
k = temp / 10;
}
if(k == 1)
a[0] += 1;
for(i=0,k=0; i<N; i++)
{
temp = a[i] + b[i] + k;
a[i] = temp % 10;
k = temp / 10;
}
temp = 0;
for(i=N; i>=0; i--)
if(a[i] != 0)
for(; i>=0; i--)
{
printf("%d",a[i]);
temp = 1;
}
if(!temp)
printf("0");
if(flag)
printf("%c",'.');
for(i=0; i<m; i++)
printf("%d",c[i]);
return 0;
}
(2)思路:将两个数字的小数和整数(假设有小数),没有就不处理“小数部分”,即整数后不做处理
#include <stdio.h>
#include <string.h>
#define N 1000
int max_1(char a[], char b[], int x1, int x2);
int max_2(char c[], char d[], int n);
int max_len(int a, int b)
{
return (a>b)? a:b;
}
int main(void)
{
char t[N+1], a[N+1] = {0}, b[N+1] = {0};
char c[N+1] = {0}, d[N+1] = {0};
long int i, j, k, x1, x2, y1, y2, temp, m, n, flag = 0;
scanf("%s",t);
y1 = strlen(t) - 1;
for(i=y1; i>=0; i--)
if(t[i] == '.')
{
x1 = i;
flag = 1;
}
if(flag != 1)
x1 = y1 + 1;
for(j=0,i=x1-1; i>=0; i--)
a[j++] = t[i] - '0';
for(j=0,i=x1+1; i<=y1; i++)
c[j++] = t[i] - '0';
//重复上面操作,完成两次输入
scanf("%s",t);
y2 = strlen(t) - 1;
for(i=y2; i>=0; i--)
if(t[i] == '.')
{
x2 = i;
flag = -1;
}
if(flag != -1)
x2 = y2 + 1;
for(j=0,i=x2-1; i>=0; i--)
b[j++] = t[i] - '0';
for(j=0,i=x2+1; i<=y2; i++)
d[j++] = t[i] - '0';
m = max_1(a,b,x1,x2);
n = max_len(y1-x1,y2-x2);
if(m == 2)
m = max_2(c, d, n);
if(m == 1)
{
for(j=n,k=0; j>=0; j--)
{
if(c[j]+k>=d[j])
{
c[j] = c[j] - d[j] + k;
k = 0;
}
else
{
c[j] = 10 + c[j] - d[j] + k;
k = -1;
}
}
a[0] += k;
for(i=0,k=0; i<N; i++)
{
if(a[i]+k>=b[i])
{
a[i] = a[i] - b[i] + k;
k = 0;
}
else
{
a[i] = 10 + a[i] - b[i] + k;
k = -1;
}
}
for(i=N; i>=0; i--)
if(a[i] != 0)
for(; i>=0; i--)
{
k = 1;
printf("%d",a[i]);
}
if(!k)
printf("0");
if(flag)
printf("%c",'.');
for(j=0; j<n; j++)
printf("%d",c[j]);
}
else if(m == 0)
{
printf("-");
for(j=n,k=0; j>=0; j--)
{
if(d[j]+k>=c[j])
{
d[j] = d[j] - c[j] + k;
k = 0;
}
else
{
d[j] = 10 + d[j] - c[j] + k;
k = -1;
}
}
b[0] += k;
for(i=0,k=0; i<N; i++)
{
if(b[i]+k>=a[i])
{
b[i] = b[i] - a[i] + k;
k = 0;
}
else
{
b[i] = 10 + b[i] - a[i] + k;
k = -1;
}
}
for(i=N; i>=0; i--)
if(b[i] != 0)
for(; i>=0; i--)
{
k = 1;
printf("%d",b[i]);
}
if(!k)
printf("0");
if(flag)
printf("%c",'.');
for(j=0; j<n; j++)
printf("%d",d[j]);
}
else
printf("0\n");
return 0;
}
//比较两个数组大小,保证差值为正
int max_1(char a[], char b[], int x1, int x2)
{
int i, m = 0;
if(x1 > x2)
m = 1;
else if(x1 == x2)
{
for(i=x1; i>=0; i--)
{
if(a[i] > b[i])
{
m = 1;
break;
}
else if(a[i] < b[i])
break;
}
if(i == -1)
m = 2;
}
return m;
}
int max_2(char c[], char d[], int n)
{
int i, m = 0;
if(n < 0)
m = 2;
for(i = 0; i < n; i++)
{
if(c[i] > d[i])
{
m = 1;
break;
}
else if(c[i] < d[i])
{
m = 0;
break;
}
}
if(i == n)
m = 2;
return m;
}
(3)思路,将两个数除去小数点,变成整数乘以整数,再根据原来的两个小数小数位数保留小数。步骤如下:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 1000
int proces(char t[], int x)
{
char *p;
int i, j = 0, s = 0;
p = &t[0];
for(i=0; i<x; i++)
{
if(p[i] == '.')
{
for(; i<x-1; i++)
{
p[i] = p[i+1];
s++;
}
if(s)
p[i] = '0';
break;
}
}
while(p[0] == '0'&&j < x)
{
for(i=0; i<x-1; i++)
p[i] = p[i+1];
p[i] = '0';
s++, j++;
}
if(j == x)
{
printf("结果为:0 \n(你真无聊!)");
exit(0);
}
return s;
}
int main(void)
{
char t[N+1]={0}, a[N+1]={0}, b[N+1]={0};
long int c[2*N+1]={0}, d[2*N+1]={0};
int i, j, k, x1, x2, s1, s2, m;
printf("请输入一个数:\n");
scanf("%s",t);
x1 = strlen(t);
s1 = proces(t, x1);
if(s1) s1++;
for(j=0,i=strlen(t)-1; i>=0; i--)
a[j++] = t[i] - '0';
printf("请输入另一个数:\n");
scanf("%s",t);
x2 = strlen(t);
s2 = proces(t, x2);
if(s2) s2++;
s1 += s2;
// printf("%d\n", s1);
for(j=0,i=strlen(t)-1; i>=0; i--)
b[j++] = t[i] - '0';//开始与之前两个一致
for(i=0; i<x1; i++)
for(j=0; j<x2; j++)
c[i+j] += a[i]*b[j];
for(i=m=0; i<2*N; i++)
{
c[i] += m;
d[i] = c[i] % 10;
m = c[i] / 10;
}
printf("乘法计算结果为:\n");
for(i=2*N; i>=0; i--)
{
if(d[i] != 0)
{
for(; i>=s1; i--)
printf("%d",d[i]);
if(s1) printf(".");
for(; i>=0; i--)
printf("%d",d[i]);
break;
}
else if(i == s1)
{
printf("%d.", d[i]);
for(i--; i>=0; i--)
printf("%d", d[i]);
}
}
return 0;
}
(4) 思路同(3),将小数转换为整数,此时保证两个数扩大倍数相同,记住小数点后移位数(即扩大倍数),商与未处理前相同,只是余数扩大了,将余数处理,缩至原倍数。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define N 1000
int proces(char t[], int x);
void dispos(char a[], char b[], int c);
int max(char a[], char b[]);//max函数帮助判断"数字"a,b的大小
int main(void)
{
char t[N+1] = {0}, a[N+1] = {0}, b[N+1] = {0};
int i, j, k, x1, x2, s1, s2, s, m, n = 0;
printf("请输入一个数:\n");
scanf("%s", t);
x1 = strlen(t);
s1 = proces(t, x1);
if(s1) s1++;
for(j=0,i=x1-1; i>=0; i--)
a[j++] = t[i] - '0';
printf("请输入另一个数:\n");
scanf("%s", t);
x2 = strlen(t);
s2 = proces(t, x2);
if(s2) s2++;
for(j = 0,i = x2-1; i >= 0; i--)
b[j++] = t[i] - '0';//开始与之前两个一致
dispos(a, b, s1-s2);
s = (s1 > s2) ? s1 : s2;
while (m = max(a, b))
{
n ++;
if(m == 1)//a > b时,差 = a - b
{
for(i=0,k=0; i<N; i++)
{
if(a[i]+k>=b[i])
{
a[i] = a[i] - b[i] + k;
k = 0;
}
else
{
a[i] = 10 + a[i] - b[i] + k;
k = -1;
}
}
}
else if(m == 2)
{
printf("商为:%d\n余数为:0\n", n);
break;
}
}
if(m == 0)
{
printf("商为:%d\n余数为:", n);
for(i = N; i >= 0; i --)
{
if(a[i] != 0)
{
if(i < s)
printf("0");
for(; i >= s; i --)
printf("%d",a[i]);
if(s)
printf(".");
for(; i >= 0; i --)
printf("%d",a[i]);
putchar('\n');
}
}
}
return 0;
}
int proces(char t[], int x)
{
char *p;
int i, j = 0, s = 0;
p = &t[0];
for(i=0; i<x; i++)
{
if(p[i] == '.')
{
for(; i<x-1; i++)
{
p[i] = p[i+1];
s++;
}
if(s)
p[i] = '0';
break;
}
}
while(p[0] == '0'&& j < x)
{
for(i=0; i<x-1; i++)
p[i] = p[i+1];
p[i] = '0';
s++, j++;
}
if(j == x)
{
printf("结果为0或者不存在!\n(你真无聊!)");
exit(0);
}
return s;
}
void dispos(char *a, char *b, int c)
{
int i = N;
if(c > 0)//b前插c个0;
{
while(!b[i])
i--;
for(; i >=0; i--)
b[i+c] = b[i];
for(i = 0; i < c; i++)
b[i] = 0;
}
else if(c < 0)//a前插c个0;
{
while(!a[i])
i--;
for(; i >=0; i--)
a[i-c] = a[i];
for(i = 0; i < -c; i++)
a[i] = 0;
}
return;
}
int max(char a[], char b[])
{
int x1, x2, m, i, j;
x1 = x2 = m = 0;
i = j = N;
while (!a[i]) i --;
x1 = i;
while (!b[j]) j --;
x2 = j;
if(x1 > x2) m = 1;
else if (x1 == x2)
{
for(i = x1; i >= 0; i --)
{
if(a[i] > b[i])
{
m = 1;
break;
}
else if(a[i] < b[i])
break;
}
if(i == -1)
m = 2;
}
return m;
}
运行结果 :