Может ли реальный номер 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
Ответы
Ответ 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, или необратимые рациональные числа, должны быть аппроксимированы. Число цифр (или бит) точности также ограничивает множество рациональных чисел, которые могут быть представлены точно.