Есть ли способ программно получить двойное значение, наиболее близкое к 1.0, но не на самом деле 1.0?
Один из хакерских способов сделать это - преобразовать двойное число в целое число того же размера, а затем вычесть единицу. Как работают форматы с плавающей запятой IEEE754, это привело бы к уменьшению экспоненты на единицу при изменении дробной части со всех нулей (1.000000000000) на все единицы (1.111111111111). Однако существуют машины, на которых целые числа хранятся с прямым порядком байтов, а числа с плавающей запятой хранятся с прямым порядком байтов, так что это не всегда работает.
c++
floating-point
floating-accuracy
Jorgbrown
источник
источник
nextafter()
это единственный правильный способ добиться того, чего он хочет.1.0000...
двоичный файл уменьшается до значения,0.111111....
и для его нормализации вы должны сдвинуть его влево:1.11111...
что требует уменьшения степени. И тогда вы на 2 ulp от 1.0. Так что нет, вычитание единицы из интегрального значения НЕ дает вам того, о чем здесь спрашивают.Ответы:
В C и C ++ следующее дает ближайшее значение к 1.0:
#include <limits.h> double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;
Однако обратите внимание, что в более поздних версиях C ++
limits.h
не рекомендуется использоватьclimits
. Но тогда, если вы все равно используете код, специфичный для C ++, вы можете использовать#include <limits> typedef std::numeric_limits<double> lim_dbl; double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;
И, как пишет Джарод42 в своем ответе, начиная с C99 или C ++ 11 вы также можете использовать
nextafter
:#include <math.h> double closest_to_1 = nextafter(1.0, 0.0);
Конечно, в C ++ вы можете (а для более поздних версий C ++ должны) включать
cmath
и использоватьstd::nextafter
вместо этого.источник
Начиная с C ++ 11, вы можете использовать
nextafter
для получения следующего представимого значения в заданном направлении:std::nextafter(1., 0.); // 0.99999999999999989 std::nextafter(1., 2.); // 1.0000000000000002
Демо
источник
std::ceil(std::nextafter(1., std::numeric_limits<double>::max()))
.nextafter
, и вот как musl реализует это на случай, если кто-то еще захочет увидеть, как это делается. В основном: сырой битлинг.В C вы можете использовать это:
#include <float.h> ... double value = 1.0+DBL_EPSILON;
DBL_EPSILON
- это разница между 1 и наименьшим представимым значением больше 1.Вам нужно будет распечатать его до нескольких цифр, чтобы увидеть фактическое значение.
На моей платформе
printf("%.16lf",1.0+DBL_EPSILON)
дает1.0000000000000002
.источник
1.
как1'000'000
Демо1.0
. Кстати, он также дает ближайшее значение больше 1, а не абсолютное ближайшее значение к 1 (которое, возможно, меньше 1). Я согласен с тем, что это частичный ответ, но я подумал, что, тем не менее, он может внести свой вклад.В C ++ вы также можете использовать это
1 + std::numeric_limits<double>::epsilon()
источник