Подтвердить что ты не робот

Может ли реальный номер IEEE 754 "покрывать" все целые числа в пределах своего диапазона?

Оригинальный вопрос был отредактирован (сокращен), чтобы сосредоточиться на проблеме точности, а не на диапазоне.

Одиночная или двойная точность, каждое представление действительного числа ограничено (-range, + range). В этом диапазоне лежат некоторые целые числа (1, 2, 3, 4... и т.д., То же самое происходит с отрицательными числами).

Есть ли гарантия, что реальное число IEEE 754 (float, double и т.д.) может "покрывать" все целые числа в пределах своего диапазона? Под "крышкой" я подразумеваю, что действительное число будет точно представлять целое число, а не как (например) "5.000001".

Как напоминание: http://www3.ntu.edu.sg/home/ehchua/programming/java/DataRepresentation.html хорошее объяснение различных форматов представления чисел.

Update:

Поскольку вопрос заключается в "can", я также искал тот факт, что этого не может быть сделано - для этого достаточно указать число. Например, "нет, этого не может быть сделано, например номер 1748574 не представляется точно по числу с плавающей запятой" (этот номер, конечно, выведен из воздуха).

Для любознательного читателя

Если вы хотите играть с представлением IEEE 754 - он-лайн калькулятором: http://www.ajdesigner.com/fl_ieee_754_word/ieee_32_bit_word.php

4b9b3361

Ответ 1

macias, чтобы добавить к уже превосходному ответу phant0m (upvoted; я предлагаю вам принять его), я буду использовать ваши собственные слова.

"Нет, этого не может быть сделано, например, номер 16777217 не представляется точно по числу с плавающей запятой".

Кроме того, "например, номер 9223372036854775809 не представлен точно двойным числом".

Предполагается, что ваш компьютер использует формат с плавающей запятой IEEE, который является довольно сильной ставкой.

Ответ 2

Нет, не все, но существует диапазон, в пределах которого вы можете точно представлять все целые числа.

Структура 32-битных чисел с плавающей запятой

32-битный тип с плавающей запятой использует

  • 1 бит для знака
  • 8 бит для экспоненты
  • 23 бит для фракции (подразумевается 1)

Представление чисел

В принципе, у вас есть номер в форме

(-)1.xxxx_xxxx_xxxx_xxxx_xxxx_xxx (binary)

который вы затем смещаете влево/вправо с помощью (объективного) экспонента.

Чтобы он представлял целое число, требующее бит n, вам нужно сдвинуть его на бит n-1 влево. (Все x es за пределами плавающей точки просто равны нулю)

Представление целых чисел с 24 битами

Легко видеть, что мы можем представлять все целые числа, требующие 24 бита (и меньше)

1xxx_xxxx_xxxx_xxxx_xxxx_xxxx.0 (unbiased exponent = 23)

так как мы можем установить x es по желанию либо 1, либо 0.

Наибольшее число, которое мы можем представить таким образом:

1111_1111_1111_1111_1111_1111.0

или 2^24 - 1 = 16777215

Следующее более высокое целое число 1_0000_0000_0000_0000_0000_0000. Таким образом, нам нужны 25 бит.

Представление целых чисел с 25 бит

Если вы попытаетесь представить 25-битное целое число (несмещенный показатель = 24), номера имеют следующий вид:

1_xxxx_xxxx_xxxx_xxxx_xxxx_xxx0.0

Двадцать три цифры, которые доступны вам, были перенесены с плавающей запятой. Ведущая цифра всегда равна 1. В общей сложности у нас есть 24 цифры. Но так как нам нужно 25, добавляется нуль.

Найден максимум

