C语言——高精度除法

一、引子

1、引言

高精度除法相较于加减乘法更加复杂,它需要处理的因素更多,在这里我们先探讨高精度数除以低精度数,即大数除小数。这已满足日常所需,如需大数除以大数,可以使用专门的库,例如:

GNU Multiple Precision Arithmetic Library (GMP)

  • 这是最知名的任意精度数学库,提供了丰富的功能来处理整数、有理数和浮点数的高精度运算。

MPIR

  • 一个与GMP兼容的库,它被设计为GMP的直接替代品,在某些系统上可能提供更好的性能。

The GNU MPFR Library

  • 基于GMP构建,提供了严格圆整的多精度浮点运算能力。

使用这些库中的任何一个都需要你下载和链接到你的C程序中。这些库的文档通常会指导你如何将它们集成到你的项目中。集成后,你可以使用库提供的函数来执行高精度的整数和小数运算。

2、介绍

这里我们要实现大数除以小数,实际原理其实是模拟我们手算除法:

与高精度加减乘法不同的是,高精度除法是从高位开始运算,一步一步运算到最低位的,所以不用将被除数字符串反转。

二、核心算法

核心算法是由刚才的手算除法得来的,如下:

#define MAX 505
#define DECIMAL_PART 50//小数部分保留五十位
int i = 0;
int remainder = 0;
int high[MAX] = { 0 };
for (i = 0; i < high_len; i++)//高精度除法核心算法,模拟我们手算除法,从最高位开始除
{long long division = remainder * 10LL + high[i];//余数乘十,加上整数部分i位的数字作为被除数IntegerResult[i] = (int)division / low;//结果是被除数除以除数,这里是有余数的整数除法remainder = (int)division % low;//取余,下一步乘十后作为下一位的除数
}for (i = 0; i < DECIMAL_PART + 1; i++)//小数部分计算,多计算一位,以便后面进行四舍五入
{remainder *= 10;//余数乘十作为被除数DecimalResult[i] = remainder / low;//计算小数部分i位的结果remainder %= low;//取余,下一步乘十后作为下一位的除数
}

核心算法分为两部分,一部分是求商的整数部分,一部分是求商的小数部分。

(1)商的整数部分代码是手动实现的长除法过程,模仿我们在纸上做除法时的步骤。这里使用数组high[]来表示高精度的被除数,low是低精度的除数,IntegerResult[]用来存储商的整数部分。

让我们逐步分析这段代码的工作原理:

  1. for循环:循环遍历高精度数high[]的每一位,从数字最高位开始进行运算。

  2. long long division = remainder * 10LL + high[i];

    • remainder是前一次除法后剩下的余数,初始化为0,因为我们从最高位开始除,最开始没有余数。
    • remainder * 10LL将余数乘以10,因为在长除法中,每向下一位,都相当于余数乘以10再加上新的一位。这里的10LL是一个long long类型的常量,确保运算结果能够存储在long long类型变量中,以避免溢出。
    • + high[i]是将当前处理的这一位数加到余数乘以10之后的值上,形成新的被除数。
  3. IntegerResult[i] = division / low;

    • 这行代码执行实际的除法运算。division是新的被除数,low是除数,计算出的商被存储在结果数组IntegerResult[i]的当前位置。
  4. remainder = division % low;

    • 这里计算新的余数,为下一位计算做准备。division % low计算了division除以low之后的余数。

循环中的每次迭代都处理高精度数的一位,并将其与前一位剩下的余数结合起来,进行除法运算。最终,这个for循环会填满整个IntegerResult[]数组,数组中的每个元素都是对应位上的商。

这个过程一直继续,直到所有的高精度数位都被处理完毕。我们通过不断将余数乘以10并加上下一位来逐位处理整个高精度数,这与手工执行长除法的过程相同。最后得到的IntegerResult[]数组就是除法操作的结果,而循环结束后剩下的remainder就是最终的余数。

(2)商的小数部分代码依旧是手动实现的长除法过程,模仿我们在纸上做除法时的步骤。这里使用remainder来除以lowDecimalResult[]用来存储商的小数部分。

