★ 声明:因部分函数未公开算法,以下内容仅为本人测试推断,不保证与事实相符。
=======================================
先看一段代码:
var num1 = math.round( 0.575*100 )
console.log( num1 );
执行结果:
问题分析:
1、0.575*100=57.5
2、对 57.5进行四舍五入(默认舍弃小数,保留到个位数),结果应该是58,但实际结果为57。很显然这是错误的。
那么问题出在哪里呢?我们逐一分析,先看两张图:
同样是对57.5进行四舍五入,为什么结果不一样呢?
我觉得,实际上应该是这两个 57.5 的本质上,应该是不一样的。
我们深入测试一下:
这两个值还是一样的,没有发现猫腻。
继续深入,将这两个值放大看看:
呵呵,发现了,非常明显,两个值不一样。
知识点:因为计算机处理数值的机制问题,影响精度,57.5*100 计算的结果,其实不是 57.5 ,而是 57.49999999999999...
但为什么aardio会显示为57.5呢?
继续看,查找本质,看看aardio为什么会让我们看到【两个一样的值】这么个假象呢?
经测试发现,aardio在显示数值时,从小数的第15位开始,会自动四舍五入。
所以,只要你的小数位数小于15位,是没有任何问题的,一旦达到15位,显示的数值和实际数值就会不一样。
为了继续确定 aardio 将第15位进行四舍五入的问题,我们进一步进行测试:
一波三折,又发现问题了,最后一位5,没向前进位。成了五舍六入了。
那我们测试一下,math.round() 是不是也这样:
额,这是咋了?
这……!!??
math.round() 出问题了,从第10位开始,就乱了。
math.round()只支持到小数点后第9位?!
数值放大测试一下
看来是有这种可能性。既然10位不准确,那么我们就验证一下9位是不是准确:
OK,继续放大数值看看:
基本上没有问题了。
看来,math.round() 自身就存在精度问题。所以,想依靠 math.round() 来处理到小数点后14位的想法,不好实现了。
结论
既然math计算出现了各种未知问题,最终如何保证我们处理的数值,跟显示的数值是一样的呢?
本来,我们只需要按以上规则,将数值进行四舍五入即可。
但既然 math.round() 有问题,而且console.log等函数也不仅仅是四舍五入这样简单,那么我只能折中一下,出两个不完美方案了。
1、因为console.log使用 tostring() 将数值变成字符串,而我们不知道tostring是如何工作的,所以,只能先利用tostring函数,再利用tonumber函数,进行一个【数值→字符串→数值】的转变过程。这样可以保证显示出来的数值,和真实的数值是一样的。
2、直接使用 math.round(,9) 进行处理,虽然处理后的数值小数位数不超过9位,但是这样既保证了与显示数值一致,也尽量保证了处理效率和准确度。
★ 建议:
牵扯到小数的计算式,尽量将计算结果做四舍五入处理,将可能出现的不精确结果,转化为一个可接受精度的固定数值。
不精确结果如:
0.1+0.1 = 0.20000000000000001 ;
0.575×100 = 57.499999999999993 ;
0.14×100 = 14.0000000000000002 ;
一般这种不精确的结果,小数部分会很长,建议将其四舍五入至小数点后9位以内。
如:
math.round( 0.1+0.1 ,9 ) = 0.2 ;
math.round( 0.575×100 ,9 ) = 57.5 ;
math.round( 0.14×100 ,9 ) = 14 ;
最终效果如下: