Javascript Number.prototype.toFixed:在Internet Explorer中非常正确
考虑以下几点:Javascript Number.prototype.toFixed:在Internet Explorer中非常正确,javascript,internet-explorer,floating-point,Javascript,Internet Explorer,Floating Point,考虑以下几点: var x = 2.175; console.log(x.toFixed(2)); // 2.17 什么?不,这并不奇怪。这是相当明显的,请参见:数字文字2.175实际上是作为一个比2.175小一点点的值存储在内存中(根据IEEE-754规则)。这很容易证明: console.log(x.toFixed(20)); // 2.17499999999999982236 这就是它在32位Windows安装程序上最新版本的Firefox、Chrome和Opera中的工作原理。但这
var x = 2.175;
console.log(x.toFixed(2)); // 2.17
什么?不,这并不奇怪。这是相当明显的,请参见:数字文字2.175
实际上是作为一个比2.175小一点点的值存储在内存中(根据IEEE-754规则)。这很容易证明:
console.log(x.toFixed(20)); // 2.17499999999999982236
这就是它在32位Windows安装程序上最新版本的Firefox、Chrome和Opera中的工作原理。但这不是问题所在
真正的问题是,Internet Explorer如何像人类一样做到正确:
var x = 2.175;
console.log(x.toFixed(2)); // 2.18
console.log(x.toFixed(20)); // 2.17500000000000000000
好吧,我太激动了:事实上,我测试过的所有Internet Explorer(IE8-11,甚至MS Edge!)的表现都是一样的。还有,沃特
更新:它变得更奇怪了:
x=1.0;while((x-=0.1) > 0) console.log(x.toFixed(20));
IE Chrome
0.90000000000000000000 0.90000000000000002220
0.80000000000000000000 0.80000000000000004441
0.70000000000000010000 0.70000000000000006661
0.60000000000000010000 0.60000000000000008882
0.50000000000000010000 0.50000000000000011102
0.40000000000000013000 0.40000000000000013323
0.30000000000000015000 0.30000000000000015543
0.20000000000000015000 0.20000000000000014988
0.10000000000000014000 0.10000000000000014433
0.00000000000000013878 0.00000000000000013878
为什么会有差异?除了最后一个?为什么最后一个没有区别?这与x=0.1非常相似;虽然(x-=0.01).
,顺便说一句:在我们非常接近于零之前,IE中的toFixed
显然是想抄近路
免责声明:我知道浮点数学有点缺陷。我不明白的是IE与浏览器世界的其他部分有什么区别。报告的行为偏离了浏览器的要求 根据第8.5条,除仅有一个NaN外,
编号
类型具有IEEE-754 64位二进制值。因此,2.175不能准确表示;最接近的是2.1749999999982236431605997495353221893310546875
根据15.7.4.5,toFixed(20)
使用的算法归结为:
- 设n是一个整数,其精确数学值n÷10f–x尽可能接近于零。如果有两个这样的n,则选择较大的n
- 在上面的例子中,f是20(请求的位数),x是操作数,应该是2.17499999999822364316059974953221893310546875
- 这将导致为n选择2174999999982236
- 然后n被格式化,生成“2.1749999999982236”
a.toFixed
时,它以
Mozilla进行往返转换时的精确字符串表示
如果能得到官方的确认就太好了,但至少这解释了我所看到的一切。特别是,
console.log( 0.3.toFixed(20) ); // 0.30000000000000000000
console.log( 0.2.toFixed(20) ); // 0.20000000000000000000
console.log( (0.3 - 0.2).toFixed(20) ); // "0.09999999999999998000"
首先,浮点不能用二进制数“精确”表示。将出现一个上升/下降,该值将稍高或稍低。提升/降低的程度取决于转换的方式。即使对于ECMAScript的
toFixed()
的字符串输出,也没有确切的“右值”
但是ECMA标准确实通过er使事情变得有趣。。制定标准。在我看来这是件好事。就像“如果我们都会犯错误,那就让我们犯同样的错误。”
因此,现在的问题是,IE如何以及为什么偏离标准。让我们检查以下测试用例
候选浏览器是IE 10.0.9200.16688和Chrome 30.0.1599.69,运行在x64 Windows 8 Pro上
Case Code IE (10) Chrome (30)
--------------------------------------------------------------------------------
A (0.06).toFixed(20) 0.60000000000000000000 0.05999999999999999778
B (0.05+0.01).toFixed(20) 0.06000000000000000500 0.06000000000000000472
因此,无论是IE还是Chrome,我们都可以看到(0.06)
并不完全等于(0.05+0.01)
。为什么呢?这是因为(0.06)的表示非常接近但不等于(0.06),(0.05)和(0.01)也是如此。当我们执行一个操作(例如加法)时,非常不显著的错误可以加起来变成一个大小稍有不同的错误
现在,由于两个原因,不同浏览器中表示值的差异可能会受到影响:
- 使用的转换算法
- 当转换发生时
number
类的实例,有或没有new
关键字)时,我们实际上提供了一个literal
。文本始终是字符串,即使它表示数字[1]。浏览器解析文本并创建对象并指定表示的值
现在,这里是事情发展的不同方向。IE推迟转换直到需要。这意味着在操作发生之前,即保持数字为文字(或某种中间格式)。但Chrome立即将其转换为操作格式
操作完成后,IE不会恢复为文字格式或中间格式,因为这是毫无意义的,可能会导致精度略有下降
我希望这能澄清一些事情
[1] 代码中表示的值总是
literal
s。如果你引用它们,它们被称为stringliteral
s.嗯,IE有自己的JavaScriptengine@StephenThomas:Chrome、Firefox和Opera也有自己的JavaScript引擎。也许IE使用toString
实现toFixed
?检查…@DCoder并不容易,这正是我问的原因。)关于toFixed
b,这里有很多类似的问题
Case Code IE (10) Chrome (30)
--------------------------------------------------------------------------------
A (0.06).toFixed(20) 0.60000000000000000000 0.05999999999999999778
B (0.05+0.01).toFixed(20) 0.06000000000000000500 0.06000000000000000472