Math.random() возвращает значение больше единицы?

Играя со случайными числами в JavaScript, я обнаружил удивительную ошибку, предположительно, в движке JavaScript V8 в Google Chrome. Рассмотреть возможность:

// Generate a random number [1,5].
var rand5 = function() {
  return parseInt(Math.random() * 5) + 1;
};

// Return a sample distribution over MAX times.
var testRand5 = function(dist, max) {
  if (!dist) { dist = {}; }
  if (!max) { max = 5000000; }
  for (var i=0; i<max; i++) {
    var r = rand5();
    dist[r] = (dist[r] || 0) + 1;
  }
  return dist;
};

Теперь, когда я запускаю testRand5(), я получаю следующие результаты (конечно, немного отличающиеся при каждом запуске, вам может потребоваться установить для «max» более высокое значение, чтобы выявить ошибку):

var d = testRand5();
d = {
  1: 1002797,
  2: 998803,
  3: 999541,
  4: 1000851,
  5: 998007,
  10: 1 // XXX: Math.random() returned 4.5?!
}

Интересно, что я вижу сопоставимые результаты в node.js, что наводит меня на мысль, что это не относится к Chrome. Иногда встречаются разные или несколько загадочных значений (7, 9 и т. д.).

Может ли кто-нибудь объяснить, почему я могу получить результаты, которые вижу? Я предполагаю, что это как-то связано с использованием parseInt (вместо Math.floor()), но я до сих пор не уверен, почему это могло произойти.


person maerics    schedule 08.09.2011    source источник


Ответы (4)


Пограничный случай возникает, когда вам приходится генерировать очень маленькое число, выраженное с помощью показателя степени, например, например, 9.546056389808655e-8.

В сочетании с parseInt, который интерпретирует аргумент как строку, ад вырывается наружу. И, как было предложено до меня, это можно решить с помощью Math.floor.

Попробуйте сами с этим фрагментом кода:

var test = 9.546056389808655e-8;

console.log(test); // prints 9.546056389808655e-8
console.log(parseInt(test)); // prints 9 - oh noes!
console.log(Math.floor(test)) // prints 0 - this is better
person Jakob    schedule 08.09.2011

Конечно, это parseInt() подвох. Сначала он преобразует свой аргумент в строку, и это может привести к научной нотации, которая заставит parseInt сделать что-то вроде этого:

var x = 0.000000004;
(x).toString(); // => "4e-9"
parseInt(x); // => 4

Дурак я...

person maerics    schedule 08.09.2011
comment
вау, хороший улов. Я не знал, что parseInt сначала преобразовал даже число в строку. - person Matt; 08.09.2011
comment
Ну, другая альтернатива - выбросить TypeError, что является способом Java. Большинство API в javascript просто пытаются работать с недопустимыми типами, а не выдают ошибку. - person Esailija; 05.06.2013

Я бы предложил изменить вашу функцию случайных чисел на это:

var rand5 = function() {
  return(Math.floor(Math.random() * 5) + 1);
};

Это будет надежно генерировать целочисленное значение от 1 до 5 включительно.

Вы можете увидеть свою тестовую функцию в действии здесь: http://jsfiddle.net/jfriend00/FCzjF/.

В этом случае parseInt не лучший выбор, потому что он преобразует ваше число с плавающей запятой в строку, которая может быть в нескольких различных форматах (включая экспоненциальную нотацию), а затем попытается разобрать из нее целое число. Гораздо лучше просто работать с поплавком напрямую с помощью Math.floor().

person jfriend00    schedule 08.09.2011
comment
Как его функция в конечном итоге генерирует такие числа, как 7, 9 и 10? - person Matt; 08.09.2011
comment
@Matt - это, вероятно, связано с parseInt без параметра счисления, а затем с операцией с десятичным числом, преобразованным в строку. Все это плохо. - person jfriend00; 09.09.2011

Создайте случайное число, равное или большее единицы, с помощью javascript:

<div id="randomNum"></div>

<script type="text/javascript">
var randomN, underone = Math.random(), digits;
digits = "10";
randomN = Math.floor(underone * Math.pow(10, digits));
document.getElementById("randomNum").innerHTML = "Your random number with " + digits + " digits is: " + randomN;
</script>
person Code Helper    schedule 02.04.2021
comment
Ваш ответ не касается вопроса ОП, который должен был объяснить, почему случайное число было больше единицы. Пожалуйста, просмотрите ответы, за которые проголосовали, а также принятый ответ, чтобы увидеть, как они решили этот конкретный вопрос, а также подумайте, может ли ваш новый ответ добавить новую, актуальную информацию, которая дает новое понимание проблемы, которая, возможно, была упущена или которые другие зрители сочли бы полезными сейчас или в будущем в связи с поднятым конкретным вопросом. - person Paul; 03.04.2021
comment
Похоже, у тебя болит голова. - person Code Helper; 10.04.2021