Какой ближайший двойной к 1.0, то есть 1.0?

Есть ли способ программно получить двойной, который ближе всего к 1.0, но на самом деле не 1.0?

Один взломанный способ сделать это - это memcpy double с целым числом одного и того же размера, а затем вычесть его. То, как работают форматы с плавающей запятой IEEE754, приведет к уменьшению экспоненты на единицу при изменении дробной части от всех нулей (1.000000000000) до всех (1.111111111111). Однако существуют машины, где целые числа хранятся мало-endian, в то время как с плавающей запятой сохраняется big-endian, поэтому это не всегда будет работать.

Ответ 1

В C и С++ следующее дает самое близкое значение 1.0:

#include <limits.h>

double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;

Обратите внимание, однако, что в более поздних версиях С++ limits.h устарел в пользу climits. Но тогда, если вы используете код С++ в любом случае, вы можете использовать

#include <limits>

typedef std::numeric_limits<double> lim_dbl;
double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;

И как пишет Jarod42 в своем ответе, с C99 или С++ 11 вы также можете использовать nextafter:

#include <math.h>

double closest_to_1 = nextafter(1.0, 0.0);

Конечно, на С++ вы можете (и для более поздних версий С++) включать cmath и вместо этого использовать std::nextafter.

Ответ 2

С С++ 11 вы можете использовать nextafter, чтобы получить следующее представимое значение в заданном направлении:

std::nextafter(1., 0.); // 0.99999999999999989
std::nextafter(1., 2.); // 1.0000000000000002

Демо-версия

Ответ 3

В C вы можете использовать это:

#include <float.h>
...
double value = 1.0+DBL_EPSILON;

DBL_EPSILON - это разница между 1 и наименьшим значением, превышающим 1, которое представляется.

Вам нужно распечатать его до нескольких цифр, чтобы увидеть фактическое значение.

На моей платформе printf("%.16lf",1.0+DBL_EPSILON) дается 1.0000000000000002.

Ответ 4

В С++ вы также можете использовать этот

1 + std::numeric_limits<double>::epsilon()