web-dev-qa-db-fra.com

Quel est le double le plus proche de 1.0, ce n'est pas 1.0?

Existe-t-il un moyen d'obtenir par programme le double le plus proche de 1.0, mais qui n'est pas réellement 1.0?

Une façon hacky de le faire serait de mémoriser le double en un entier de même taille, puis de soustraire un. La façon dont les formats à virgule flottante IEEE754 fonctionnent, cela finirait par diminuer l'exposant de un tout en changeant la partie fractionnaire de tous les zéros (1.000000000000) à tous les (1.111111111111). Cependant, il existe des machines où les nombres entiers sont stockés en petit bout, tandis que les nombres à virgule flottante sont stockés en gros bout, de sorte que cela ne fonctionnera pas toujours.

87
jorgbrown

En C et C++, ce qui suit donne la valeur la plus proche de 1.0:

#include <limits.h>

double closest_to_1 = 1.0 - DBL_EPSILON/FLT_RADIX;

Notez cependant que dans les versions ultérieures de C++, limits.h est déconseillé au profit de climits. Mais si vous utilisez de toute façon du code spécifique C++, vous pouvez utiliser

#include <limits>

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

Et comme Jarod42 l'écrit dans sa réponse, depuis C99 ou C++ 11, vous pouvez également utiliser nextafter:

#include <math.h>

double closest_to_1 = nextafter(1.0, 0.0);

Bien sûr, en C++, vous pouvez (et pour les versions C++ ultérieures devraient) inclure cmath et utiliser std::nextafter au lieu.

22
celtschk

Depuis C++ 11, vous pouvez utiliser nextafter pour obtenir la prochaine valeur représentable dans une direction donnée:

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

Démo

138
Jarod42

En C, vous pouvez utiliser ceci:

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

DBL_EPSILON Est la différence entre 1 et la plus petite valeur supérieure à 1 qui est représentable.

Vous devrez l'imprimer sur plusieurs chiffres afin de voir la valeur réelle.

Sur ma plateforme, printf("%.16lf",1.0+DBL_EPSILON) donne 1.0000000000000002.

25
barak manos

En C++, vous pouvez également utiliser ceci

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