js做四则运算时,精度丢失问题及解决方法
一、前言:
这个问题可以说是程序员必踩的坑,因此网上针对该问题的分析有很多也很详细,解决方法也比较统一,写法也是大同小异,本以为预期效果真能如他们所说是完美的,然而效果却是差强人意。
二、问题:
首先,先来看看两数相加的一个经典问题,网上找过不少资料的人会发现,大多数人分析精度问题都是由此展开,然而最后所谓的解决方法成也在它,败也在它。
0.1+0.2=0.30000000000000004
网上所说的完美解决方法:
function add(arg1,arg2){
var digits1,digits2,maxDigits;
try{digits1=arg1.toString().split(".")[1].length}catch(e){digits1=0}
try{digits2=arg2.toString().split(".")[1].length}catch(e){digits2=0}
maxDigits=Math.pow(10,Math.max(digits1,digits2))
return (arg1*maxDigits+arg2*maxDigits)/maxDigits
}
应用后的输出结果:
0.1+0.2=0.3
从结果可以看出,这方法是完美的解决了这个经典问题,那其他数做运算是不是也都能完美解决呢?在我多数测试后发现并没有,本以为有可能是开发环境或者浏览器导致的问题,但是切换了多个开发环境和浏览器也还是如此,因此可知,方法本身就有问题。
两数直接相加的输出结果:
2.22+2.22=4.44
4.44+2.22=6.66
6.66+2.22=8.88
8.88+2.22=11.100000000000001
11.10+2.22=13.32
13.32+2.22=15.540000000000001
应用网上找的方法的输出结果:
2.22+2.22=4.44
4.44+2.22=6.660000000000001
6.66+2.22=8.88
8.88+2.22=11.100000000000001
11.10+2.22=13.32
13.32+2.22=15.54
对比两次结果可以发现,有些数的精度问题是解决了,而有些数根本没有解决,甚至还导致有些本不会出现精度问题的数产生了问题,除了加法,关于减乘除网上那些方法也一概行不通,限于篇幅,这里就不再一一举例。
三、解决方法:
最后发现那些方法都有个共同特征,就是将原来带n位小数的浮点数乘以10的n次方再进行运算,但是没有解决的主要问题,还是数据类型运算。只要存在浮点数的运算,怎么算也都会有精度问题。
因此,还是要保证参与运算的数为整数才行。保证为整数其实这点就是他们方法中将原来带n位小数的浮点数乘以10的n次方,但还需要强制指定类型为int。但是如果直接将乘以10的n次方后的数转换为Integer对象,会导致在乘方时出现精度问题而出现精度丢失,即计算结果有误。因此还是需要利用Math库中round方法,将数四舍五入取整再进行运算。
两数相加方法:
function add(arg1, arg2) {
return (Math.round(arg1 * 100) + Math.round(arg2 * 100)) / 100;
}
应用该方法进行两数相加的运算结果:
0.1+0.2=0.3
2.22+2.22=4.44
4.44+2.22=6.66
6.66+2.22=8.88
8.88+2.22=11.1
11.10+2.22=13.32
13.32+2.22=15.54
两数相减(既一正数加一负数):
function subtract(arg1, arg2) {
return this.add(arg1, -arg2);
}
两数相乘:
function multiple(arg1, arg2) {
return (Math.round(arg1 * 100) * Math.round(arg2 * 100)) / 10000;
}
两数相除:
/**
* arg1与arg2相除,并以四舍五入的方式保留小数点后2位
*/
function divide(arg1, arg2) {
var d1, d2,
n1 = Number(arg1.toString().replace(".", "")),
n2 = Number(arg2.toString().replace(".", ""));
try {d1 = arg1.toString().split(".")[1].length;} catch (e) {d1 = 0;}
try {d2 = arg2.toString().split(".")[1].length;} catch (e) {d2 = 0;}
return this.toFixed((n1 / n2) * Math.pow(10, d2 - d1), 2);
} /**
* arg以四舍五入的方式保留小数点后n位
*/
function toFixed(arg, n) {
if(n == 0) {
return Math.round(arg)
}
try {
var d, carryD,
ds = arg.toString().split('.'), // 分割整数和小数
len = ds[1].length
// arg的小数位数超出限制位数n才需要处理
if (len > n) {
// 先截取前n位小数
d = Number(ds[1].substring(0, n))
// 舍去的小数部分是否能够进一:通过 0.[第n位小数后的数] 四舍五入取整,结果为0或1
carryD = Math.round(Number('0.' + ds[1].substring(n, len)))
len = (d + carryD).toString().length
if (len > n) {
// 当d=9...,carryD=1,相加后就得向整数进位了,直接返回 整数部分+1
return Number(ds[0]) + 1
} else if (len == n) {
return Number(ds[0] + '.' + (d + carryD))
}
// 小数以0开头要往前补0
var b0 = '', k = 0
while(k < n && ds[1].substring(0, ++k) == '0') {
b0 += '0'
}
return Number(ds[0] + '.' + b0 + (d + carryD))
}
} catch (e) {}
return arg
}
注:js中自带的toFixed函数会把多余的小数直接截掉,因此,这里我进行重写,采用四舍五入的方式保留小数,该方法也很实用。
————————————————
版权声明:本文为CSDN博主「Homilier」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Honiler/article/details/86559589
js做四则运算时,精度丢失问题及解决方法的更多相关文章
- [ JAVA编程 ] double类型计算精度丢失问题及解决方法
前言 如果你在测试金融相关产品,请务必覆盖交易金额为小数的场景.特别是使用Java语言的初级开发. Java基本实例 先来看Java中double类型数值加.减.乘.除计算式实例: public cl ...
- java中double和float精度丢失问题及解决方法
在讨论两位double数0.2和0.3相加时,毫无疑问他们相加的结果是0.5.但是问题总是如此吗? 下面我们让下面两个doubles数相加,然后看看输出结果: @Test public void te ...
- JavaScript(js)文件路径字符串中丢失"\"斜线的解决方法
在刚刚的开发过程中,遇到一个JavaScript 文件路径字符串中丢失"\"的问题,解决过程如下: 背景:cs文件中获取一段包含有路径信息的字符串,将此字符串做为参数传递给前台as ...
- Xshell启动时显示丢失MSVCP110.dll解决方法
成功安装xshell之后,在运行时却弹出“无法启动此程序,因为计算机中丢失MSVCP110.dll.尝试重新安装该程序以解决此问题”,很多人按照提示重装了还是出现同样的问题,本集教程将具体讲解如何处理 ...
- django 做 migrate 时 表已存在的处理方法
django 做 migrate 时 表已存在的处理方法 文章来源:嗨学网 http://www.piaodoo.com 在开发web的时候,如果是以前已存在的项目,项目下载下来后,为了使用测试库的数 ...
- linux下安装Oracle时交换空间不足的解决方法
摘:linux下安装Oracle时交换空间不足的解决方法 linux上安装Oracle时交换空间不足的解决办法 增加交换空间有两种方法: 严格的说,在系统安装完后只有一种方法可以增加swap,那就是本 ...
- EXCEL词典(xllex.dll)文件丢失或损坏解决方法
EXCEL词典(xllex.dll)文件丢失或损坏解决方法 1● 问题 2● 解决 fail 3● 方法2 regsvr32 xllex.dll 4● 方法3 启动server ...
- 使用WebLogic时控制台输出中文乱码解决方法
使用WebLogic时控制台输出中文乱码解决方法 1.找到weblogic安装目录,当前项目配置的domain 2.找到bin下的setDomainEnv.cmd文件 3.打开文件,从文件最后搜索第一 ...
- Apache commons StringUtils 在运行时出现NoClassDefError错误的解决方法
Apache commons StringUtils 在运行时出现NoClassDefError错误的解决方法 在用tomcat运行WEB项目,并且使用了StringUtils包的时候,会出现 jav ...
- JDBC插入数据时中文变为问号的解决方法
JDBC插入数据时中文变为问号的解决方法 制作人:全心全意 出现中文变问号的代码: String url = "jdbc:mysql://localhost:3306/test"; ...
随机推荐
- VS Code 有哪些好用的插件呢?【持续更新】
一.画图工具:vscode-drawio 功能:在 VSCode 中画流程图.数据流图等等. 使用方法: 创建一个后缀名为 .drawio 的文件,然后用 VSCode 打开 ...
- 三万字盘点Spring 9大核心基础功能
大家好,我是三友~~ 今天来跟大家聊一聊Spring的9大核心基础功能. 其实最近有小伙伴私信问我怎么不写文章了,催更来了 其实我不是不写,而是一直在写这篇文章,只不过令我没想到的是,从前期的选题.准 ...
- shell分析nginx日志的一些指令
前言 nginx日志格式默认 shell指令 查看有多少个IP访问: awk '{print $1}' log_file|sort|uniq|wc -l 查看某一个页面被访问的次数: grep &qu ...
- 基于Pair-wise和CrossEncoder训练单塔模型
本文分享自华为云社区<语义检索系统排序模块:基于ERNIE-Gram的Pair-wise和基于RocketQA的CrossEncoder训练单塔模型>,作者: 汀丶. 文本匹配任务数据每一 ...
- 使用C#创建安装Windows服务程序(最全教程)
开发语言:C# 开发环境: Visual Studio 2022 微软官方文档:https://learn.microsoft.com/zh-cn/dotnet/framework/windows-s ...
- 【pandas小技巧】--DataFrame的显示参数
我们在jupyter notebook中使用pandas显示DataFrame的数据时,由于屏幕大小,或者数据量大小的原因,常常会觉得显示出来的表格不是特别符合预期. 这时,就需要调整pandas显示 ...
- 使用 OpenTelemetry 构建 .NET 应用可观测性(1):什么是可观测性
目录 什么是系统的可观测性(Observability) 为什么需要软件系统需要可观测性 可观测性的三大支柱 日志(Logging) 指标(Metrics) 分布式追踪(Distributed Tra ...
- Python自定义终端命令
在python中自定义一个终端命令 这里我们想要将一个csv文件中的数据导入到数据库中,就可以定义一个终端命令,直接一行命令就可以将我们文件中的数据导入到数据库中,特别的简单 首先,我们先创建一个py ...
- 想让你的工作轻松高效吗?揭秘Java + React导出Excel/PDF的绝妙技巧!
前言 在B/S架构中,服务端导出是一种高效的方式.它将导出的逻辑放在服务端,前端仅需发起请求即可.通过在服务端完成导出后,前端再下载文件完成整个导出过程.服务端导出具有许多优点,如数据安全.适用于大规 ...
- Solution -「洛谷 P6287」「COCI 2016-2017」Mag
Description Link. 定义一条链的价值为链上点权乘积除以节链上点数,求一条价值最小的链. Solution 结论:答案链上最多包含一个 \(2\)(其余全为 \(1\)),并且不在链的两 ...