Может кто-нибудь объяснить, почему (int) (Math.random()*12-3) возвращает значения от -2 до 8, а (int) (Math.random()*12)-3 возвращает от -3 до 8?
Разница заключается в размещении скобок, но я не знаю "скрытую" причину, по которой это имеет значение. Если наименьшее значение, которое может вернуть Math.random(), равно 0, это 0 * 12 = 0, и оба должны иметь как минимум -3.
Я предполагаю, что это связано с приведением к типу int и от 0.x к 1. Это просто (теоретически) невозможно достичь 0,00000000 ...?
Это хороший вопрос. Приведенные ниже ответы, надеюсь, иллюстрируют эффекты приведения к int в разное время в расчете. Обратите внимание, что Math.random() может возвращать 0, но не 1.
Я протестировал это, запустив цикл while, который останавливался только при достижении -3. Он работал около часа без остановки. Я преподаю AP CSA и задаю / тестирую это, потому что вопрос появился в учебном пособии, и в нем утверждалось, что -2 - это минимум для первой функции. Когда я протестировал вторую функцию, она довольно быстро сгенерировала -3.
Вполне возможно запускать его часами и часами и не генерировать 0, но все же это возможно. Другой был намного быстрее, поскольку генерация случайного значения меньше 1/12 гораздо более вероятно, чем одно, точно равное 0.




Первый может вернуть -3, это маловероятно.
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Итак, когда у вас есть (int) (Math.random()*12-3), внутри внутренних круглых скобок результат будет двойным, который вы приведете к int. Это усекает десятичные разряды, поэтому, если Math.random() * 12 не вернет точно 0 (а затем, как только вы вычтите 3, чтобы получить ровно -3), Math.random() * 12 -3 вернется с наименьшим значением 2.{...} и будет усечено до -2.
Когда вы это сделаете:
(int) (Math.random()*12)-3
Приведение имеет большее значение приоритет, чем вычитание, поэтому вероятность усечения до 0 выше. Затем вы вычитаете три, что дает -3.
Приведение к int с помощью (int) обрезает значение с плавающей запятой до 0. Таким образом, с (int) (Math.random()*12-3), даже если мы получаем -2,9999, (int) -2.9999 = -2. В то время как, если мы вычисляем (int) (Math.random()*12), мы можем усечь, например, 0,5 до 0, а затем 0-3 = -3.
Это связано с порядком операций, а также с тем, что (int) someNumberусекаетsomeNumber, если это double. Это означает, что в первом случае крайне маловероятно (но возможно), что Math.random() вернет ноль, в таком случае выражение будет оценивать как -3. Однако любое другое маленькое значение дает (int) -2.[...], который становится -2, потому что он усечен (десятичные дроби просто обрезаются).
В другом случае (int) применяется к Math.random()*12, затем из результата вычитается 3. Здесь каждый раз, когда Math.random()*12 < 1, вы получаете 0 - 3 = -3 в качестве результата. Это случается с 1/12 в большинстве случаев, поэтому вы часто видите, что он дает -3.
Они оба могут достигать -3.
Math.random() возвращает double от 0 (включительно) до 1 (исключая)
При преобразовании в int значение обрезается ближе к 0: (int)(-2.9) == -2 и (int)(2.9) == 2. Фактически, он делает отрицательные числа «больше», а положительные числа «меньше».
Разница в том, что (int) (Math.random()*12)-3 оценивает только часть Math.random()*12, а затем преобразует ее в int - любое случайное значение меньше 1/12 приведет к результату 0 при преобразовании в int с последующим вычитанием 3 листьев -3.
Исходный случай может привести к -3, но ТОЛЬКО когда Math.random() дает результат 0 - гораздо реже, чем предоставление значения меньше 1/12.
Вы абсолютно уверены, что просто случайно не увидели -3, когда выполняли первый расчет? Попробуйте поместить
Math.random()вdoubleи выполнить оба вычисления, распечатав в sysout. Теоретически они должны возвращать один и тот же номер.