Сколько двойных чисел существует между 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 .

Java double s находятся в формате IEEE-754 , поэтому они имеют 52-битную долю; между любыми двумя смежными степенями двух (включая один и исключая следующий), следовательно, будет 2 до 52-й степени с разными double s (то есть, 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 до 100,1», это еще сложнее, потому что верхняя граница не может быть точно представлена ​​как double (не являющаяся точным кратным любой мощности двух). В качестве удобного приближения, поскольку прогрессия между степенями двух линейна, вы можете сказать, что указанный диапазон составляет 0.1 / 64 й промежуток между окружающими силами двух (64 и 128), поэтому вы ожидаете

 (0.1 / 64) * 2**52 

отдельные double с – что приходит к 7036874417766.4004 … дайте или возьмите один или два ;-).

Каждое 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... 

Другие уже объяснили, что в диапазоне [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 предлагает следующий fragment кода для решения этой проблемы (в поплавках, но я подозреваю, что это работает и для удвоений):

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

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

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

Java double – это номер двоичного кода IEEE 754.

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

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

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

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

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

  • Как создать случайную перестановку в Java?
  • Как вы эффективно генерируете список K неповторяющихся целых чисел между 0 и верхней границей N
  • Как выбрать предмет по его вероятности?
  • Создание m различных случайных чисел в диапазоне
  • Случайный порядок и разбивка на страницы Elicsearch
  • Случайная дата в C #
  • Как я могу перетасовать строки текстового файла в командной строке Unix или в сценарии оболочки?
  • Как рандомизировать (или переместить) кадр данных и разбить по столбцу?
  • Структура данных для загруженных кубиков?
  • Случайное число с вероятностями
  • Давайте будем гением компьютера.