Мы можем представить `1_0000_0000_0000_0000_0000_0000 формой 1_xxxx_xxxx_xxxx_xxxx_xxxx_xxx0.0, просто присваивая 1 всем x es. Следующее более высокое целое число из этого: 1_0000_0000_0000_0000_0000_0001. Легко видеть, что это число невозможно представить точно, потому что форма не позволяет нам установить последнюю цифру в 1: она всегда 0.

Отсюда следует, что 1, за которым следуют 24 нуля, является верхней границей для целых чисел, которые мы можем точно представлять. Нижняя граница просто перевернула знаковый бит.

Диапазон, в пределах которого могут быть представлены все целые числа (включая границы)

  • 2 24 как верхняя граница
  • -2 24 как нижняя граница

Структура 64-битных чисел с плавающей запятой

  • 1 бит для знака
  • 11 экспоненциальных битов
  • 52 дробных разряда

Диапазон, в пределах которого могут быть представлены все целые числа (включая границы)

  • 2 54 как верхняя граница
  • -2 54 как нижняя граница

Это легко следует, применяя ту же аргументацию к структуре 64-битных чисел с плавающей запятой.

Примечание. Это не значит, что это все целые числа, которые мы можем представлять, но это дает вам диапазон, в котором вы можете представлять все целые числа. Помимо этого диапазона мы можем представить только мощность двух, умноженных на целое число из указанного диапазона.

Комбинаторный аргумент

Просто убедившись в том, что 32-битные числа с плавающей запятой не могут представлять все целые числа, которые могут представлять 32-битное целое число, нам даже не нужно смотреть на структуру чисел с плавающей запятой.

  • С 32 битами есть 2 32 разные вещи, которые мы можем представить. Не больше, не меньше.
  • 32-битное целое использует все эти "вещи" для представления чисел (попарно разных).
  • 32-битное число с плавающей запятой может представлять как минимум одно число с дробной частью.

Таким образом, невозможно, чтобы 32-битное число с плавающей запятой могло представлять это дробное число в дополнение ко всем целым числам 2 32.

Ответ 3

Нет.

Например, в моей системе тип float может представлять значения примерно до 3.40282e+38. В качестве целого числа это будет приблизительно 340282000000000000000000000000000000000, или около 2 128.

Размер float составляет 32 бита, поэтому он может точно представлять не более 2 32 различных номеров.

Integer объект обычно использует все свои биты для представления значений (с 1 битом, выделенным как знаковый бит для подписанных типов). Объект с плавающей точкой использует некоторые из своих битов для представления экспоненты (8 бит для 32-битного IEEE float); это увеличивает его диапазон за счет потери точности.

Конкретный пример (1267650600228229401496703205376.0 равен 2 100 и точно представлен как a float):

#include <stdio.h>
#include <float.h>
#include <math.h>
int main(void) {
    float x = 1267650600228229401496703205376.0;
    float y = nextafterf(x, FLT_MAX);
    printf("x = %.1f\n", x);
    printf("y = %.1f\n", y);

    return 0;
}

Выходной сигнал в моей системе:

x = 1267650600228229401496703205376.0
y = 1267650751343956853325350043648.0

Еще один способ взглянуть на это:

32-битный объект может представлять не более 2 32 различных значений.

32-разрядное целое число со знаком может представлять все целочисленные значения в диапазоне -2147483648.. 2147483647 (-2 31.. +2 31 -1).

32-разрядный float может представлять множество значений, которые не могут иметь 32-разрядное целое число со знаком, либо потому, что они дробные (0,5), либо потому, что они слишком большие (2.0 100). Поскольку существуют значения, которые могут быть представлены 32-разрядным float, но не 32-разрядным int, должны быть другие значения, которые могут быть представлены 32-разрядным int, но не 32-разрядным < бит float. Эти значения представляют собой целые числа, которые имеют более значимые цифры, чем float могут обрабатывать, поскольку int имеет 31 биты значений, а float имеет только около 24.

Ответ 4

По-видимому, вы спрашиваете, может ли настоящий тип данных представлять все целочисленные значения в своем диапазоне (абсолютные значения до FLT_MAX или DBL_MAX, на C или аналогичные константы на других языках).

Наибольшие числа, представляемые числами с плавающей запятой, хранящиеся в K-битах, обычно намного больше, чем число целых чисел 2 ^ K, которое может представлять K-бит, поэтому обычно ответ отрицательный. 32-битные C-поплавки превышают 10 ^ 37, 32-битные C-целые числа меньше 10 ^ 10. Чтобы узнать следующее представимое число после некоторого числа, используйте nextafter() или nextafterf(). Например, код

printf ("%20.4f %20.4f\n", nextafterf(1e5,1e9), nextafterf(1e6,1e9));
printf ("%20.4f %20.4f\n", nextafterf(1e7,1e9), nextafterf(1e8,1e9));

выводит

     100000.0078         1000000.0625
   10000001.0000       100000008.0000

Вам может быть интересно узнать, может ли быть представлено целое число J, находящееся между двумя соседними дробными плавающими значениями R и S, предполагая, что S-R < 1 и R < J < S. Да, такой J можно представить точно. Каждое значение float представляет собой отношение некоторого целого и некоторой степени 2. (или произведение некоторого целого числа и некоторой степени 2.) Пусть степень 2 равна P, и пусть R = U/P, S = V/П. Теперь U/P < J < V/P, так что U < J * P < V. Более младшие разряды J * P равны нулю, чем единицы U, V (потому что V-U < P, из-за S-R 1), поэтому J можно представить точно.

Я не заполнил все детали, чтобы показать, что J * P-U < P и V-J * P < P, но в предположении S-R < 1 это просто. Ниже приведен пример вычисления значений R, J, S, P, U, V: R = 99999.9921875 = 12799999/128 (т.е. P = 128); пусть S = 100000.0078125 = 12800001/128; мы имеем U = 0xc34fff и V = 0xc35001, и между ними существует число, которое имеет более низкие нули, чем либо; до, J = 0xc35000/128 = 12800000/128 = 100000,0. Для чисел в этом примере обратите внимание, что U и V требуют 24 бит для их точных представлений (6 бит 4-разрядных шестнадцатеричных цифр). Обратите внимание, что 24 бита - это число бит точности в IEEE 754 с одинарной точностью число с плавающей запятой. (См. Таблицу в статье в Википедии.)

То, что каждое число с плавающей запятой является продуктом или отношением некоторого целого числа, а некоторая степень 2 (как упомянуто выше в двух параграфах) также обсуждается в том, что с плавающей запятой в абзаце, который начинается:

По своей природе все числа, выраженные в формате с плавающей запятой, являются рациональными числами с завершающим расширением в соответствующей базе (например,... завершающим двоичным расширением в базе-2). Иррациональные числа, такие как π или √2, или необратимые рациональные числа, должны быть аппроксимированы. Число цифр (или бит) точности также ограничивает множество рациональных чисел, которые могут быть представлены точно.