Сколько двойных чисел существует между 0,0 и 1,0? - PullRequest
90 голосов
/ 05 июня 2010

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

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

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

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

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

Ответы [ 6 ]

64 голосов
/ 05 июня 2010

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 Исключая денормализованный & C, я считаю, что счет будет в 1023 раза 2**52.

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

(0.1 / 64) * 2**52

различается double с - что означает 7036874417766.4004 ... дать или взять один или два; -).

39 голосов
/ 05 июня 2010

Каждое значение 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...
7 голосов
/ 05 июня 2010

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

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

3 голосов
/ 05 июня 2010

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

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

См. Статью в википедии для получения дополнительной информации.

1 голос
/ 05 июня 2010

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

Это означает, что нам нужно учитывать:

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...