C语言高精度大数除法的算法实现(附有实战案例)

一、引言

在C语言解决问题的过程中,我们常常会遇到一些问题需要进行大数处理。

这里定义的大数为位数达到几百位的整数。

通常做法是将大数转化为一维数组,再进行四则运算。

在四则运算中,除法的高效率实现最为困难。

本文即是针对这种高精度大数除法问题给出模板化的解答。

二、算法实现

(1)数据读入

首先,我们的思路是将大数转化为一维数组存储起来。但是,直接读入数组的话会产生一个问题。比如我们定义一个数组arr[1000],直接读入的话,大数的最高位会储存在下标为零的数组空间内,也就是arr[0]。这不符合我们对数字的自然逻辑,也会对之后的处理带来困难。所以在以下所涉及到的数字中,包括被除数、除数、商、余数这四个数,我们都采用反向读入的方式,也就是将个位储存在arr[0]中,将十位储存在arr[1]中,依次类推。

先定义数组

char beiChuShuStr[1004] = { 0 };
char chuShuStr[1004] = { 0 };
int beiChuShu[1004] = { 0 };
int chuShu[1004] = { 0 };
int shang[1004] = { 0 };
int yuShu[1004] = { 0 };

这里为什么多定义了两个字符串数组呢?

因为我们的处理思路是先将大数以字符串的形式读入,再进行反向赋值给数字数组

具体实现如下:

scanf("%s", beiChuShuStr);
scanf("%s", chuShuStr);
int len1 = strlen(beiChuShuStr);
int len2 = strlen(chuShuStr);
for (int i = 0; i < len1; i++) {//将字符串数组输入整形数组,调整顺序使得下标为零的元素
	beiChuShu[i] = beiChuShuStr[len1 - 1 - i] - '0';//对应个位,下标为一的元素对应十位
}
for (int i = 0; i < len2; i++) {
	chuShu[i] = chuShuStr[len2 - 1 - i] - '0';
}

如此以来我们的大数就成功储存了

同学们可以学习一下字符转化为数字的方法,只要减去‘0’就可以了。

完成了数据的读入,现在来确定算法的具体实现方式。

一种很简单的想法是,除法本身是许多个减法的叠加,那你只要令被除数不断减去除数,直到不能减不就好了吗?然而,这种思路的效率很低,因为如果被除数的位数是几百位,除数的位数是几十位,相除之后的商大概率也是几百位。相当于电脑要进行10的几百次方的运算,效率是很低下的。

让我们回归淳朴,来看看最开始手算除法是用什么方式呢?

答案是竖式除法。

(2)判断是否被除数的前lb位是否可以与除数相减

    竖式除法很重要的一步是,判断当前被除数的前lb位能否与除数相减,其中lb是除数的长度。对吧,尤其是对于几百位的大数而言,这个判断要进行几百次,所以,我们封装一个函数用来执行这个判断。

bool ability_to_subtraction(int a[], int b[], int last_weishu, int lb) {
	if (a[last_weishu + lb] != 0)return true;
	for (int i = lb; i > 0; i--) {
		if (a[last_weishu + i - 1] > b[i - 1])return true;
		if (a[last_weishu + i - 1] < b[i - 1])return false;
	}
	return true;
}

博主英语不好,只能想到这么一个函数名。意思是减法的能力。

传入的last_weishu这样一个参数,大小为la-lb,用来描述被除数的前lb位中,最小一位的位置。

这个语句意思是,如果取到的被除数长度比除数大,那么一定可以相减;

if (a[last_weishu + lb] != 0)return true;

这个语句的意思是从最大位开始判断,遇到被除数的该位数字大于除数的情况就可以相减,被除数的该位数字小于除数的就不可相减;

	for (int i = lb; i > 0; i--) {
		if (a[last_weishu + i - 1] > b[i - 1])return true;
		if (a[last_weishu + i - 1] < b[i - 1])return false;
	}

最后一个语句return true意思是,如果被除数取出的每一位都和除数对应的那个位子上的数字相等,也可以相减,结果为零嘛。

(3)将处理后的新的被除数重复相减操作

for (int i = 0; i < la; i++) {//保护被除数不改变,通过对余数进行改变最后得出结果
	yuShu[i] = beiChuShu[i];
}
for (int i = la - lb; i >= 0; i--) {
	while (ability_to_subtraction(yuShu, chuShu, i, lb)) {
		for (int j = 0; j < lb; j++) {
			yuShu[i + j] -= chuShu[j];
			if (yuShu[i + j] < 0) {
				yuShu[i + j] += 10;
				yuShu[i + j + 1] -= 1;
			}
		}
		shang[i]++;
	}
}

最后输出结果

	for (lc = 1004; lc >= 0; lc--)
		if (yuShu[lc - 1] != 0)break;
	for (ld = 1004; ld >= 0; ld--)
		if (shang[ld - 1] != 0)break;
	for (int i = 0; i < lc; i++) {
		printf("%d", yuShu[i]);
	}
	printf("\n");
	for (int i = 0; i < ld; i++) {
		printf("%d", shang[i]);
	}

三、实战案例

光棍数

