Я сталкиваюсь с этим любопытным явлением, пытающимся реализовать генератор UUID в JavaScript.
В принципе, в JavaScript, если я создаю большой список случайных чисел со встроенным Math.random()
на Node 4.2.2
:
var records = {};
var l;
for (var i=0; i < 1e6; i += 1) {
l = String(Math.random()).length;
if (records[l]) {
records[l] += 1;
} else {
records[l] = 1;
}
}
console.log(records);
Числа цифр имеют странный шаблон:
{ '12': 1,
'13': 11,
'14': 65,
'15': 663,
'16': 6619,
'17': 66378,
'18': 611441,
'19': 281175,
'20': 30379,
'21': 2939,
'22': 282,
'23': 44,
'24': 3 }
Я думал, что это причуда генератора случайных чисел для V8, но аналогичная модель появляется в Python 3.4.3
:
12 : 2
13 : 5
14 : 64
15 : 672
16 : 6736
17 : 66861
18 : 610907
19 : 280945
20 : 30455
21 : 3129
22 : 224
И код Python выглядит следующим образом:
import random
random.seed()
records = {}
for i in range(0, 1000000):
n = random.random()
l = len(str(n))
try:
records[l] += 1
except KeyError:
records[l] = 1;
for i in sorted(records):
print(i, ':', records[i])
Ожидается шаблон от 18 до ниже: скажем, если случайное число должно содержать 20 цифр, тогда, если последняя цифра числа равна 0, у него фактически есть только 19 цифр. Если генератор случайных чисел хорош, вероятность того, что это происходит, составляет примерно 1/10.
Но почему шаблон меняется на 19 и более?
Я предполагаю, что это связано с двоичным представлением чисел с плавающей запятой, но я не могу понять, почему именно.