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

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

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

Таким образом, вопросы:

  1. Сколько double числа там между 0,0 и 1.0?
  2. Есть ли так же, как много чисел между 1 и 2? Между 100 и 101? Между 10^100 и 10^100+1?

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

92
задан polygenelubricants 5 June 2010 в 02:51
поделиться

6 ответов

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

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

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

(0.1 / 64) * 2**52

различных двойных s - что составляет 7036874417766.4004 ... плюс-минус один или два ;-).

67
ответ дан 24 November 2019 в 06:34
поделиться

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

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

Интервал [100.0, 101.0] соответствует представлениям между 0x40590000000000 и 0x405940000000000000; это 2^46 различных значений.

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

99999999999999982163600188718701095...

и

10000000000000000159028911097599180...
41
ответ дан 24 November 2019 в 06:34
поделиться

Другие уже объяснили, что в диапазоне [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] никогда не будут сгенерированы.

7
ответ дан 24 November 2019 в 06:34
поделиться

В статье Новая математика Java, Часть 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 для единицы наименьшей точности или последней единицы.

3
ответ дан 24 November 2019 в 06:34
поделиться
  1. 2 ^ 53 - размер мантиссы / мантиссы 64-битного числа с плавающей запятой, включая скрытый бит.
  2. Примерно да, поскольку sifnificand фиксируется, но показатель степени изменяется.

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

2
ответ дан 24 November 2019 в 06:34
поделиться

Java double - это двоичное число IEEE 754.

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

  1. Мантисса - 52 бита
  2. Экспонента - 11-битное число со смещением 1023 (т.е. с прибавлением к нему 1023)
  3. Если экспонента равна 0, а мантисса не равна нулю, то число считается ненормализованным

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

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

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

1
ответ дан 24 November 2019 в 06:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: