如果你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与保留小数的更多相关文章

  1. Number(),parseInt(),parseFloat(),Math.round(),Math.floor(),Math.ceil()对比横评

    首先,这些处理方法可分为三类. 1,只用来处理数字取整问题的:Math.round(),Math.floor(),Math.ceil(): 2,专门用于把字符串转化成数值:parseInt(),par ...

  2. WinCE的C#编程,对float型进行四舍五入保留两位小数,小数进行四舍五入操作,Math.Round的应用案例。

    private  float ConvertFloat4Se5Ru(float flotValue) {              int iValue = (int)Math.Round(flotV ...

  3. 【JAVA】Math.Round()函数常见问题“四舍5入”

    java.lang.Math.Round()使用时候,处理方式整理,方便以后查找   /**  * 测试函数 2014-01-10  */ public class TestMath {     pu ...

  4. (Math.round(num*100)/100).toFixed(2); 将输入的数字变成保留两位小数

    <input type="number" @input="onInputPrice" @blur="onPrice" data-id= ...

  5. Js 和 PHP 中保留小数点后X位数的方法 toFixed、round、number_format、sprintf

    在 Javacript 中保留小数点后两位数的方法为 toFixed(2),其中的2为保留两位,写多少就保留多少了,满5进1. Javacript例子: var num = 24.54789523; ...

  6. JAVA除法保留小数点后两位的两种方法 Java Math的 floor,round和ceil的总结

    floor 返回不大于的最大整数 round 则是4舍5入的计算,入的时候是到大于它的整数round方法,它表示“四舍五入”,算法为Math.floor(x+0.5),即将原来的数字加上0.5后再向下 ...

  7. Js中toFixed()方法保留小数不精准的问题

    toFixed() 方法可把 Number 四舍五入为指定小数位数的数字. 问题:部分特殊数值使用toFixed() 方法会出现转换不正确的情况,举个例子: (3329.225).toFixed(2) ...

  8. java.math.BigDecimal保留两位小数,保留小数,精确位数

    http://blog.csdn.net/yuhua3272004/article/details/3075436 使用java.math.BigDecimal工具类实现   java保留两位小数问题 ...

  9. C#对应JavaScript的银行家舍入规则(Math.Round()对应toFixed(f))

    Math.Round((n * u - t * u )/ u, f);//这里使用银行家四舍五入对应JS的 toFixed() ((n * u - t * u) / u).toFixed(f) f为小 ...

随机推荐

  1. [转]UiPath Keyboard Shortcuts

    本文转自:https://docs.uipath.com/studio/docs/keyboard-shortcuts The complete list of keyboard shortcuts ...

  2. Error: Unable to establish IPMI v2 / RMCP+ session

    是这样的,需要ipmi控制器,然后一直报错这个: [root@localhost ~]# sudo ipmitool -I lanplus -H 192.168.87.12 -U root -P pa ...

  3. 使用Apollo动态修改线上数据源

    前言 最近需要实现一个功能,动态刷新线上数据源环境,下面来使用Apollo配置中心和Spring提供的AbstractRoutingDataSource来实现. 具体实现 Apollo是携程开源的统一 ...

  4. 11. Go 语言网络编程

    Go 语言网络编程 Go语言在编写 web 应用方面非常得力.因为目前它还没有 GUI(Graphic User Interface 图形化用户界面)的框架,通过文本或者模板展现的 html 界面是目 ...

  5. 多项式总结(STAGE 1)

    这么难的专题居然只给了这么短时间... 然而在NC的教导之下还是有一定的收获的. 必须打广告:0,1,2,3 附带一个垃圾博客:-1 按照习惯,堆砌结论而不加证明. Section1 导数: 基本形式 ...

  6. filter,map,reduce三个数组高阶函数的使用

    filter ,map ,reduce三个高阶函数的使用 普通方法解决数据问题 const nums1= [10,20,111,222,444,40,50] // 需求1.取出小于100的数字 // ...

  7. pixijs shader 贴图溶解效果教程

    pixijs shader 贴图溶解效果教程 我直接贴代码了 没什么好讲解了 稍微有点基础的人应该能看懂 const app = new PIXI.Application({ transparent: ...

  8. 解决 vscode 中 nuget 插件无法获取包版本的问题

    解决 vscode 中 nuget 插件无法获取包版本的问题 1.问题描述 大概在今年的7月份左右,我忽然发现 NuGet Package Manager 拓展没法正常使用了,只能查询到包: 选完包之 ...

  9. SpringBoot2.0 整合 Dubbo框架 ,实现RPC服务远程调用

    一.Dubbo框架简介 1.框架依赖 图例说明: 1)图中小方块 Protocol, Cluster, Proxy, Service, Container, Registry, Monitor 代表层 ...

  10. maven将xml文件一起打包

    pom文件配置 <build> <!-- 将mapper.xml一起打包 --> <resources> <resource> <director ...