Js中toFixed(2)精度问题的原因及解决办法

2024-02-14 07:20

本文主要是介绍Js中toFixed(2)精度问题的原因及解决办法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

    toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。例如将数据Num保留2位小数,则表示为:toFixed(Num);但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则,银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。具体规则如下:简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。

经测试发现,在chorme下面,并没有完全遵守这个规则,尤其是5的后面没有数字的时候,不是这么判断的,如下:

var b = 1.335b.toFixed(2)"1.33"var b = 1.345b.toFixed(2)"1.34"var b = 1.355b.toFixed(2)"1.35"var b = 1.365b.toFixed(2)"1.36"var b = 1.375b.toFixed(2)"1.38"var b = 1.385b.toFixed(2)"1.39"

可以发现在chorme下没有完全去遵循这个规律,或许它有自己的算法,但是毕竟它没有遵循通用的银行家算法,所以tofixed这个方法在涉及到金钱计算的业务中还是少用.

总而言之:不论引入toFixed解决浮点数计算精度缺失的问题也好,它有没有使用银行家舍入法也罢,都是为了解决精度的问题,但是又离不开二进制浮点数的环境,但至少他帮助我们找到了问题所在,从而让我们有解决方法。

一开始的办法是把要四舍五入的后一位单独拎出来单独判断。

解决方法:

通过重写toFixed方法:

Number.prototype.toFixed = function (n) {let result = number.toString();const arr = result.split('.');const integer = arr[0];const decimal = arr[1];result = integer + '.' + decimal.substr(0, n);const last = decimal.substr(n, 1);

// 四舍五入,转换为整数再处理,避免浮点数精度的损失

if (parseInt(last, 10) >= 5) {const x = Math.pow(10, n);result = ((parseFloat(result) * x) + 1) / x;result = result.toFixed(n);}return result;}

然后又发现计算机二进制编码导致的精度问题,详见上一篇博客。

自己debugger,发现页面中的js进了死循环。很明显问题出在toFixed中回调了toFixed,结果没有走出来,继续debugger,又有了惊人的发现。以下是控制台测试:

console.log(2.115 * 100) // 211.50000000000003console.log(2.0115 * 1000) // 2011.4999999999998

既然你一直进入循环,我就手动把你拉出来。

result = (Math.round((parseFloat(result)) * x) + 1) / x;

最终完整的重写toFixed的方法

// toFixed兼容方法Number.prototype.toFixed = function (n) {if (n > 20 || n < 0) {throw new RangeError('toFixed() digits argument must be between 0 and 20');}const number = this;if (isNaN(number) || number >= Math.pow(10, 21)) {return number.toString();}if (typeof (n) == 'undefined' || n == 0) {return (Math.round(number)).toString();}let result = number.toString();const arr = result.split('.');// 整数的情况if (arr.length < 2) {result += '.';for (let i = 0; i < n; i += 1) {result += '0';}return result;}const integer = arr[0];const decimal = arr[1];if (decimal.length == n) {return result;}if (decimal.length < n) {for (let i = 0; i < n - decimal.length; i += 1) {result += '0';}return result;}result = integer + '.' + decimal.substr(0, n);const last = decimal.substr(n, 1);// 四舍五入,转换为整数再处理,避免浮点数精度的损失if (parseInt(last, 10) >= 5) {const x = Math.pow(10, n);result = (Math.round((parseFloat(result) * x)) + 1) / x;result = result.toFixed(n);}return result;}

这篇关于Js中toFixed(2)精度问题的原因及解决办法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/707864

相关文章

Java 线程安全与 volatile与单例模式问题及解决方案

《Java线程安全与volatile与单例模式问题及解决方案》文章主要讲解线程安全问题的五个成因(调度随机、变量修改、非原子操作、内存可见性、指令重排序)及解决方案,强调使用volatile关键字... 目录什么是线程安全线程安全问题的产生与解决方案线程的调度是随机的多个线程对同一个变量进行修改线程的修改操

Redis出现中文乱码的问题及解决

《Redis出现中文乱码的问题及解决》:本文主要介绍Redis出现中文乱码的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1. 问题的产生2China编程. 问题的解决redihttp://www.chinasem.cns数据进制问题的解决中文乱码问题解决总结

全面解析MySQL索引长度限制问题与解决方案

《全面解析MySQL索引长度限制问题与解决方案》MySQL对索引长度设限是为了保持高效的数据检索性能,这个限制不是MySQL的缺陷,而是数据库设计中的权衡结果,下面我们就来看看如何解决这一问题吧... 目录引言:为什么会有索引键长度问题?一、问题根源深度解析mysql索引长度限制原理实际场景示例二、五大解决

Springboot如何正确使用AOP问题

《Springboot如何正确使用AOP问题》:本文主要介绍Springboot如何正确使用AOP问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录​一、AOP概念二、切点表达式​execution表达式案例三、AOP通知四、springboot中使用AOP导出

Python中Tensorflow无法调用GPU问题的解决方法

《Python中Tensorflow无法调用GPU问题的解决方法》文章详解如何解决TensorFlow在Windows无法识别GPU的问题,需降级至2.10版本,安装匹配CUDA11.2和cuDNN... 当用以下代码查看GPU数量时,gpuspython返回的是一个空列表,说明tensorflow没有找到

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM

IDEA Maven提示:未解析的依赖项的问题及解决

《IDEAMaven提示:未解析的依赖项的问题及解决》:本文主要介绍IDEAMaven提示:未解析的依赖项的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝... 目录IDEA Maven提示:未解析的依编程赖项例如总结IDEA Maven提示:未解析的依赖项例如

Redis分片集群、数据读写规则问题小结

《Redis分片集群、数据读写规则问题小结》本文介绍了Redis分片集群的原理,通过数据分片和哈希槽机制解决单机内存限制与写瓶颈问题,实现分布式存储和高并发处理,但存在通信开销大、维护复杂及对事务支持... 目录一、分片集群解android决的问题二、分片集群图解 分片集群特征如何解决的上述问题?(与哨兵模

SpringBoot+Redis防止接口重复提交问题

《SpringBoot+Redis防止接口重复提交问题》:本文主要介绍SpringBoot+Redis防止接口重复提交问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不... 目录前言实现思路代码示例测试总结前言在项目的使用使用过程中,经常会出现某些操作在短时间内频繁提交。例

SpringSecurity显示用户账号已被锁定的原因及解决方案

《SpringSecurity显示用户账号已被锁定的原因及解决方案》SpringSecurity中用户账号被锁定问题源于UserDetails接口方法返回值错误,解决方案是修正isAccountNon... 目录SpringSecurity显示用户账号已被锁定的解决方案1.问题出现前的工作2.问题出现原因各