【基础】(C语言)高精度算法


前言:为什么我们需要高精度算法?

多数时候我们需要进行非常庞大的数字运算,其中涉及四则运算,加减乘除,但是当连最大的long long类型也容纳不下如此大的数字的时候,我们应该怎么办?
那么,我们就要用到今天所介绍的高精度算法,顾名思义,我们可以用一些特殊的方式来得出我们想要计算的答案。

一、高精度算法基础

在讲高精度算法之前,我们需要引入数组和字符串这两位我们在学习过程中的老朋友。
第一:我们知道,数组的优点是可以储存大量数字,并且每一位都是数的形式,运算时非常方便,但是数组在输入的时候必须要有分隔符,不符合数字的输入习惯。
第二:我们知道,字符串在输入的时候是连续的,不需要分隔符,非常符合数字的输入习惯,但是不能直接进行运算,非常不方便。
所以,我们可以就其两者取长补短,用数组来进行运算和储存数据,用字符串来输入数据!

二、高精度乘法

1.计算流程

  1. 通过字符串引入两串数字分别存放到两个字符数组
  2. 将其每一位数字逆序分别存放到两个整型数组
  3. 进行计算并处理进位(关键)
  4. 将结果存放到第三个整型数组当中(引进动态数组)
  5. 输出结果

第一:我们引进两串数字

char num1[102];
char num2[102];
scanf("%s", num1);
scanf("%s", num2);

第二:将每一位数字逆序存放整型数组

	int la,lb,lc;
    int a[2001]={0};
    int b[2001]={0};
    int c[2001]={0};//这是待会儿要存答案的数组
    la=strlen(num1);//取第一个字符串的长度
    lb=strlen(num2);//取第二个字符串的长度
    for(int i=0;i<la;i++)
    {//这里我们用la-i-1来实现逆序存放,将num数组的逆序存放在数组a中:即数字的个位存放在a【0】以此类推
        a[la-i-1]=num1[i]-'0';//通过ASCII码的运算,将字符数字转成整型数字
    }
    for(int i=0;i<lb;i++)
    {
        b[lb-i-1]=num2[i]-'0';
    }
    lc=la+lb;//记录两个字符串的总长度

第三:进行计算并处理进位

for(int i=0;i<la;i++)
    {
        for(int j=0;j<lb;j++)
        {
            c[i+j]+=a[i]*b[j];
            c[i+j+1]+=c[i+j]/10;
            c[i+j]%=10;
        }
    }

想必大家不知道这算法公式是怎样推导出来的吧,那就让我针对推导过程进行讲解吧!
在这里插入图片描述
在这里插入图片描述
第四:将结果存放到第三个整型数组当中(引进动态数组)

while(c[lc]==0&&lc>0)lc--;
    char *re=(char *)malloc(sizeof(char)*(lc+2));
    for(int i=lc;i>=0;i--){
        re[lc-i]=c[i]+'0';
    }
    re[lc+1]=0;

4.1
没错,这里又出现了一个特别的while语句
while(c[lc]==0&&lc>0)lc–
它的作用是:比较大众的说法是删去前导零,不过这里有个小插曲,就是笔者在阅读其他作者的文章的时候并不能理解前导零是怎么产生的(没错就是这么傻 ),所以在这里我有另一种较为容易理解的说法。
还记得我们前面定义了两个字符串的长度和lc吗?
想想我们有两种情况:
1.在最高位有进位,那么这是存答案的数组就会往前再储存一位数字,存在c【lc】中(想想为什么)
2.在最高位没有进位,那么我们在初始化的时候就已经把c【lc】置为0了,那么我们就要将总长度lc(总位数)减掉,避免输出的时候在答案前面多了个0
4.2
这里我们引入动态数组的原因是笔者是用函数写的这部分运算,因此在函数结束时,函数会销毁,导致我们不能正常输出结果,因此需要另外开一个动态数组来存放我们的结果。
4.3:
有没有注意到 re[lc+1]=0,它可是至关重要的一步
笔者因为漏了它导致作业一直没能满分,因为内存的问题QAQ
它能够让我们在输出结果的时候及时地终止程序的读取,为什么呢?因为字符串在输出的时候只有读取到’\0’的时候才会终止,那么我们加上这句之后就是要让它在答案结尾处就终止输出,能避免不断输出而引起的内存出错哦!

第五:输出
没啥好讲的其实hhhhh

2.完整代码

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* multiply(char* num1, char* num2)
{
    int la,lb,lc;
    int a[2001]={0};
    int b[2001]={0};
    int c[2001]={0};
    la=strlen(num1);
    lb=strlen(num2);
    for(int i=0;i<la;i++)
    {
        a[la-i-1]=num1[i]-'0';
    }
    for(int i=0;i<lb;i++)
    {
        b[lb-i-1]=num2[i]-'0';
    }
    lc=la+lb;
    for(int i=0;i<la;i++)
    {
        for(int j=0;j<lb;j++)
        {
            c[i+j]+=a[i]*b[j];
            c[i+j+1]+=c[i+j]/10;
            c[i+j]%=10;
        }
    }
    while(c[lc]==0&&lc>0)lc--;
    char *re=(char *)malloc(sizeof(char)*(lc+2));
    for(int i=lc;i>=0;i--){
        re[lc-i]=c[i]+'0';
    }
    re[lc+1]=0;
    return re;
}
int main(){
	char num1[102];
    char num2[102];
    scanf("%s", num1);
    scanf("%s", num2);
    char* num = multiply(num1, num2);
    printf("%s", num);
    free(num);
	return 0;
}

