我觉得这只是一个无害的错误,但我仍然想了解发生了什么。
当我注意到一个函数在Chrome中返回一个荒谬的长字符串时,我正在玩一些代码来在画布上呈现Peano curve,该画布涉及在基数3中表达逻辑坐标。仔细观察,结果表明
(.1).toString(3)
在Chrome中评估
0.00220022002200220022002200220022010000210021000011010100020220112020121211021220201121200010202102221012011200102210101012020202002210201010020021011001000020222100102200220210212210211000201201022020202001100022202200120010210220200011202201010010221121201212202101221212001212001222121001102101022020000120212112002222211011112111220121211112022112100100222121000022102202101222002011202200112101201100111200000110110010101100220121020011020202102112021110010021012001020222211122120120110000221100220200011001122121021021001110002222110122112202001121200021001212100002220022011202201110220211200221011122012200011010121122012110100101101220112011200222101020211000020001210201200011121222222202012002200122111220010220220012220112211002120011000102000012110220211202102221100222212020021200112102200120010221120122021101012121000112200002202001222221022011002021010121102012212022112202011110211121122011201011211222121122202111100020201202010220221212101200022020212120001012222211011222010 01100021211101012101011202020110010112202201201001020212002021112020021121202000000222122210022012001201
如此处所示:http://jsfiddle.net/zvp8osm8/
据我所知,在这种情况下,只有点后面的前33位有意义,其余的看起来像没有可识别模式的随机垃圾。
对于不同的基数和指数,在点之后产生1099(!)个数字的类似结果也类似于(10000000000.1).toString(3)
或(.7).toString(7)
。像(.5).toString(3)
这样的其他值也会产生很长的字符串,但数字都有意义。
除Opera之外的其他浏览器在每种情况下只产生合理数量的数字,这让我觉得问题出现在Chrome的Javascript引擎中。
我现在有两个问题:
答案 0 :(得分:5)
对于您显示的特定情况,看起来数字是使用以下天真算法生成的,从x = .1
开始。
x
乘以3。x
替换为小数部分。这在数学上可以很好地工作,但是在浮点世界中这是完全无稽之谈,当然,因为乘以3和后续舍入到最近的浮点数可能会引入一个小错误,并且在30之后数字左右,错误已经完全淹没了原始数字,而我们只是变得垃圾。
据推测,在初始数字绝对值大于1.0
的情况下,还有一些方法可以处理数字之前的数字,但是没有样本输出,我不会去猜猜算法是什么。
为了证明上述原因,这里有一些Python中的代码,其输出与问题中给出的完全匹配。这里,modf
是提取Python float的小数部分和整数部分的操作。
>>> from math import modf
>>> x = 0.1
>>> digits = []
>>> for _ in xrange(1099):
... x, digit = modf(3.0 * x)
... digits.append(str(int(digit)))
...
>>> print('0.' + ''.join(digits))
输出:
0.00220022002200220022002200220022010000210021000011010100020220112020121211021220201121200010202102221012011200102210101012020202002210201010020021011001000020222100102200220210212210211000201201022020202001100022202200120010210220200011202201010010221121201212202101221212001212001222121001102101022020000120212112002222211011112111220121211112022112100100222121000022102202101222002011202200112101201100111200000110110010101100220121020011020202102112021110010021012001020222211122120120110000221100220200011001122121021021001110002222110122112202001121200021001212100002220022011202201110220211200221011122012200011010121122012110100101101220112011200222101020211000020001210201200011121222222202012002200122111220010220220012220112211002120011000102000012110220211202102221100222212020021200112102200120010221120122021101012121000112200002202001222221022011002021010121102012212022112202011110211121122011201011211222121122202111100020201202010220221212101200022020212120001012222211011222010 01100021211101012101011202020110010112202201201001020212002021112020021121202000000222122210022012001201
这应该回答你的一个问题:即随机数字的来源。我无法回答为什么Chrome会选择输出这么多数字的问题。
答案 1 :(得分:2)
首先必须将数字.1
转换为浮点数,以二进制表示。在二进制中,.1
无法精确表示,因此低位数字中的某个错误将在何处。这类似于尝试用十进制表示1/7
:它是重复序列.142857 142857 ...
;无论你在哪里结束,都会失去精确度。
当然后将其转换为基数3时,这些数字中的错误会导致您看到的随机性。
答案 2 :(得分:1)
从ECMAScript 5.1规范开始,即15.7.4.2 Number.prototype.toString([radix])
和9.8.1 ToString Applied to the Number Type:
如果基数不是10,则将数字转换为字符串的精确算法取决于实现(参见15.7.4.2),但是,它应该是9.8.1中概述的算法的推广。 。
这意味着每个浏览器(以及其他所有实现)都可以自由选择是否要提供标准精度(最多21位数)或更多。