Сколько двойных чисел существует между 0.0 и 1.0?

Это то, что было у меня на уме в течение многих лет, но я никогда не тратил время, чтобы спросить раньше.

Многие (псевдо) генераторы случайных чисел генерируют случайное число между 0.0 и 1.0. Математически в этом диапазоне есть бесконечные числа, но double - число с плавающей запятой и поэтому имеет конечную точность.

Итак, вопросы:

  • Сколько чисел double существует между 0.0 и 1.0?
  • Есть ли столько чисел между 1 и 2? Между 100 и 101? Между 10 ^ 100 и 10 ^ 100 + 1?

Примечание: если это имеет значение, меня интересует определение Java double в частности.

Ответ 1

Java double находятся в формате IEEE-754, поэтому они имеют 52-битную дробь; между любыми двумя смежными степенями двух (включая один и исключая следующий), следовательно, будет от 2 до 52-й степени различной double (то есть, 4503599627370496 из них). Например, количество выделенных double между 0.5 включенными и 1.0 исключено, и именно то, что многие также лежат между 1.0 включенными и 2.0 исключенными и т.д.

Подсчет doubles между 0.0 и 1.0 сложнее, чем между двумя степенями, потому что в этом диапазоне имеется много полномочий из двух, а также попадает в тернистые проблемы денормализованных чисел. 10 из 11 бит экспонентов охватывают диапазон, о котором идет речь, поэтому, включая денормализованные числа (и, я думаю, несколько видов NaN), у вас будет 1024 раза double как лежащий между степенями двух - нет более чем 2**62. Исключая denormalized & c, я считаю, что счетчик будет 1023 раза 2**52.

Для произвольного диапазона, например, "100-1100,1", это еще сложнее, потому что верхняя граница не может быть точно представлена ​​как double (не являясь точным кратным любой степени из двух). В качестве удобного приближения, поскольку прогрессия между степенями двух линейна, вы можете сказать, что указанный диапазон составляет 0.1 / 64 th промежутка между окружающими силами двух (64 и 128), поэтому вы ожидаете о

(0.1 / 64) * 2**52

different double - который приходит к 7036874417766.4004... дает или принимает один или два; -).

Ответ 2

Каждое значение double, представление которого находится между 0x0000000000000000 и 0x3ff0000000000000, находится в интервале [0.0, 1.0]. Это (2 ^ 62 - 2 ^ 52) различные значения (плюс или минус пара в зависимости от того, подсчитываете ли вы конечные точки).

Интервал [1.0, 2.0] соответствует представлениям между 0x3ff0000000000000 и 0x400000000000000; что 2 ^ 52 различных значений.

Интервал [100,0, 101,0] соответствует представлениям между 0x4059000000000000 и 0x4059400000000000; что 2 ^ 46 различных значений.

Нет удвоений между 10 ^ 100 и 10 ^ 100 + 1. Ни одно из этих чисел не представляется в двойной точности, и между ними нет двойников. Ближайшие два числа двойной точности:

99999999999999982163600188718701095...

и

10000000000000000159028911097599180...

Ответ 3

Другие уже объяснили, что в диапазоне [0.0, 1.0] около 2 ^ 62 удваивается.
(Не удивительно: почти 2 ^ 64 отдельных конечных двойника, из них половина положительна, а примерно половина из них равна 1,0)

Но вы говорите о генераторах случайных чисел: обратите внимание, что генератор случайных чисел, генерирующий числа между 0.0 и 1.0, вообще не может вывести все эти числа; обычно он будет генерировать числа формы n/2 ^ 53 с n целым числом (см., например, документацию по Java для nextDouble). Таким образом, обычно есть только около 2 ^ 53 (+/- 1, в зависимости от того, какие конечные точки включены) возможные значения для выхода random(). Это означает, что большинство удвоений в [0.0, 1.0] никогда не будут сгенерированы.

Ответ 4

В статье Java new math, часть 2: числа с плавающей запятой от IBM предлагает следующий фрагмент кода для решения этой проблемы (в поплавках, но я подозреваю, что он работает и в парном разряде):

public class FloatCounter {

    public static void main(String[] args) {
        float x = 1.0F;
        int numFloats = 0;
        while (x <= 2.0) {
            numFloats++;
            System.out.println(x);
            x = Math.nextUp(x);
        }
        System.out.println(numFloats);
    }
}

У них есть комментарий по этому поводу:

Оказывается, ровно 8 388 609 поплавок между 1.0 и 2.0 включительно; большая, но едва ли бесчисленная бесконечность вещественных чисел, существующих в этом диапазоне. Последовательные числа составляют около 0,0000001 друг от друга. Это расстояние называется ULP для единицы наименьшей точности или единицы в последнем месте.

Ответ 5

  • 2 ^ 53 - размер значимости/мантиссы 64-битного числа с плавающей запятой, включая скрытый бит.
  • Грубо да, поскольку sifnificand фиксирован, но экспонента изменяется.

Дополнительную информацию см. в статье в википедии.

Ответ 6

Java double - это двоичный код IEEE 754.

Это означает, что нам нужно рассмотреть:

  • Мантисса - 52 бит
  • Exponent - 11-разрядное число с 1023 смещением (то есть с добавлением 1023)
  • Если показатель степени равен 0, а мантисса не равна нулю, то число называется ненормированным

В основном это означает, что существует всего 2 ^ 62-2 ^ 52 + 1 возможных двойных представлений, которые в соответствии со стандартом находятся между 0 и 1. Заметим, что 2 ^ 52 + 1 - это удаление случаев ненормированные номера.

Помните, что если мантисса положительна, а показатель отрицательного числа положителен, но меньше 1: -)

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