这里所谓的“光棍”,并不是指单身汪啦~ 说的是全部由1组成的数字,比如1、11、111、1111等。传说任何一个光棍都能被一个不以5结尾的奇数整除。比如,111111就可以被13整除。 现在,你的程序要读入一个整数x,这个整数一定是奇数并且不以5结尾。然后,经过计算,输出两个数字:第一个数字s,表示x乘以s是一个光棍,第二个数字n是这个光棍的位数。这样的解当然不是唯一的,题目要求你输出最小的解。

提示:一个显然的办法是逐渐增加光棍的位数,直到可以整除x为止。但难点在于,s可能是个非常大的数 —— 比如,程序输入31,那么就输出3584229390681和15,因为31乘以3584229390681的结果是111111111111111,一共15个1。

输入格式:

输入在一行中给出一个不以5结尾的正奇数x(<1000)。

输出格式:

在一行中输出相应的最小的sn,其间以1个空格分隔。

输入样例:

31

输出样例:

3584229390681 15

这道题目因为明显涉及到大数,所以我们可以直接借鉴高精度大数除法。

同学们可以自己尝试一下,附有参考代码。

#include<stdio.h>
#include<string.h>
int ability_to_subtraction(int a[], int b[], int last_weishu, int lb) {
	if (a[last_weishu + lb] != 0)return 1;
	for (int i = lb; i > 0; i--) {
		if (a[last_weishu + i - 1] > b[i - 1])return 1;
		if (a[last_weishu + i - 1] < b[i - 1])return 0;
	}
	return 1;
}
int main() {
	char N[4] = { 0 };
	int n;
	int flag = 0;
	int yuShu[1002] = { 0 };
	int chuShu[4] = { 0 };
	int shang[1002] = { 0 };
	scanf("%s", &N);
	int lb = strlen(N);
	int ld;
	for (int i = 0; i < lb; i++) {
		chuShu[i] = N[lb - 1 - i] - '0';
	}
	//for (lb = 3; lb >= 0; lb--)
	//	if (chuShu[lb-1] != 0)break;
	for (n = 1; n < 1000 && !flag; n++) {
		flag = 1;
		memset(yuShu, 0, sizeof(yuShu));
		memset(shang, 0, sizeof(shang));
		for (int i = 0; i < n; i++) {//生成光棍数
			yuShu[i] = 1;
		}
		for (int i = n - lb; i >= 0; i--) {
			while (ability_to_subtraction(yuShu, chuShu, i, lb)) {
				for (int j = 0; j < lb; j++) {
					yuShu[i + j] -= chuShu[j];
					if (yuShu[i + j] < 0) {
						yuShu[i + j] += 10;
						yuShu[i + j + 1] -= 1;
					}
				}
				shang[i]++;
			}
		}
		for (int i = 0; i < 4; i++) {
			if (yuShu[i] != 0)flag = 0;
		}
	}
	if (flag) {
		for (ld = 1002; ld >= 0; ld--)
			if (shang[ld - 1] != 0)break;
		for (int i = ld - 1; i >= 0; i--) {
			printf("%d", shang[i]);
		}
		printf(" %d", n-1);
	}
	return 0;
}

  • 12
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
C语言实现高精度除法高精度除以高精度)可以通过字符串和数组来实现。下面是一个示例代码: ```c #include <stdio.h> #include <string.h> #define MAX_LEN 1000 void divide(char dividend[], char divisor[], char quotient[]) { int len1 = strlen(dividend); int len2 = strlen(divisor); int i, j, k; // 将被除数和除数转换为整型数组 int num1[MAX_LEN], num2[MAX_LEN]; for (i = 0; i < len1; i++) { num1[i] = dividend[i] - '0'; } for (i = 0; i < len2; i++) { num2[i] = divisor[i] - '0'; } // 初始化商和余数 int result[MAX_LEN], remainder[MAX_LEN]; memset(result, 0, sizeof(result)); memset(remainder, 0, sizeof(remainder)); // 从高位到低位进行除法运算 for (i = 0; i < len1; i++) { // 将余数左移一位,加上当前位的数字 for (j = len2 - 1; j >= 0; j--) { remainder[j + 1] = remainder[j]; } remainder[0] = num1[i]; // 计算当前位的商 for (j = 0; j < 10; j++) { if (compare(remainder, num2, len2) >= 0) { subtract(remainder, num2, len2); result[i]++; } else { break; } } } // 将商转换为字符串 int len = 0; for (i = 0; i < len1; i++) { if (result[i] != 0) { break; } } for (; i < len1; i++) { quotient[len++] = result[i] + '0'; } quotient[len] = '\0'; } int compare(int num1[], int num2[], int len) { for (int i = 0; i < len; i++) { if (num1[i] > num2[i]) { return 1; } else if (num1[i] < num2[i]) { return -1; } } return 0; } void subtract(int num1[], int num2[], int len) { for (int i = len - 1; i >= 0; i--) { if (num1[i] < num2[i]) { num1[i] += 10; num1[i - 1]--; } num1[i] -= num2[i]; } } int main() { char dividend[MAX_LEN], divisor[MAX_LEN], quotient[MAX_LEN]; printf("请输入被除数:"); scanf("%s", dividend); printf("请输入除数:"); scanf("%s", divisor); divide(dividend, divisor, quotient); printf("商为:%s\n", quotient); return 0; } ``` 这段代码实现高精度除法,通过将被除数和除数转换为整型数组,然后从高位到低位进行除法运算,最后将商转换为字符串输出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞猪0_0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值