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.mzph.cn/news/241278.shtml

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

相关文章

Angular 11到升级到 Angular 16

日新月异&#xff0c;与时俱进… 随着Angular版本不断更新&#xff0c;再看所开发的项目版本仍然是Angular 11&#xff0c;于是准备升级 截止发博日最版本是 v17.1.0&#xff0c;考虑到稳定性因素决定升级到v16版本 一&#xff1a;查看 升级指南 二&#xff1a;按照指南&…

推荐算法架构7:特征工程(吊打面试官,史上最全!)

系列文章&#xff0c;请多关注 推荐算法架构1&#xff1a;召回 推荐算法架构2&#xff1a;粗排 推荐算法架构3&#xff1a;精排 推荐算法架构4&#xff1a;重排 推荐算法架构5&#xff1a;全链路专项优化 推荐算法架构6&#xff1a;数据样本 推荐算法架构7&#xff1a;特…

数据校园服务管理系统,教育平台可视化界面(教育资源信息化PS文件)

大屏组件可以让UI设计师的工作更加便捷&#xff0c;使其更高效快速的完成设计任务。现分享大数据校园服务管理系统、科技教育平台大数据可视化界面、教育资源信息化大数据分析等Photoshop源文件&#xff0c;文末提供完整资料&#xff0c;供UI设计师们工作使用。 若需其他 大屏…

Linux一行命令配置jdk环境

使用方法&#xff1a; 压缩包上传 到/opt, 更换命令中对应的jdk包名即可。 注意点&#xff1a;jdk-8u151-linux-x64.tar.gz 解压后名字是jdk1.8.0_151 sudo tar -zxvf jdk-8u151-linux-x64.tar.gz -C /opt && echo export JAVA_HOME/opt/jdk1.8.0_151 | sudo tee -a …

unity中使用protobuf工具将proto文件转为C#实体脚本

unity中使用protobuf工具将proto文件转为C#实体脚本 介绍优点缺点Protobuf 为什么比 XML 快得多&#xff1f;Protobuf的EncodingProtobuf封解包的过程通常编写一个Google Protocol Buffer应用需要以下几步&#xff1a; Protostuff是什么Protobuf工具总结 介绍 protobuf也就是G…

Java面向对象(初级)

面向对象编程(基础) 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它强调程序设计是围绕对象、类和方法构建的。在面向对象编程中&#xff0c;程序被组织为一组对象&#xff0c;这些对象可以互相传递消息。面向对象编程的核心概念包括封装、继承和多态。…

Vue3选项式API和组合式API详解

前言 相信学习Vue3的人中大多数都是之前使用Vue2开发的&#xff0c;当拿到一个Vue3项目时就接触到了组合式api&#xff0c;但对于组合式api不了解的人第一眼看上去会觉得一头雾水。&#xff1a;“什么玩意&#xff0c;乱七八糟的&#xff0c;选项式api多好&#xff0c;方法变量…

Linux bridge开启hairpin模拟测试macvlan vepa模式

看到网上介绍可以通过Linux bridge 开启hairpin方式测试macvlan vepa模式&#xff0c;但是没有找到详细资料。我尝试测试总提示错误信息&#xff0c;无法实现&#xff0c;经过几天的研究&#xff0c;我总算实现模拟测试&#xff0c;记录如下&#xff1a; 参考 1.Linux Macvla…

「Vue3面试系列」Vue3.0性能提升主要是通过哪几方面体现的?

文章目录 一、编译阶段diff算法优化静态提升事件监听缓存SSR优化 二、源码体积三、响应式系统参考文献 一、编译阶段 回顾Vue2&#xff0c;我们知道每个组件实例都对应一个 watcher 实例&#xff0c;它会在组件渲染的过程中把用到的数据property记录为依赖&#xff0c;当依赖发…

MicroPython的交互式解释器模式 REPL

MicroPython的交互式解释器模式又名REPL&#xff08;read-eval-print-loop&#xff09;&#xff0c;就是一种命令输入交互模式&#xff0c;跟Python的REPL是类似的&#xff0c;就是在命令行直接输入Python代码或表达式执行并打印结果。关于MicroPython的REPL跟通常的Python类似…

