Java double
имеют формат IEEE-754 , поэтому они имеют 52-битную дробь; между любыми двумя соседними степенями двойки (включая одну и double
исключая следующую), следовательно, будет от 2 до 52-й степени различных s (т. е. 4503599627370496 из них). Например, это количество различных double
s между 0,5 включенным и исключенным 1,0, и ровно столько же находится между 1,0 включенным и 2,0 исключенным и т. Д.
Подсчитать doubles
между 0,0 и 1,0 труднее, чем между степенями двойки, потому что в этот диапазон входит много степеней двойки, и, кроме того, один попадает в острые проблемы денормализованных чисел. 10 из 11 разрядов экспоненты покрывают рассматриваемый диапазон, поэтому, включая денормализованные числа (и я думаю, несколько видов NaN
), у вас будет в 1024 раза больше double
s, чем между степенями двойки - 2**62
в любом случае не больше, чем всего . Не считая денормализованного и т. Д., Я считаю, что счет будет 1023 раза 2**52
.
Для произвольного диапазона, такого как «от 100 до 100,1», это еще сложнее, потому что верхняя граница не может быть точно представлена как double
(не является точным кратным любой степени двойки). В качестве удобного приближения, поскольку прогрессия между степенями двойки линейна, вы могли бы сказать, что указанный диапазон является 0.1 / 64
th от промежутка между окружающими степенями двойки (64 и 128), поэтому вы ожидаете около
(0.1 / 64) * 2**52
отличное double
s - которое сводится к 7036874417766.4004
... плюс-минус один или два ;-).
2**64
возможных двойных значений (поскольку это 64-битный тип), и, по-видимому, ОГРОМНАЯ пропорция этих значений находится между0..1
?Каждое
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 нет удвоений . Ни одно из этих чисел не может быть представлено с двойной точностью, и между ними нет двойных чисел. Ближайшими двумя числами двойной точности являются:
а также
источник
Другие уже объяснили, что в диапазоне [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] никогда не будут сгенерированы.источник
В статье «Новая математика Java, Часть 2: Числа с плавающей запятой» от IBM предлагается следующий фрагмент кода для решения этой проблемы (для чисел с плавающей запятой, но я подозреваю, что он работает и для чисел с двойной точностью):
У них есть такой комментарий по этому поводу:
источник
float
, что неdouble
-float
s имеют 23-битную дробь, поэтому2**23 -> 8388608
разные значения между соседними степенями двойки («включающая» часть, конечно, означает, что вам нужно считать еще один, следующую степень двойки).double
s имеют 52-битные дроби!double
эквивалент и подумал: «Эй, я отвечу на свой вопрос примерно через 5 минут ...»double
между соседними силами двух потребуется около 52 дней (println
конечно было бы очень маловероятно , чтобы бежать так быстро независимо от того, что, так допустим, что одно утверждение уходит ;-). Думаю, на мощной, но реалистичной машине можно потратить год или меньше ;-).См. Статью в Википедии для получения дополнительной информации.
источник
1
это неправильно , потому что скрытый бит всегда один - поэтому2^52
, не2^53
отдельные значения (между соседними степенями двойки, один включал и следующий исключенного - не ! От 0.0 до 1.0).Двойное число Java - это двоичное 64-разрядное число IEEE 754.
Это означает, что нам необходимо учитывать:
Это в основном означает, что существует всего 2 ^ 62-2 ^ 52 + 1 возможных двойных представлений, которые согласно стандарту находятся между 0 и 1. Обратите внимание, что 2 ^ 52 + 1 предназначено для удаления случаев ненормализованного числа.
Помните, что если мантисса положительна, а показатель степени отрицателен, число положительно, но меньше 1 :-)
Для других чисел это немного сложнее, потому что крайние целые числа не могут быть представлены точным образом в представлении IEEE 754, и потому что есть другие биты, используемые в экспоненте, чтобы иметь возможность представлять числа, поэтому чем больше число, тем меньше разные значения.
источник