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()方法时,规则并不是所谓的“四舍五入”或者是“四舍六入五成双”,所谓“四舍六入五成双”,在百 ...
随机推荐
- 树莓派SG90舵机接法
我的舵机的三条线是红的.黑色.棕色,接法如下: 棕 : GND 红 : VCC 黄: 信号线 如图所示: 图片来源 如上图所示,写代码时注意舵机的BCM编码是18,而不是物理引脚的编码12.
- Linux线程同步之读写锁(rwlock)
读写锁和互斥量(互斥锁)很类似,是另一种线程同步机制,但不属于POSIX标准,可以用来同步同一进程中的各个线程.当然如果一个读写锁存放在多个进程共享的某个内存区中,那么还可以用来进行进程间的同步, 和 ...
- 详细讲讲netty的pipiline!
前言 提到 Netty 首当其冲被提起的肯定是支持它承受高并发的线程模型,说到线程模型就不得不提到 NioEventLoopGroup 这个线程池,接下来进入正题. 线程模型 首先来看一段 Netty ...
- springboot2集成log4j2
pom <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http:// ...
- Python - typing 模块 —— TypeVar 泛型
前言 typing 是在 python 3.5 才有的模块 前置学习 Python 类型提示:https://www.cnblogs.com/poloyy/p/15145380.html 常用类型提示 ...
- Linux系统启动初始化
文章目录 一.BIOS 加载启动引导程序 二.MBR 主引导扇区 三.GRUB引导内核 3.1运行 boot.img 3.2加载 core.img 3.3切换到保护模式 3.4kernel.img 引 ...
- Linux修改Ip简单知识了解
1. 在终端输入:vim /etc/sysconfig/network-scripts/ifcfg-etho(etho是指的安装centos的产生的网卡) 2.按i开始编辑,填写ip地址.子网掩码.网 ...
- BZOJ 4826 影魔
本题可以采用主席树的在线做法,只不过常数会 \(super\) 大. 和其他题解差不多,我们先要求出第 \(i\) 个数的 \(l_i\) 和 \(r_i\) ,其中 \(l_i\) 表示左边第一个比 ...
- 题解 P3158 [CQOI2011]放棋子
题解 本题是一个 \(DP\) 加 容斥,容斥的式子很好推,重点是如何想到和如何推出 \(DP\) 部分的式子. 因为不同种颜色的棋子不能放在同一行或同一列,所以不同种的棋子是相对独立的. 据此,我们 ...
- java-通过ip获取地址
添加maven依赖 <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all&l ...