Javascript开发:toFixed方法保留小数最后一位出现随机偏差问题

一、问题如下

  起初一直以为toFixed就是js中用于四舍五入保留小数的方法,直到最近遇到一个付款明细计算合计金额的时候出现了保留的最后一位数偏差问题。财务相关的数据是不允许出现金额不一致的问题的,即便是1分钱的差值。于是在网上搜索了许多这个方法相关的问题,发现好像比较特殊。

  有的文章说toFixed遵循的是银行家算法,四舍六入五成双:位数很多的近似数当有效位数确定后,后面多余的数字应该舍去,只保留有效数字最末一位。四是指值小于等于时舍去,六是指大于等于6时进一位,五指的是根据5后面的有效数字来定,当5后面有数字时,舍5入1;当5后无有效数字时,需要分两种情况来讲:若5前面的数字时奇数,则舍5入1;若5前面的数字为偶数,则舍去不进。

  后来在浏览器中测试了一下,发现貌似实际结果与逻辑并不一样

  

  上面是将第三位为5的数据,第二位分别从0-9测试保留两位小数后的结果。发现5的前一位为0-4的都进了位,前一位为5-9的都舍去了,显然和上面说的奇进偶不进并不一致。

  而将小数点后第一位改为8后:

  

  现在又是5前一位为0-6的都舍去了,前一位为7-9的进一位,逻辑又不同了。说明这里的逻辑并不是所谓的银行家算法

  只能去找ECMAScript规范定义的方法:https://262.ecma-international.org/6.0/#sec-number.prototype.tofixed

  页面搜索toFixed,果然,并不是简单的四舍五入这种逻辑,而是一大串不明所以的操作:

  

  意思是,toFixed方法的参数数字如果小于10的21次方的话,就要根据n/10^f-x的方式进行计算,从而决定是进位还是舍去。在参与计算的两个数据中,取更接近0的那个值。

  例如:

  要处理的数字为1.235,要保留两位小数   其中,设立数值n1n2,分别是小数保留进位后舍去后的两个数字去除小数点后的整数值。则1.235进位后和舍去后分别是1.24和1.23,则n1 = 1.24,n2 = 1.23.   f为要保留的位数,保留两位小数,则f = 2.   x是要保留小数的原数值x = 1.235.   分别用n1和n2代入公式进行计算:     n1得出的数值为:1.24/10^2-1.235 = -1.2226     n2得出的数值为:1.23/10^2-1.235 = -1.2227   n1的绝对值为1.2226,比n2得出的数值1.2227要小,所以更接近0。因此1.235.toFixed(2)得出的数值为1.24,正是n1的值。

二、问题解决

  既然官方的方法不适用四舍五入的业务需求,直接自己加个工具类重定义一个方法,然后全局挂载使用就可以了。

  //四舍五入方法,num为处理的数值,point为保留位数 function toFixed(num,point){ //取要保留位数后的一位 var endNum = parseInt(num * Math.pow(10,(point + 1))) % 10; if(endNum <= 4){ return parseInt(num * Math.pow(10,point)) / Math.pow(10,point); }else{ return (parseInt(num * Math.pow(10,point)) + 1) / Math.pow(10,point); } }

 


__EOF__

本文作者我命倾尘
本文链接https://www.cnblogs.com/guobin-/p/16719362.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   我命倾尘  阅读(536)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
历史上的今天:
2020-09-22 SpringBoot框架:两个方法同时调用时父方法使内部方法的DataSource注解失效的解决办法
2019-09-22 Oracle数据库:PLSQL安装过程和SCOTT用户被锁的解决方法
点击右上角即可分享
微信分享提示