Ответ 1
C99 определяет функцию nextafter()
. Используйте его как
#include <math.h>
double under_one = nextafter(1, 0);
Я делал некоторые вычисления округления и возникал по вопросу. Как я могу выразить наибольшее количество меньше 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
Я хочу, чтобы все еще существует, связь может просто неправильно выразить его.)
C99 определяет функцию nextafter()
. Используйте его как
#include <math.h>
double under_one = nextafter(1, 0);
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
.
Существует способ получить наименьшее количество, добавляемое к 1, приведет к наименьшему выражаемому количеству, превышающему 1. Это std::numeric_limits<type>::epsilon()
. Если вы докажете, что эта величина равна той, которую вы ищете, что вы хотите:
шаблон static _Tp std:: numeric_limits < _Tp > :: epsilon() throw() [inline, static] Эпсилон машины: разница между 1 и наименьшим значением, превышающим 1, которое представляется.
Представление с плавающей запятой IEEE 754 имеет свойство, что для чисел, которые являются положительными, а не NaN
, порядок совпадает с порядком на битовых шаблонах, рассматриваемых как целые числа.
Итак, вы можете переинтерпретировать битовый шаблон числа с плавающей запятой 1.0 как целое число, уменьшить это целое число и затем снова интерпретировать его как число с плавающей запятой, чтобы получить число с плавающей запятой чуть ниже единицы.
Согласно стандарту 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.
Функция 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.