JS013. 重写toFixed( )方法,toFixed()原理 - 四舍五入?银行家舍入法?No!六舍七允许四舍五入√!
以下为场景实测与原理分析,需要重写函数请直接滚动至页尾!!!
语法 - Number.prototype.toFixed( )
// toFixed()方法 使用定点表示法来格式化一个数值。
numObj.toFixed(digits)
| 参数 | 描述 |
| digits | 小数点后数字的个数;介于 0 到 20 (包括)之间,实现环境可能支持更大范围。如果忽略该参数,则默认为 0。 |
MDN给出的实例
function financial(x) {
return Number.parseFloat(x).toFixed(2);
}
console.log(financial(123.456));
// expected output: "123.46"
console.log(financial(0.004));
// expected output: "0.00"
console.log(financial('1.23e+5'));
// expected output: "123000.00"
然而事实浏览器反馈给我们的结果并非如此。
找到原因
经阅读 .toFixed()为什么精度损失、js中toFixed精度问题的原因及解决办法 两篇文章得到了相对可靠的解释:
toFixed() 方法可把 Number 四舍五入为指定小数位数的数字。例如将数据Num保留2位小数,则表示为:toFixed(Num);但是其四舍五入的规则与数学中的规则不同,使用的是银行家舍入规则,银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。具体规则如下:简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。
实际场景(多浏览器实测)
- Chrome

可以发现在chorme下没有完全去遵循这个规律,看来Chrome有自己的算法,测试1.305 ~ 1.395十个用例,得:在Chrome浏览器中toFixed()的后一位 >6时进位,否则舍去。
2.IE 版本11

IE同样没有采纳银行家舍入法,但所有实例都通过了四舍五入的测试。
3.EDGE

4.FireFox

5.Opera

6.PC Weixin内置浏览器

7.QQ浏览器

在QQ浏览器的智能、极速、IE三个内核模式切换,得到的都是同上大部分的结果。
结论
除了IE11浏览器外,大部分主流浏览器num.toFixed(2)采用了:
num的百分位小数 > 6 ? ( 千分位小数 > 4 ? 进位 : 舍去 ) : 无差别舍去
IE11浏览器则是全部通过四舍五入思维,我无法保证上述文章提到的银行家舍入法一定是误判,但目前精度丢失的规律已经明了。
重写toFixed()
解决方法也非常简单,重写Number.prototype.toFixed()方法(补零无效):
Number.prototype.toFixed = function (s) {
changenum = (parseInt(this * Math.pow( 10, s ) + 0.5) / Math.pow( 10, s )).toString()
return changenum;
}
理念是将小数点左移s(参数)个单位,加上0.5后取整完成四舍五入,如 1.236.toFixed(2) 小数点左移两个单位 -> 123.6 + 0.5 = 124.1 取整 -> 124,最后再将小数点右移s个单位后将Float类型格式化为String类型后return即可。
该方法存在一个问题,即假设参数大于浮点数长度,1.23.toFixed(3) 运算过程 -> 1230 -> 1230.5 -> 1230 -> 1.23,此处的 + 0.5 完全是无效的,且理想结果应补零至千分位得到 1.230 ,优化该方法(可用最终版):
/***************************************************************************
* Number.prototype.toFixed() -> rewrite *
***************************************************************************/
Number.prototype.toFixed = function (s) {
changenum = (parseInt(this * Math.pow( 10, s ) + 0.5) / Math.pow( 10, s )).toString()
index = changenum.indexOf(".")
if(index < 0 && s > 0){
changenum = changenum+"."
for(i = 0; i < s; i++){
changenum = changenum + "0"
}
} else {
index = changenum.length - index;
for(i = 0; i < (s - index) + 1; i++){
changenum = changenum + "0"
}
}
return changenum;
}
进阶 - Number.prototype消失的 “ 0 ”
在所有浏览器下,String("0.050").toFixed(2) = 0.1
原本保留至百分位的小数只保留到了十分位,并非是toFixed( )舍弃了最后的 “ 0 ”,而幕后黑手是Number.prototype,所有toFixed、toString这样的对象方法都成了它的背锅侠。

