number.toFixed和Math.round与保留小数
如果你baidu/google过或者自己写过保留两位小数,那下面这代码一定不陌生
Math.round(number*100)/100
那你使用过Number.prototype.toFixed这个方法吗。老实说此前我一次没用过,我猜我以前看书的时候没注意它(反省img...)。
今天看书复习再次看到这个方法,感觉很方便的,一个方法搞定保留小数,岂不是美滋滋。
研究以后发现事情并没有那么简单。
根据网上的说法,toFixed使用的是银行家舍入规则。并非我们熟悉的四舍五入,所以并不适合用来保留小数。对于银行家舍入的解释引用自互联网:
银行家舍入:所谓银行家舍入法,其实质是一种四舍六入五取偶(又称四舍六入五留双)法。
简单来说就是:四舍六入五考虑,五后非零就进一,五后为零看奇偶,五前为偶应舍去,五前为奇要进一。
规则不难理解,可不知道为什么我就是想去浏览器控制台试试....
说好的银行家舍入呢(手动滑稽)。
到这里我开始自己对问题的猜想,是不是以前toFiexed舍入规则是这种银行家舍入规则,而后来随着版本的变更,方法已经变为我们熟知的四舍五入了。现在到底能不能用,我决定试试
function contrast(number,fractionDigits) {
var times = Math.pow(10,fractionDigits);
var roundNum = Math.round(number*times)/times;
var toFixedNum = number.toFixed(fractionDigits);
if(roundNum.toString() !== toFixedNum){
console.log('-------------------------');
console.count();
console.log("number:"+number);
console.log("fractionDigits:"+fractionDigits);
console.log("roundNum:"+roundNum);
console.log("toFixedNum:"+toFixedNum);
}
}
var number,
fractionDigits;
for (var i = 0; i < 1000; i++) {
number = Math.floor(Math.random()*Math.pow(10,16))/Math.pow(10,16);
//一开始是以toFiexed参数范围取的20位,后来发现精度只支持16位
fractionDigits = Math.floor(Math.random()*16);
contrast(number,fractionDigits)
}
实验的结果,有两种情况,一是值一样,保留的小数不同(末尾0舍去与否)
坏就坏在第二种情况
出问题的数,保留小数,都在15位,难道是支持的准确精度位数不够吗,并不是的,比如:
这图也可以证明,toFiexed并非什么银行家舍入规则,至少我现在使用的chrome 62.0.3202.75不是,我使用的6.10.3nodejs也不是
网上找不到答案,那就书上找呗。在犀牛书里3.1.4里找到了一个原因,二进制浮点数表示法:
此外在知乎看到一个相当典型的例子1.555+1
可见1.555,在js里,其实是一个非常接近真实的1.555,但小于它的一个近似值。
我们认为的那个该进一的5其实在计算机眼中是4999..由上面的结果,不难预见到下面的结果
由此可见真正的问题源于二进制浮点数表示法并不能精准表示十进制分数!
----------------------------------------------分割线----------------------------------------------
理论完了,下面说说应用。
虽然toFixed由于二进制浮点数表示法的精确问题,并不能成为可靠的保留小数方案。
但我注意到其对小数位数的保留比round实现的保留小数(未做补零处理前)位数准确,也就是实验中的第一种情况。
我想利用这一特点,来给round保留的小数补零!!
由于Math.round(number*times)/times正确处理过toFiexed可能出错的5(4999....),这时候再用toFiexed,就可以避免错误(因为现在是999....\000...)。而又可以利用toFiexed正确保留小数位数的特点来补零。
function contrast(number,fractionDigits) {
var times = Math.pow(10, fractionDigits);
var roundNum = Math.round(number * times) / times;
var toFixedNum = number.toFixed(fractionDigits);
var decimal = roundNum.toString().split(".");
var realValue1 = roundNum.toString();//手动补0
var realValue2 = roundNum.toFixed(fractionDigits);//toFixed补0
if(decimal.length === 2 ){
if (decimal[1].length < fractionDigits) {
realValue1 = decimal[0] + '.' + (decimal[1] + "0000000000000000").slice(0,fractionDigits);
}
}else if(fractionDigits !== 0){
realValue1 = decimal[0] + '.' + ("0000000000000000").slice(0,fractionDigits);
}
if (realValue1 !== realValue2) {
console.log('-------------------------');
console.count('错误数');
console.log("number:" + number);
console.log("fractionDigits:" + fractionDigits);
console.log("roundNum:" + roundNum);
console.log("realValue1:" + realValue1);
console.log("realValue2:" + realValue2);
console.log("toFixedNum:" + toFixedNum);
}else{
console.count('正确数');
}
}
var number,
fractionDigits;
for (var i = 0; i < 10000; i++) {
number = Math.floor(Math.random()*Math.pow(10,20))/Math.pow(10,20);
fractionDigits = Math.floor(Math.random()*16);
contrast(number,fractionDigits)
}
实验了10000*10次随机数随机保留小数,无错误。
理论和实际都无问题,以后我保留小数就准备这样用了!
function toFixed(number,fractionDigits){
var times = Math.pow(10, fractionDigits);
var roundNum = Math.round(number * times) / times;
return roundNum.toFixed(fractionDigits);
}
number.toFixed和Math.round与保留小数的更多相关文章
- Number(),parseInt(),parseFloat(),Math.round(),Math.floor(),Math.ceil()对比横评
首先,这些处理方法可分为三类. 1,只用来处理数字取整问题的:Math.round(),Math.floor(),Math.ceil(): 2,专门用于把字符串转化成数值:parseInt(),par ...
- WinCE的C#编程,对float型进行四舍五入保留两位小数,小数进行四舍五入操作,Math.Round的应用案例。
private float ConvertFloat4Se5Ru(float flotValue) { int iValue = (int)Math.Round(flotV ...
- 【JAVA】Math.Round()函数常见问题“四舍5入”
java.lang.Math.Round()使用时候,处理方式整理,方便以后查找 /** * 测试函数 2014-01-10 */ public class TestMath { pu ...
- (Math.round(num*100)/100).toFixed(2); 将输入的数字变成保留两位小数
<input type="number" @input="onInputPrice" @blur="onPrice" data-id= ...
- Js 和 PHP 中保留小数点后X位数的方法 toFixed、round、number_format、sprintf
在 Javacript 中保留小数点后两位数的方法为 toFixed(2),其中的2为保留两位,写多少就保留多少了,满5进1. Javacript例子: var num = 24.54789523; ...
- JAVA除法保留小数点后两位的两种方法 Java Math的 floor,round和ceil的总结
floor 返回不大于的最大整数 round 则是4舍5入的计算,入的时候是到大于它的整数round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下 ...
- Js中toFixed()方法保留小数不精准的问题
toFixed() 方法可把 Number 四舍五入为指定小数位数的数字. 问题:部分特殊数值使用toFixed() 方法会出现转换不正确的情况,举个例子: (3329.225).toFixed(2) ...
- java.math.BigDecimal保留两位小数,保留小数,精确位数
http://blog.csdn.net/yuhua3272004/article/details/3075436 使用java.math.BigDecimal工具类实现 java保留两位小数问题 ...
- C#对应JavaScript的银行家舍入规则(Math.Round()对应toFixed(f))
Math.Round((n * u - t * u )/ u, f);//这里使用银行家四舍五入对应JS的 toFixed() ((n * u - t * u) / u).toFixed(f) f为小 ...
随机推荐
- go路由httprouter中的压缩字典树算法图解及c++实现
目录 go路由httprouter中的压缩字典树算法图解及c++实现 前言 httprouter简介 压缩字典树 概念 插入操作 查询操作 c+++实现 go路由httprouter中的压缩字典树算法 ...
- flex招式心法
flex布局绝对是我们平常在布局中用的最多的一个属性,我们来看看它在can i use中的浏览器支持度:(截止到2019/11/16) 挖藕,凹森!支持度居然这么好,好到连ie也能支持大部分的flex ...
- Refresh design pattern
多年后, 再次翻阅设计模式书籍, 将每种模式的要点总结于此, 需要本身有一定设计模式基础, 再结合要点, 帮助更好理解与运用. 策略模式 (Strategy) 附加功能单独抽象不同接口 功能以组合方式 ...
- 超宽banner图在版心居中
步骤如下: 1.版心盒子设置相对定位relative 2.banner图设置绝对定位,设置block,清除默认的间距 3.banner图的left设置:left:50%: margin-left:- ...
- [20191122]oracel SQL parsing function qcplgte.txt
[20191122]oracel SQL parsing function qcplgte.txt --//昨天看了链接:https://nenadnoveljic.com/blog/memory-l ...
- java程序猿工具
1.做为一个程序员打字最重要 指法打字练习软件:http://home.bdqn.cn/thread-11142-1-1.html 2.JDK必不可少 JDK6.X下载 JDK ...
- Markdown语法教程
标题 # 一级标题 ## 二级标题 ### 三级标题 #### 四级标题 ##### 五级标题 ###### 六级标题 效果如下: 一级标题 二级标题 三级标题 四级标题 五级标题 六级标题 段落 换 ...
- RTP中的H264的SVC相关信息
概览 本文简单的介绍了rtp中的h264的svc相关信息 h264的svc相关格式信息 从RTP Payload Format for H.264 Video可以看见264在rtp的传输过程中,在rt ...
- 一些常用的 redis 的操作配置(对String、hash)
import java.util.List; import java.util.Map; import org.apache.logging.log4j.LogManager; import org. ...
- Git终端命令行的常用操作
一.git源代码管理的优点 方便多人协同开发.工作 降低代码的管理成本 良好的分支管理机制 二.结构分析 服务端和客户端都有版本控制能力,都能进行代码的提交.合并 结构一: 结构二: 三.工作区的创建 ...