¿Hay alguna manera de obtener programáticamente el doble que está más cerca de 1.0, pero que en realidad no es 1.0?
Una forma engañosa de hacer esto sería memcpy el doble a un entero del mismo tamaño y luego restar uno. De la forma en que funcionan los formatos de punto flotante IEEE754, esto terminaría disminuyendo el exponente en uno mientras cambia la parte fraccionaria de todos los ceros (1.000000000000) a todos los unos (1.111111111111). Sin embargo, existen máquinas donde los enteros se almacenan en little-endian mientras que el punto flotante se almacena en big-endian, por lo que no siempre funcionará.
c++
floating-point
floating-accuracy
jorgbrown
fuente
fuente
nextafter()
es la única forma adecuada de lograr lo que quiere.1.0000...
binario se reduce0.111111....
y para normalizarlo, debe desplazarlo hacia la izquierda: lo1.11111...
que requiere que disminuya el exponente. Y luego estás a 2 ulp de 1.0. Entonces no, restar uno del valor integral NO le da lo que se pregunta aquí.Respuestas:
En C y C ++, lo siguiente da el valor más cercano a 1.0:
#include <limits.h> double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;
Sin embargo,
limits.h
tenga en cuenta que en versiones posteriores de C ++, está obsoleto en favor declimits
. Pero luego, si está usando código específico de C ++ de todos modos, puede usar#include <limits> typedef std::numeric_limits<double> lim_dbl; double closest_to_1 = 1.0 - lim_dbl::epsilon()/lim_dbl::radix;
Y como Jarod42 escribe en su respuesta, desde C99 o C ++ 11 también puede usar
nextafter
:#include <math.h> double closest_to_1 = nextafter(1.0, 0.0);
Por supuesto, en C ++ puede (y para versiones posteriores de C ++ debería) incluir
cmath
y usarstd::nextafter
en su lugar.fuente
Desde C ++ 11, puede usar
nextafter
para obtener el siguiente valor representable en la dirección dada:std::nextafter(1., 0.); // 0.99999999999999989 std::nextafter(1., 2.); // 1.0000000000000002
Manifestación
fuente
std::ceil(std::nextafter(1., std::numeric_limits<double>::max()))
.nextafter
, y así es como musl lo implementa en caso de que alguien más quiera ver cómo se hace. Básicamente: juego de bits crudo.En C, puede usar esto:
#include <float.h> ... double value = 1.0+DBL_EPSILON;
DBL_EPSILON
es la diferencia entre 1 y el valor mínimo mayor que 1 que es representable.Deberá imprimirlo en varios dígitos para ver el valor real.
En mi plataforma,
printf("%.16lf",1.0+DBL_EPSILON)
da1.0000000000000002
.fuente
1.
como1'000'000
demo1.0
. Por cierto, también da el valor más cercano mayor que 1, y no el valor absoluto más cercano a 1 (que posiblemente sea menor que 1). Así que estoy de acuerdo en que esta es una respuesta parcial, pero pensé que, no obstante, podría contribuir.En C ++ también puedes usar esto
1 + std::numeric_limits<double>::epsilon()
fuente