接着我们逐步分析这段代码的工作原理:

  1. for循环:保留50位小数,多计算一位,为了后面的四舍五入,从数字最高位开始进行运算。

  2. remainder *= 10;

    • remainder整数商计算好后的余数,乘十后作为被除数,因为原被除数小数部分为0,所以相对于商的整数部分不用加其他的。
  3. DecimalResult[i] = remainder / low;

    • 这行代码执行实际的除法运算。remainder是新的被除数,low是除数,计算出的商被存储在结果数组DecimalResult[i]的当前位置。
  4. remainder %= low;

    • 这里计算新的余数,为下一位计算做准备。remainder %= low;计算了remainder除以low之后的余数。

最后商的小数部分也就求出了。

三、代码实现

#include <stdio.h>
#include <string.h>
#include <stdlib.h>#define MAX 505
#define DECIMAL_PART 50//小数部分保留五十位void StringTranstoDigit(char numch[], int num[],int length)//字符数组转成整型数组
{int i = 0;for (i = 0; i < length; i++){num[i] = numch[i] - '0';}
}void highDivLow(char highch[], int high_len, int low, int IntegerResult[],int DecimalResult[])//高精度除法
{if (low == 0)//除数为零的情况{fprintf(stderr,"divisor can not be zero!\n");//输出错误信息exit(EXIT_FAILURE);//退出程序,运行过程中失败}int i = 0;int remainder = 0;int high[MAX] = { 0 };StringTranstoDigit(highch,high,high_len);//字符转整型for (i = 0; i < high_len; i++)//高精度除法核心算法,模拟我们手算除法,从最高位开始除{long long division = remainder * 10LL + high[i];//余数乘十,加上整数部分i位的数字作为被除数IntegerResult[i] = (int)division / low;//结果是被除数除以除数,这里是有余数的整数除法remainder = (int)division % low;//取余,下一步乘十后作为下一位的除数}for (i = 0; i < DECIMAL_PART + 1; i++)//小数部分计算,多计算一位,以便后面进行四舍五入{remainder *= 10;//余数乘十作为被除数DecimalResult[i] = remainder / low;//计算小数部分i位的结果remainder %= low;//取余,下一步乘十后作为下一位的除数}if (DecimalResult[DECIMAL_PART] >= 5)//四舍五入{DecimalResult[DECIMAL_PART - 1]++;}for (i = DECIMAL_PART; i > 0; i--)//处理四舍五入后的进位,小数部分进位{int carry = 0;carry = DecimalResult[i] / 10;DecimalResult[i] %= 10;DecimalResult[i - 1] += carry;}if (DecimalResult[0] >= 10)//小数进整数位{IntegerResult[high_len - 1] = DecimalResult[0] / 10;DecimalResult[0] %= DecimalResult[0];}
}void Print(int num[],int numdec[],int length)//打印整数和小数部分
{int i = 0;while (i < length - 1 && num[i] == 0)//去除前导零{i++;}for (; i < length ; i++)//打印整数部分{printf("%d",num[i]);}printf(".");//小数点for (i = 0; i < DECIMAL_PART; i++)//打印小数部分{printf("%d",numdec[i]);}
}int main()
{char high[MAX] = { 0 };//高精度数,被除数scanf("%s",high);int low = 0;//低精度数,除数scanf("%d",&low);int IntegerResult[MAX] = { 0 };//结果整数部分int DecimalResult[DECIMAL_PART + 1] = { 0 };//结果小数部分int high_len = (int)strlen(high);//被除数长度highDivLow(high, high_len, low, IntegerResult,DecimalResult);//高精度除法Print(IntegerResult,DecimalResult,high_len);//打印return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/293813.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

大创项目推荐 深度学习+opencv+python实现车道线检测 - 自动驾驶

文章目录 0 前言1 课题背景2 实现效果3 卷积神经网络3.1卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV56 数据集处理7 模型训练8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &am…

基于AE、VAE 和 VQ-VAE的图像生成

AE 是将数据映直接映射为数值code&#xff08;确定的数值&#xff09;&#xff0c;主要用于图像压缩与还原VAE是先将数据映射为分布&#xff0c;再从分布中采样得到数值code&#xff0c;主要用于图像生成。AQ-VAE是在原始VAE基础上多了一步Vector Quantization矢量量化操作&…

放心安全国产主食冻干猫粮有哪些牌子?分享十大放心猫粮国产名单

近几年&#xff0c;冻干猫粮在宠物圈内非常流行&#xff0c;许多品牌都推出了冻干猫粮。在所有的猫食品中&#xff0c;冻干无疑是最具营养、动物蛋白含量最高的食品之一。冻干作为现在宠物圈最火的猫食品&#xff0c;受到了众多猫友们的喜爱和追捧。但有些铲屎官在选择冻干猫粮…

仿悬赏猫任务平台源码 悬赏任务系统源码 带支付接口

源码介绍 最新仿悬赏猫任务平台源码 悬赏任务系统源码 带支付接口&#xff0c; 全新开发悬赏任务系统&#xff0c;功能齐全&#xff0c;包含接任务&#xff0c;发布任务&#xff0c; 店铺关注&#xff0c;置顶推荐&#xff0c;排行榜&#xff0c;红包大厅&#xff0c;红包抽奖…

一些问题/技巧的集合(仅个人使用)

目录 第一章、1.1&#xff09;前端找不到图片1.2&#xff09;1.3&#xff09;1.4&#xff09; 第二章、2.1&#xff09;2.2&#xff09;2.3&#xff09; 第三章、3.1&#xff09;3.2&#xff09;3.3&#xff09; 第四章、4.1&#xff09;4.2&#xff09;4.3&#xff09; 友情提…

MT6739/MTK6739安卓核心板规格参数_MTK平台核心板定制

安卓核心板采用联发科 MT6739 平台开发设计&#xff0c;搭载开放的智能 Android 操作系统。它集成 GPU PowerVR GE8100 570MHz&#xff0c;集成了 BASEBAND、UMCP、PMU 等核心器件&#xff0c;支持 2.4G5G 双频 WIFI(可支持 1*1 MIMO)、BLUETOOTH 近距离无线传输技术&#xff0…

12 数列的新顺序

分组后反转 #include <iostream> using namespace::std; using std::cout; using std::cin; int main() {int l,n;cin >> l;int nums[l];for(int i0; i<l; i){cin >> nums[i];}cin >> n;int t;for(int i0; i<l/n; i){for(int j0; j<n/2; j)…

蓝牙物联网与嵌入式开发如何结合?

蓝牙物联网与嵌入式开发可以紧密结合&#xff0c;以实现更高效、更智能的物联网应用。以下是一些结合的方式&#xff1a; 嵌入式开发为蓝牙设备提供硬件基础设施和控制逻辑&#xff1a;嵌入式系统可以利用微处理器和各种外设组成的系统&#xff0c;为蓝牙设备提供硬件基础设施和…

web网页端使用webSocket实现语音通话功能(SpringBoot+VUE)

写在前面 最近在写一个web项目&#xff0c;需要实现web客户端之间的语音通话&#xff0c;期望能够借助webSocket全双工通信的方式来实现&#xff0c;但是网上没有发现可以正确使用的代码。网上能找到的一个代码使用之后只能听到“嘀嘀嘀”的杂音 解决方案&#xff1a;使用Jso…

JMeter常见错误分析

&#x1f4e2;专注于分享软件测试干货内容&#xff0c;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01;&#x1f4e2;交流讨论&#xff1a;欢迎加入我们一起学习&#xff01;&#x1f4e2;资源分享&#xff1a;耗时200小时精选的「软件测试」资…

LTspice 电路仿真软件教程--基础篇

本文要干什么 介绍LTspice电路仿真软件的基础使用教程。 主角是谁&#xff0c;他有啥牛掰的地方 LTspice是一款高性能Spice III仿真软件、原理图采集和波形查看器&#xff0c;集成增强功能和模型&#xff0c;简化了开关稳压器的仿真。与常规Spice仿真器相比&#xff0c;我们…

计算机存储术语: 扇区,磁盘块,页

扇区(sector) 硬盘的读写以扇区为基本单位。磁盘上的每个磁道被等分为若干个弧段&#xff0c;这些弧段称之为扇区。硬盘的物理读写以扇区为基本单位。通常情况下每个扇区的大小是 512 字节。linux 下可以使用 fdisk -l 了解扇区大小&#xff1a; $ sudo /sbin/fdisk -l Disk …