Подтвердить что ты не робот

Может ли 0.99999999999 округлить до 1.0 при умножении?

При умножении числа с плавающей запятой, которое очень близко к 1 с помощью int > 0, может ли оно быть интерпретировано как 1.

То есть, если Math.random() возвращает свой наивысший возможный результат (который на 1 шаг ниже 1.0), будет

(int)(Math.random() * 8)

будет 8 или 7?

Для практического примера, может ли эта часто используемая конструкция давать ошибку индекса за пределы:

someArray[(int)(Math.random() * someArray.length)];

Меня особенно интересуют ответы для Java и ActionScript 3, но я полагаю, что все они используют одни и те же правила для арифметики с плавающей запятой, и ответы на любую платформу были бы полезны.

Обновление: хотя я уже принял ответ, я по-прежнему буду благодарен за подтверждение того, что это не может пойти не так, как в ActionScript 3, так как коллега, сообщивший, что он видел, что он ошибается, - это то, что отчасти заставило меня задать этот вопрос.

4b9b3361

Ответ 1

Если вы умножаете наибольшее значение ниже 1.0 с someInt ( > 0), результат никогда не будет someInt.

Это может быть исчерпывающе проверено на такие целые числа:

Double greatestLessThanOne = Double.longBitsToDouble(4607182418800017407L);

// Assert that greatestLessThanOne is indeed the largest double less than 1.
//assert 1.0 == greatestLessThanOne + Math.ulp(greatestLessThanOne);

for (int i = 1; i >= 0; i++)
    if ((int) (greatestLessThanOne * i) == i)
        System.out.println("Exception found: " + i);

Отрывок не выводит.

(Math.ulp возвращает расстояние между данным двойным и двойным значением, которое больше по величине. Таким образом, это утверждение гарантирует, что greatestLessThanOne действительно самое большое значение меньше 1.0.)

Другими словами, ваша строка

Object element = elementArray[(int)(Math.random() * elementArray.length)];

никогда не приведет к исключению ArrayIndexOutOfBoundsException.


Кроме того, согласно комментарию Марка Дикинсона здесь, это также относится к умножению на двойной.

С помощью арифметики с плавающей запятой IEEE 754 в режиме "круглый" мы можем показать, что x * y < y для любого x < 1.0 и любого не-маленького положительного y. (Он может терпеть неудачу, если y является либо субнормальным, либо наименьшим положительным нормальным числом.)

Ответ 2

Просто вокруг него может быть так:

BigDecimal bd = new BigDecimal(Double.toString(d));
bd = bd.setScale(decimalPlace,BigDecimal.ROUND_HALF_UP);