这个坑留到以后再填
JS013. 重写toFixed( )方法,toFixed()原理 - 四舍五入?银行家舍入法?No!六舍七允许四舍五入√!的更多相关文章
- 关于BigDecimal 和 double 类型保存金钱,以及精度问题,银行家舍入法
1. BigDecimal 类型数据 的创建,构造函数 有 public BigDecimal(BigInteger intVal, long val, int scale, int prec); p ...
- 四舍五入VS银行家舍入法
在学习python的时候,遇见了一个颠覆了我传统观念的四舍五入. 看下面,round()的结果和我们以前根深蒂固的四舍五入是不同的. >>> round(0.5) 0 >> ...
- tofixed方法 四舍五入
tofixed方法 四舍五入 toFixed() 方法可把 Number 四舍五入为指定小数位数的数字.例如将数据Num保留2位小数,则表示为:toFixed(Num):但是其四舍五入的规则与数学中的 ...
- .NET压缩图片保存 .NET CORE WebApi Post跨域提交 C# Debug和release判断用法 tofixed方法 四舍五入 (function($){})(jQuery); 使用VUE+iView+.Net Core上传图片
.NET压缩图片保存 需求: 需要将用户后买的图片批量下载打包压缩,并且分不同的文件夹(因:购买了多个用户的图片情况) 文章中用到了一个第三方的类库,Nuget下载 SharpZipLib 目前用 ...
- js toFixed()方法的坑
javascript中toFixed使用的是银行家舍入规则. 银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法. 简单来说就是:四舍六入五考虑,五后非零就进一,五后为零 ...
- round函数——银行家舍入算法
在处理四舍五入时,相信大部分人会使用math.round函数(不同的语言应该都有).有没有考虑过,这个函数是不是自己所需要的? po主碰到的问题是用来计算平均分.有个顶真的学生反映,明明是86.5,怎 ...
- Chrome/Firefox 中头toFixed方法四舍五入兼容性问题
每个Number的toFixed()方法可把 Number 四舍五入为指定小数位数的数字.四舍五入顾名思义,4及以下舍去,5及以上加1. 四舍 1.31.toFixed(1) // 1.3 1.32. ...
- toFixed()与银行家舍入
toFixed()与银行家舍入 一直在用toFixed()方法做浮点数的舍入取值,如果只是客户端展示数据是没有多大问题的,但是如果涉及到和后端互交,数据的精度可能会导致接口对接失败,当然了,涉及安全性 ...
- JS中toFixed()方法的问题及解决方案
最近发现JS当中toFixed()方法存在一些问题,采用原生的Number对象的原型对象上的toFixed()方法时,规则并不是所谓的“四舍五入”或者是“四舍六入五成双”,所谓“四舍六入五成双”,在百 ...
随机推荐
- skywalking简介
监控的分类 Logging,Metrics和Tracing Logging用于记录离散的事件例如,应用程序的调试信息或错误信息,Logging是我们诊断问题的依据. Metrics用于记录可聚合的数据 ...
- 跟我一起写 Makefile(十)
四.foreach 函数 foreach函数和别的函数非常的不一样.因为这个函数是用来做循环用的,Makefile中的foreach函数几乎是仿照于Unix标准Shell(/bin/sh)中的for语 ...
- Python语言系列-03-文件操作和函数
## 深浅拷贝 #!/usr/bin/env python3 # author:Alnk(李成果) # 赋值运算 # 可变的数据类型:由于数据类型可变,修改数据会在原来的数据的基础上进行修改, # 可 ...
- 【笔记】求数据前n个主成分以及对高维数据映射为低维数据
求数据前n个主成分并进行高维数据映射为低维数据的操作 求数据前n个主成分 先前的将多个样本映射到一个轴上以求使其降维的操作,其中的样本点本身是二维的样本点,将其映射到新的轴上以后,还不是一维的数据,对 ...
- Linux文件系统只读 解决方案:
Linux系统Read-only file system,文件系统只读排查解决方案:文件系统只读机制:当文件系统自身的校验机制发现文件系统存在问题时,为避免文件系统受到进一步的损坏,系统会把文件系统设 ...
- kali虚拟机安装VMTools、更新源、安装docker、配置sqli-labs
一.安装VMTools: 传送门:关于安装VMTools 跟其他版本的虚拟机安装VMTools没什么区别,也得连网(我是kali用dhcp开nat模式) 之后按照上面的链接根据博主的步骤一步一步来即可 ...
- 常见web中间件漏洞(一)IIS漏洞
web中间件作为web安全的重要一块,经常会有人问balabala,虽然有很多已经人尽皆知并且基本不再构成威胁了,但是还是有必要说一下,了解历史,了解我们从哪里来 鉴于内容实在是太多,本来打算一起写完 ...
- 线程队列 concurrent 协程 greenlet gevent
死锁问题 所谓死锁:是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进 ...
- java使用wol远程开机
param类 package com.meeno.framework.wol.params; import lombok.Getter; import lombok.NoArgsConstructor ...
- JdbcTemplateUtils
package com.meeno.common.utils; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.J ...