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"; ...
随机推荐
- 利用文件包含漏洞包含ssh日志拿shell
今天看文章学了一招,有包含漏洞无法传文件的时候用 目标服务器环境为ubuntu,ssh登录日志文件是/var/log/auth.log 找个Linux的环境执行ssh '<? phpinfo() ...
- [gin]基于切片实现crud
前言 代码参考自<Building Distributed Application in Gin> 需求:设计一个食谱相关的API,数据存放到切片中. 设计模型和API 模型 type R ...
- 重学HTTP:理解同源策略和CORS
每次遇到跨域.代理.CORS这几个词都懵懵的,我决定一次把他们都搞明白,以后遇到他们再也不用害怕了. 一.什么是同源策略? 同源策略是在1995年由 Netscape公司引入到浏览器的,目前所有浏览 ...
- UI自动化执行过程中,隐藏浏览器页面
在执行UI自动化的过程中,浏览器总是会弹出,如果自动化环境是在个人办公笔记本,在工作过程中会影响正常办公.故需要将UI自动化执行时的浏览器隐藏. 代码实现如下: from selenium impor ...
- [Lua] IT技术熟练度生成器 | 根据IT活动记录生成md表格 | 自创
IT技术熟练度 v1.0 为衡量个人能力水平自创的一套评分机制,根据时间.代码行数.基础理论三个变量生成.最近在学lua,正好练下基本功.效果可见 个人介绍 | 代码统计 - 小能日记 - 博客园 ( ...
- 揭秘ChatGPT,如何打造自己的自定义指令
一.ChatGPT-0720更新 又在深夜,正要打开ChatGPT官网测试下pdf对话功能,发现ChatGPT又有更新.本次更新总结有2点: 1.对于Plus用户,GPT-4的使用限额从25条/3h提 ...
- 如何通过API接口获取1688的商品详情
1688是中国最大的B2B电商平台之一,吸引了大量的国内外买家和卖家,提供了丰富的商品资源.许多开发者和企业想要通过API接口获取1688商品的详细信息,以便于进行商品数据分析.价格监控等工作.在本文 ...
- SQL语句简单入门
SQL语句速查 创建部门表 deptno dname location 1 技术部 23楼 create table dept --dept部门 ( deptno int primary key, - ...
- Nhk R1 Editorial
前言 这场比赛的锅貌似有点多-在准备的时候就已经推迟过三次,在这里为对各位比赛时造成的困扰抱歉.这是出题组第一次放比赛,欢迎批评指正. 主要问题在于 C 的数据造水了,hack 数据造反了于是没有 h ...
- Linux 安装 helm
下载helm压缩包,地址 https://github.com/helm/helm/releases/tag/v3.10.1 选择适合自己操作系统的包 上传解压安装 1 root@calico-m ...