Скільки подвійних чисел між 0,0 і 1,0?


94

Це те, що мені запам’яталось роками, але я ніколи раніше не знайшов часу, щоб запитати.

Багато генераторів випадкових чисел (псевдо) генерують випадкове число від 0,0 до 1,0. Математично в цьому діапазоні є нескінченні числа, але doubleце число з плаваючою комою і, отже, має кінцеву точність.

Тож питання такі:

  1. Скільки всього doubleчисел між 0,0 і 1,0?
  2. Чи стільки ж цифр від 1 до 2? Між 100 і 101? Між 10 ^ 100 і 10 ^ 100 + 1?

Примітка: якщо це має значення, мене цікавить, doubleзокрема , визначення Java .

Відповіді:


68

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

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

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

(0.1 / 64) * 2**52

чітке doubles - яке зводиться до 7036874417766.4004... дати або взяти один або два ;-).


@Alex: лише на замітку, коли я писав від 100 до 100,1, я писав неправильно. Я мав на увазі від 100 до 101. В основному, між N і N + 1 для довільних N.
полігенмастильні

4
@Alex: тож дозвольте мені це зрозуміти: може бути не більше 2**64можливих подвійних значень (оскільки це 64-бітний тип), і, мабуть, ВЕЛИЧЕЗНА частка цих значень лежить між ними 0..1?
полігенмастильні речовини

9
@polygene, так і так - зокрема, приблизно одна чверть можливих значень (для будь-якого "нормального" подання з плаваючою точкою будь-якої бази та показника проти довжини дробу) лежить між 0,0 і 1,0 (інша чверть між 1,0 і нескінченністю, а половина, що залишилася на від’ємній половині реальної осі). По суті, половина значень показника (з нормальним зміщенням, наполовину в межах його діапазону) представляють від'ємні потужності основи, отже, числа <1,0.
Alex Martelli,

8
@polygenelubricants: для багатьох застосувань діапазон від 0 до 1 набагато, набагато важливіший і цікавіший, ніж діапазон від 100 до 101, тому він отримує більшу частку значень. Наприклад, у фізиці часто доводиться мати справу із смішно малими значеннями, такими як гравітаційна константа Ньютона при 6.67e-11. Маючи хорошу точність, корисніше, ніж між 100 і 101. Прочитайте floating-point-gui.de для отримання додаткової інформації.
Michael Borgwardt

1
Ви також можете масштабувати будь-яке число від 0,0 до 1,0, відстежуючи шкалу окремо, даючи менше помилок при обчисленні. Приємно, коли весь числовий рядок може бути зіставлений між двома числами!
codekaizen

42

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

+1, за добре підкріплену точну відповідь. (Якщо ви вимогливі до підрахунку кінцевих точок, пам’ятайте, що +0.0 та -0.0 мають різні подання.)
Джим Льюїс,

1
+1, такий поворот закінчується! Відчував, ніби я читаю сценарій М. Нічного Шьямалана!
полігенмастильні речовини

7

Інші вже пояснювали, що в діапазоні є приблизно 2 ^ 62 подвійних [0,0, 1,0].
(Це насправді не дивно: існує майже 2 ^ 64 чітких скінченних подвійних; з них половина є позитивними, і приблизно половина з них <1,0.)

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


3

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


Так, але це для float, а не double - floatчастка має 23 біти, тому 2**23 -> 8388608різні значення між сусідніми степенями двох ("включна" частина, звичайно, означає, що вам доведеться порахувати ще одну, наступну ступінь двох). doubles мають 52-розрядні дроби!
Alex Martelli,

1
@Alex: Гадаю, мені доведеться залишити програму (модифіковану для парних), що працює до кінця Всесвіту, або близько того, перш ніж я зможу отримати результати ... :(
Марк Рушаков,

1
Я почуваюся німо; Я просто написав doubleеквівалент і подумав: "Гей, я відповім на власне запитання приблизно за 5 хвилин ..."
полігенмастильні матеріали,

1
@polygene: Це схоже на проблему Ейлера проекту, де очевидний підхід неможливо обчислити, але повинна бути якась
надзвичайно

2
можливо, не з по-справжньому надзарядженим суперкомп'ютером: на машині, яка займає лише наносекунду, щоб запустити внутрішній цикл, підрахунок doubleміж сусідніми потужностями двох займе близько 52 днів ( printlnзвичайно, дуже малоймовірно, щоб він працював так швидко, незважаючи ні на що, тому припустимо, що одне твердження зникає ;-). Я думаю, що можливо взяти рік чи менше на потужній, але реалістичній машині ;-).
Alex Martelli

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

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


Ваша відповідь за 2 суперечить тому, як я розумію роботу FP.
полігенмастильні речовини

Я думаю , що 1це неправильно , тому що прихований біт завжди один - тому 2^52, НЕ 2^53 окремі значення (між сусідніми ступенями двійки, один включав і наступний виключеного - НЕ ! Від 0.0 до 1.0).
Alex Martelli

1

Двомісний Java - це двійковий64 номер IEEE 754.

Це означає, що нам потрібно врахувати:

  1. Мантіса - 52 біт
  2. Показником є ​​11-бітове число з 1023 зміщенням (тобто з доданим до нього 1023)
  3. Якщо показник степеня дорівнює 0, а мантиса не дорівнює нулю, то число називають ненормованим

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

Пам'ятайте, що якщо мантиса додатна, але показник від'ємний, число є додатним, але менше 1 :-)

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.