Максимальное количество с плавающей запятой, которое меньше 1

Я делал некоторые вычисления округления и возникал по вопросу. Как я могу выразить наибольшее количество меньше 1 для данного типа с плавающей точкой?

То есть, как я пишу/представляю значение x такое, что x < 1, x + y >= 1 для любого y > 0.

В долях это будет x = (q-1)/q, где q - точность типа. Например, если вы рассчитываете в 1/999 приращениях, тогда x = 998/999.

Для заданного типа (float, double, long double), как можно выразить значение x в коде?


Я также задаюсь вопросом, действительно ли такое значение существует для всех значений y. То есть, поскольку показатель y's становится меньше, возможно, это отношение больше не выполняется. Таким образом, ответ с некоторым ограничением диапазона на y также является приемлемым. (Значение x Я хочу, чтобы все еще существует, связь может просто неправильно выразить его.)

Ответы

Ответ 1

C99 определяет функцию nextafter(). Используйте его как

#include <math.h>
double under_one = nextafter(1, 0);

Ответ 2

Altouht другие правы, что большее значение меньше 1 равно 1-FLT_EPSILON, в плавающей точке оно не может соответствовать условию x < 1, x + y >= 1 для любого y > 0, если вы не используете округление.

Причина в том, что расстояние между 1 и предшествующим ему (что составляет FLT_EPSILON ~ 1.2E-7) намного больше, чем минимальное представимое положительное число FLT_MIN, которое составляет ~ 1.2E-38. Таким образом, существует класс чисел (FLT_MIN ... FLT_EPSILON/2 при округлении до ближайшего, который по умолчанию используется для большинства систем), для которого (1-FLT_EPSILON)+y == (1-FLT_EPSILON) < 1.

Ответ 3

Существует способ получить наименьшее количество, добавляемое к 1, приведет к наименьшему выражаемому количеству, превышающему 1. Это std::numeric_limits<type>::epsilon(). Если вы докажете, что эта величина равна той, которую вы ищете, что вы хотите:

шаблон static _Tp std:: numeric_limits < _Tp > :: epsilon() throw() [inline, static]        Эпсилон машины: разница между 1 и наименьшим значением, превышающим 1, которое представляется.

Ответ 4

Представление с плавающей запятой IEEE 754 имеет свойство, что для чисел, которые являются положительными, а не NaN, порядок совпадает с порядком на битовых шаблонах, рассматриваемых как целые числа.

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

Ответ 5

Согласно стандарту IEEE 754, одноточечная (32-разрядная версия) 1.0 имеет представление 0x3F800000. Мы можем записать это в двоичном виде как 0 01111111 (1) 00000000000000000000000, что означает:

sign = 0
biased exponent = 01111111 = 0x7F, so exponent = -23 (decimal)
mantissa = 0x800000 (the (1) in parentheses is the implied msb)

Итак, значение равно 0x800000 * 2 ^ -23, что равно 1.0. Следующим самым низким номером одной точности является

0 01111110 (1)11111111111111111111111

или 0x3F7FFFFF, или 0xFFFFFF * 2 ^ -24, что составляет около 0,99999994.

Ответ 6

Функция nextafter() работает хорошо @qrdl

#include <math.h>
// find next double from 1.0 working towards 0.0
double before_1 = nextafter(1.0, 0.0);

Тем не менее, чтобы сделать это во время компиляции, как это было прокомментировано @OP, очень переносимо:

#include <float.h>
double before_1 = 1.0 - DBL_EPSILON/FLT_RADIX;

DBL_EPSILON - абсолютная разница между 1.0 и следующей большей double.

FLT_RADIX является основанием (базой) системы с плавающей запятой. Часто 2. Используются значения, такие как 16 и 10.