三、总结

希望这篇文章能够帮助到所有正在学习程序设计的朋友们,如果对这篇文章有任何问题的欢迎在评论区留言,笔者会一一回复的,也恳请大家多多提出建议,让我们的博客越来越好。
如果觉得这篇文章不错的话,不要忘记点个赞哦!

<think>好的,用户想了解C语言中实现高精度算法的方法和示例。我需要先回忆高精度算法的基本概念,通常用于处理大整数运算,超出普通数据类型范围的情况。常见的方法是用数组或字符串存储每一位数字,然后模拟手工计算的过程。 首先,确定用户的需求。用户可能在进行大数运算时遇到问题,比如加减乘除,需要处理非常大的整数或者高精度小数。C语言的标准数据类型无法直接处理,所以需要自己实现。 接下来,我需要考虑不同的高精度操作,比如加法、减法、乘法和除法。每种操作有不同的实现方法。例如,加法需要处理进位,乘法需要考虑逐位相乘后的累加,而除法则更为复杂,可能涉及试商法。 然后,参考用户提供的引用。引用中没有直接提到高精度算法,但引用[1]提到了CORDIC算法和泰勒展开,这可能与数值计算有关,但可能不直接相关。引用[2]提到了优化计算,比如存储重复使用的计算结果,这可能在高精度算法中用于优化性能。引用[3]用户提到自己算法基础较弱,可能需要更基础的示例和详细解释。 因此,我需要用简单易懂的方式解释高精度算法的实现,并提供具体的示例代码,比如大整数加法和乘法。代码需要详细注释,帮助用户理解每一步的作用。 还需要考虑数据的存储方式。通常,使用数组来存储每一位数字,低位在前或高位在前。例如,数12345可以存储为数组[5,4,3,2,1],这样进位处理更方便。 在加法示例中,需要遍历每一位,处理进位。乘法则需要双重循环,处理每一位相乘后的累加和进位,同时注意结果的位数可能达到两倍长度。 可能的问题点:用户可能不清楚如何管理进位,或者如何处理不同长度的数字。需要确保示例代码能处理这些情况,并解释清楚。 最后,生成相关问题,帮助用户进一步学习,例如如何处理减法、除法,或者如何优化性能,如引用[2]提到的存储中间结果来减少计算量。 总结:提供高精度算法的基本实现方法,用数组存储数字,模拟手工计算,给出加法和乘法的示例代码,并附上详细解释。同时,生成相关问题引导深入学习。</think>### C语言实现高精度算法的方法 在C语言中实现高精度算法,核心思路是通过**数组或字符串存储大数的每一位**,并模拟手工计算的过程。以下是具体实现方法和示例: --- #### 1. 数据存储与初始化 将大数按字符形式存储,或按整型数组存储(每个元素表示一位数字)。例如,数字$123456789$可以表示为: ```c int num[] = {9, 8, 7, 6, 5, 4, 3, 2, 1}; // 低位在前,方便进位处理 int length = 9; ``` --- #### 2. 高精度加法示例 **实现思路**:逐位相加,处理进位。 ```c #include <stdio.h> #include <string.h> void reverse(char *arr) { int len = strlen(arr); for (int i = 0; i < len/2; i++) { char temp = arr[i]; arr[i] = arr[len-1-i]; arr[len-1-i] = temp; } } void add(char *a, char *b, char *result) { reverse(a); // 反转字符串,低位对齐 reverse(b); int carry = 0, sum, i; for (i = 0; a[i] || b[i] || carry; i++) { int digit_a = (a[i] != '\0') ? a[i] - '0' : 0; int digit_b = (b[i] != '\0') ? b[i] - '0' : 0; sum = digit_a + digit_b + carry; carry = sum / 10; result[i] = sum % 10 + '0'; } result[i] = '\0'; reverse(result); // 反转回高位在前 } int main() { char a[1000] = "123456789"; char b[1000] = "987654321"; char result[1001]; add(a, b, result); printf("Sum: %s\n", result); // 输出:1111111110 return 0; } ``` --- #### 3. 高精度乘法示例 **实现思路**:双重循环逐位相乘,累加中间结果并处理进位。 ```c void multiply(char *a, char *b, char *result) { int len_a = strlen(a), len_b = strlen(b); int temp[len_a + len_b]; memset(temp, 0, sizeof(temp)); reverse(a); reverse(b); for (int i = 0; i < len_a; i++) { for (int j = 0; j < len_b; j++) { temp[i+j] += (a[i] - '0') * (b[j] - '0'); temp[i+j+1] += temp[i+j] / 10; temp[i+j] %= 10; } } int k = len_a + len_b - 1; while (k > 0 && temp[k] == 0) k--; // 去除前导零 for (int i = 0; i <= k; i++) result[i] = temp[k-i] + '0'; // 反转存储结果 result[k+1] = '\0'; } int main() { char a[100] = "123"; char b[100] = "456"; char result[200]; multiply(a, b, result); printf("Product: %s\n", result); // 输出:56088 return 0; } ``` --- #### 4. 优化与注意事项 - **存储优化**:使用动态数组或结构体封装大数,提升灵活性[^2]。 - **性能提升**:预处理重复计算值(如乘法的中间结果缓存)[^2]。 - **边界处理**:注意去除前导零,处理负数情况。 ---
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值