Ответ 1
Причина действительно связана с представлением с плавающей запятой. Число чисел с плавающей запятой имеет максимальное количество (двоичных) цифр, которые оно может представлять, и ограниченный диапазон значений экспоненты. Теперь, когда вы распечатываете это без использования научной нотации, вы можете в некоторых случаях иметь нулевые значения после десятичной точки, прежде чем начнут следовать знаковые цифры.
Вы можете визуализировать этот эффект, напечатав те случайные числа, которые имеют самую длинную длину при преобразовании в string
:
var records = {};
var l, r;
for (var i=0; i < 1e6; i += 1) {
r = Math.random();
l = String(r).length;
if (l === 23) {
console.log(r);
}
if (records[l]) {
records[l] += 1;
} else {
records[l] = 1;
}
}
Это печатает только 23-длинные строки, и вы получите такие номера:
0.000007411070483631654
0.000053944830052166104
0.000018188989763578967
0.000029525788901141325
0.000009613635131744402
0.000005937417234758158
0.000021099748521158368
Обратите внимание на нули перед первой ненулевой цифрой. Они фактически не сохраняются в числовой части представления с плавающей запятой, но подразумеваются его экспоненциальной частью.
Если вы должны были вынуть ведущие нули, а затем сделать счет:
var records = {};
var l, r, s;
for (var i=0; i < 1e6; i += 1) {
r = Math.random();
s = String(r).replace(/^[0\.]+/, '');
l = s.length;
if (records[l]) {
records[l] += 1;
} else {
records[l] = 1;
}
}
... вы получите менее странные результаты.
Однако вы увидите некоторую неравномерность, связанную с тем, что javascript
преобразует малые числа в string
: когда они становятся слишком маленькими, научная нотация используется в представлении string
. Вы можете увидеть это со следующим script (не уверен, что каждый браузер имеет одинаковую точку прерывания, поэтому, возможно, вам нужно немного поиграть с номером):
var i = 0.00000123456789012345678;
console.log(String(i), String(i/10));
Это дает мне следующий результат:
0.0000012345678901234567 1.2345678901234568e-7
Таким образом, очень маленькие числа получат более фиксированную длину string
в результате, не более 22 символов, в то время как в ненаучном обозначении длина 23 является общей. Это влияет и на второй script I, а длина 22 будет больше, чем 23.
Следует отметить, что javascript
не переключается на научную нотацию при преобразовании в string
в двоичном представлении:
var i = 0.1234567890123456789e-120;
console.log(i.toString(2));
Вышеприведённый текст выведет строку из более чем 450 двоичных цифр!