Страницы

Поиск по вопросам

вторник, 2 апреля 2019 г.

Как узнать минимальное положительное целое число не представимое в float?(и других машинных арифметиках)

Хотелось бы узнать как правильно найти минимальное целое число не представимое в float и десятичной арифметике с заданной мантиссой и экспонентами(минимальная,максимальная)


Ответ

В С константы
FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG
из дадут вам количество цифр в мантиссе соответствующего плавающего типа. Каждая цифра мантиссы - в базе FLT_RADIX (обычно 2). В С++ те же значения можно также получить через std::numeric_limits::digits
Соответственно, все целые числа, чей модуль не превосходит FLT_RADIXFLT_MANT_DIG должны быть представимы. А вот
      FLT_RADIXFLT_MANT_DIG + 1
будет первым (минимальным) положительным целым не представимым в типе float
Почему так? Так устроены плавающие типы. Если убрать не относящиеся к делу детали, то плавающее двоичное значение представляется по принципу
      значение = мантисса * 2экспонента
Если полагать, что мантисса - целое число(1, то при любом значении экспоненты больше 0, в последовательности представимых таким способом целых чисел будут "дырки". Например, очевидно, что при экспоненте 1 представимы будут только четные числа. Непрерывная последовательность целых чисел возможна только при нулевой величине экспоненты, а также в точке перехода от экспоненты 0 к экспоненте 1.
Для экспоненты 0 диапазон ограничен диапазоном значений самой мантиссы. В типе float ширина мантиссы - 24 (это FLT_MANT_DIG). Соответственно диапазон представимых целых идет от 0 до 224-1. А затем, при переходе к экспоненте 1 мы получаем еще одно представимое целое число: 224. А вот следующим представимым целым числом при экспоненте 1 будет только 224+2. Так что число 224+1 - это первая "дырка" в последовательности представимых целых чисел.
Проверим
#include #include #include
int main() { static_assert(FLT_RADIX == 2, "Ya krevedko");
{ unsigned long long i = 1ull << FLT_MANT_DIG; float f = i; printf("%llu %f
", i, f); f = ++i; printf("%llu %f
", i, f); } { unsigned long long i = 1ull << DBL_MANT_DIG; double f = i; printf("%llu %lf
", i, f); f = ++i; printf("%llu %lf
", i, f); } }
Вывод
16777216 16777216.000000 16777217 16777216.000000 9007199254740992 9007199254740992.000000 9007199254740993 9007199254740992.000000
Таким образом в IEEE 754 типа float первое непредставимое целое число - это 16777217, а для типа double - это число 9007199254740993
Та же формула применима и к десятичным представлениям с плавающей точкой, построенным на тех же принципах.

1) В реальности в IEEE 754 все несколько по-другому. Мантисса - это двоичное число с точкой вида 1.000...0 шириной в 24 бита (т.е. 23 двоичных знака после точки), и соответственно идущие подряд целые числа будут представляться при значениях экспоненты до 23. А начиная со значения экспоненты 24 будут представляться уже только четные целые числа. Но на вышеприведенные рассуждения это не оказывает принципиального влияния. Принципиальный момент тут в любом случае один и тот же - непрерывный диапазон целых чисел определяется шириной мантиссы.

Комментариев нет:

Отправить комментарий