linux运维面试题

linux运维面试题 面试 K8S篇(高可用) Q&#xff1a;k8s是什么&#xff1f;架构&#xff1f; Kubenetes是一个开源的容器集群管理系统。主要用于容器编排&#xff0c;解决容器调度问题。当应用请求时&#xff0c;k8s需要合理分配请求到空闲node节点上去。k8s使用的主从模式&…

python通过JS逆向采集艺恩电影数据, 并制作可视化

嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! 如果有什么疑惑/资料需要的可以点击文章末尾名片领取源码 环境使用: 版 本&#xff1a; python 3.10 编辑器&#xff1a;pycharm 2022.3.2 nodejs 模块使用: requests -> pip install requests execjs -> pip install…

【Git】在 IDEA 中合并多个 commit 为一个

文章目录 1 未提交到远程分支1.1 需求说明1.2 reset 操作1.3 再次 push 2 已经提交到远程分支2.1 需求说明2.2 rebase 操作2.3 强制 push 分两种情况&#xff1a; 一种是本地提交还没推到远程&#xff0c;这种好处理另一种是已经提交到远程分支&#xff0c;这个略麻烦 1 未提…

【接口测试】Postman(三)-变量与集合

一、变量 ​ 变量这个概念相信大家都不陌生&#xff0c;因此在这里我们不介绍了。主要说一下在Postman中有哪几类变量&#xff0c;主要包括以下四类&#xff1a; Global&#xff08;全局&#xff09; Environment&#xff08;环境&#xff09; Local&#xff08;本地&#xf…

Linux中安装Maven3.6.1

一、安装及配置maven 1.下载maven安装包 首先需要切换到自己需要安装的目录 我自己是把配置都放到了&#xff1a;/usr/local/maven路径下 cd /usr/local/maven 下载maven安装包&#xff1a; wget https://archive.apache.org/dist/maven/maven-3/3.6.1/binaries/apache-maven…

FreeRTOS信号量学习

目录 一、信号量的特性 1. 信号量的常规操作 2. 信号量跟队列的对比 3. 两种信号量的对比 4. 信号量函数 4.1 创建 4.2 删除 4.3 give/take 5. 使用二进制信号量来同步 6. 防止数据丢失 7. 使用计数型信号量 队列(queue)可以用于传输数据&#xff1a;在任务之间、任务和…

Linux多线程:线程池(单例),读写锁

目录 一、线程池&#xff08;单例模式&#xff09;1.1 makefile1.2 LockGuard.hpp1.3 log.hpp1.4 Task.hpp1.5 Thread.hpp1.6 ThreadPool.hpp1.7 main.cc 二、STL,智能指针和线程安全2.1 STL中的容器是否是线程安全的?2.2 智能指针是否是线程安全的? 三、其他常见的各种锁四、…

微服务之配置中心与服务跟踪

zookeeper 配置中心 实现的架构图如下所示&#xff0c;采取数据加载到内存方式解决高效获取的问题&#xff0c;借助 zookeeper 的节点监听机制来实现实时感知。 配置中心数据分类 事件调度&#xff08;kafka&#xff09; 消息服务和事件的统一调度&#xff0c;常用用 kafka …

使用Java语言中的算法输出杨辉三角形

一、算法思想 创建一个名为YanghuiTest的类,然后创建二维数组&#xff0c;然后遍历二维数组的第一层&#xff0c;然后初始化第二层数组的大小&#xff0c;然后遍历第二层数组&#xff0c;然后将两侧的数组元素赋为1&#xff0c;然后其它数值通过公式计算&#xff0c;最后可以输…

Leetcode—1099.小于K的两数之和【简单】Plus

2023每日刷题&#xff08;六十八&#xff09; Leetcode—1099.小于K的两数之和 实现代码 class Solution { public:int twoSumLessThanK(vector<int>& nums, int k) {int n nums.size();int left 0, right n - 1;int sum 0;int ans 0;sort(nums.begin(), nums…