valeur double minimale en C / C ++

92

Existe-t-il un moyen standard et / ou portable de représenter la plus petite valeur négative (par exemple pour utiliser l'infini négatif) dans un programme C (++)?

DBL_MIN dans float.h est le plus petit positif nombre .

Volonté
la source
4
Je vais pour -DBL_MAX, mais je suis sûr qu'il ya une raison technique est pas :-)
4
@Neil, non il n'y en a pas, ce n'est pas comme 2 entiers complémentaires
fortran
Je n'ai encore rien vu dans la norme indiquant que la plage des types à virgule flottante doit être symétrique autour de zéro. Mais les constantes dans limits.h et <limits> suggèrent que les standards C et C ++ s'attendent à ce qu'ils le soient.
Steve Jessop
4
En fait, DBL_MIN dans float.h est le plus petit nombre normalisé positif . Il y a des nombres encore plus petits.
fdermishin
1
@fortran: IEEE 754 FP utilise un bit de signe, et certainement la plupart des matériels FP de nos jours sont IEEE 754. Mais C et C ++ prennent en charge le matériel non IEEE 754 FP, la question est donc de savoir si le langage garantit que -DBL_MAX doit être égal à la valeur minimale représentable.
j_random_hacker

Réponses:

135

-DBL_MAX dans ANSI C , qui est défini dans float.h.

dfa
la source
cela semble le plus standard et portable
Will
Voici l'explication de mon -1: qui ou quoi dit que -DBL_MAX est garanti par le langage C ou C ++ pour être représentable, sans parler de la valeur minimum représentable? Le fait que la plupart du matériel FP soit conforme à la norme IEEE 754 et utilise cette représentation ne signifie pas que -DBL_MAX est garanti de fonctionner sur n'importe quelle plate-forme C conforme à la norme.
j_random_hacker
@j_random_hacker: voir la réponse de fortran 'ci-dessous'.
JohnTortugo
3
@j_random_hacker C'est un très bon point, mais le standard C exige -DBL_MAXd'être exactement représentable, donc si le matériel FP n'est pas capable de cela, l'implémentation doit juste contourner cela. Voir le modèle à virgule flottante en 5.2.4.2.2 Caractéristiques des types flottants <float.h> p2 de C99 (peuvent avoir été déplacés ailleurs depuis).
2
@j_random_hacker Oui, mais p2 spécifie que e_min et e_max sont indépendants du bit de signe, il en DBL_MAXest exactement de (1 - b ^ −p) b ^ e_max, qui est exactement représentable, la valeur finie la plus négative est exactement - (1 - b ^ −p) b ^ e_max, et comme cela se trouve être exactement -DBL_MAX, la négation DBL_MAXne peut pas non plus introduire d'erreurs d'arrondi.
70

Les nombres à virgule flottante (IEEE 754) sont symétriques, donc si vous pouvez représenter la plus grande valeur ( DBL_MAXounumeric_limits<double>::max() ), ajoutez simplement un signe moins.

Et puis est la manière cool:

double f;
(*((long long*)&f))= ~(1LL<<52);
fortran
la source
6
+1 Pour souligner la symétrie des nombres à virgule flottante :)
Andrew Hare
4
Qu'en est-il des implémentations C / C ++ qui n'utilisent pas les flottants IEEE 754?
Steve Jessop
1
Le manuel de gcc pour -ffast-math dit: "Définit -fno-math-errno, -funsafe-math-optimisations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans et -fcx-limited- range Cette option n'est activée par aucune option -O car elle peut entraîner une sortie incorrecte pour les programmes qui dépendent d'une implémentation exacte des règles / spécifications IEEE ou ISO pour les fonctions mathématiques. Elle peut cependant générer un code plus rapide pour les programmes qui ne nécessitent pas les garanties de ces spécifications. " Le calcul rapide est un paramètre courant, et l'ICC d'Intel, par exemple, est défini par défaut. Dans l'ensemble, je ne sais pas ce que cela signifie pour moi :-)
Will
4
Cela signifie que les implémentations n'utilisent pas l'arithmétique IEEE 754, mais pour être honnête, ces options utilisent toujours la représentation IEEE. Vous pouvez trouver des bibliothèques d'émulation utilisant une représentation non IEEE, car tous les processeurs n'ont pas un format flottant natif (bien qu'ils puissent publier un ABI C qui inclut un format, correspondant aux bibliothèques d'émulation fournies par le fabricant). Par conséquent, tous les compilateurs ne peuvent pas en utiliser un. Tout dépend de ce que vous entendez lorsque vous demandez "standard et / ou portable", il y a portable en principe et portable en pratique.
Steve Jessop
3
Ce que vous dites est vrai pour IEEE 754, mais la norme ne nécessite pas l'utilisation de cet encodage (comme le souligne @SteveJessop, portable en pratique n'est pas la même chose que portable en principe).
Christophe
44

En C, utilisez

#include <float.h>

const double lowest_double = -DBL_MAX;

Dans C ++ pré-11, utilisez

#include <limits>

const double lowest_double = -std::numeric_limits<double>::max();

Dans C ++ 11 et versions ultérieures, utilisez

#include <limits>

constexpr double lowest_double = std::numeric_limits<double>::lowest();
rubenvb
la source
La min()fonction n'était-elle pas disponible avant C ++ 11? Ou est-ce une valeur différente de celle -max()? en.cppreference.com/w/cpp/types/numeric_limits
Alexis Wilke
5
@Alexis: si vous regardez les trois lignes les plus basses du tableau sur la page que vous avez liée, vous verrez que minvous obtenez la plus petite valeur positive en magnitude et lowestla plus grande valeur négative en magnitude. Oui, c'est terrible. Bienvenue dans le monde brillant de la bibliothèque standard C ++ :-P.
rubenvb
pour C, il est défini dans float.h. limits.hest pour les entiers
Ciprian Tomoiagă
33

Essaye ça:

-1 * numeric_limits<double>::max()

Référence: numeric_limits

Cette classe est spécialisée pour chacun des types fondamentaux, ses membres retournant ou définis sur les différentes valeurs qui définissent les propriétés de ce type dans la plate-forme spécifique dans laquelle il se compile.

Andrew Hare
la source
1
Pourquoi pas juste -numeric_limits<double>::max()?
k06a
4
@ k06a ayant la négation représentée par un seul caractère dans une expression aussi longue, où la chaîne dit même "max", est sûr d'obtenir quelqu'un tôt ou tard. Soit il est stocké dans une variable descriptive, soit utilisé -1 * ...pour le rendre un peu plus clair.
Filip Haglund
20

Recherchez-vous l'infini réel ou la valeur finie minimale? Si le premier, utilisez

-numeric_limits<double>::infinity()

qui ne fonctionne que si

numeric_limits<double>::has_infinity

Sinon, vous devez utiliser

numeric_limits<double>::lowest()

qui a été introduit dans C ++ 11.

S'il lowest()n'est pas disponible, vous pouvez revenir à

-numeric_limits<double>::max()

ce qui peut différer du lowest()principe, mais ne le fait normalement pas dans la pratique.

Christoph
la source
+1 pour la différence entre la valeur finie et infinie! Mais la norme ne garantit pas un encodage symétrique en virgule flottante. Donc, -numeric_limits<double>::max()même si cela fonctionne dans la pratique, ce n'est pas entièrement portable en théorie.
Christophe
@Christophe: [x] corrigé
Christoph
10

Une solution C ++ vraiment portable

À partir de C ++ 11, vous pouvez utiliser numeric_limits<double>::lowest(). Selon la norme, il renvoie exactement ce que vous recherchez:

Une valeur finie x telle qu'il n'y a pas d'autre valeur finie y où y < x.
Significatif pour toutes les spécialisations dans lesquelles is_bounded != false.

Démo en ligne


Beaucoup de réponses C ++ non portables ici!

Il existe de nombreuses réponses pour -std::numeric_limits<double>::max() .

Heureusement, ils fonctionneront bien dans la plupart des cas. Les schémas d'encodage en virgule flottante décomposent un nombre en une mantisse et un exposant et la plupart d'entre eux (par exemple le populaire IEEE-754 ) utilisent un bit de signe distinct, qui n'appartient pas à la mantisse. Cela permet de transformer le plus grand positif en le plus petit négatif en retournant simplement le signe:

entrez la description de l'image ici

Pourquoi ne sont-ils pas portables?

La norme n'impose aucune norme à virgule flottante.

Je conviens que mon argument est un peu théorique, mais supposons qu'un fabricant de compilateur excentrique utilise un schéma de codage révolutionnaire avec une mantisse codée dans certaines variations d'un complément à deux . Le codage du complément à deux n'est pas symétrique. par exemple pour un caractère 8 bits signé, le maximum positif est 127, mais le minimum négatif est -128. Nous pourrions donc imaginer qu'un codage en virgule flottante montre un comportement asymétrique similaire.

Je ne connais aucun schéma d'encodage comme celui-là, mais le fait est que la norme ne garantit pas que le retournement de signe donne le résultat attendu . Donc, cette réponse populaire (désolé les gars!) Ne peut pas être considérée comme une solution standard entièrement portable! / * du moins pas si vous n'avez pas affirmé que numeric_limits<double>::is_iec559c'est vrai * /

Christophe
la source
1

La question initiale concerne l'infini. Alors, pourquoi ne pas utiliser

#define Infinity  ((double)(42 / 0.0))

selon la définition IEEE? Vous pouvez bien sûr nier cela.

Norbert
la source
Bonne idée ! Et ça marche . Mais seulement sinumeric_limits<double>::has_infinity && ! numeric_limits<double>::traps
Christophe
1

Existe-t-il un moyen standard et / ou portable de représenter la plus petite valeur négative (par exemple pour utiliser l'infini négatif) dans un programme C (++)?

Approche C.

De nombreuses implémentations prennent en charge +/- infinis, donc la doublevaleur la plus négative est -INFINITY.

#include <math.h>
double most_negative = -INFINITY;

Existe-t-il un moyen standard et / ou portable ...?

Maintenant, nous devons également considérer d'autres cas:

  • Pas d'infinis

Simplement -DBL_MAX.

  • Seulement un infini non signé .

Je m'attendrais dans ce cas, OP préférerait -DBL_MAX.

  • Valeurs anormales supérieures à DBL_MAX.

Il s'agit d'un cas inhabituel, probablement hors des préoccupations d'OP. Quand doubleest codé comme une paire de points flottants pour atteindre la plage / précession désirée (voir double-double ), il existe une normale maximale doubleet peut-être une plus grande dé-normale . J'ai vu un débat pour DBL_MAXsavoir s'il fallait se référer à la plus grande normale , à la plus grande des deux.

Heureusement, cette approche par paires inclut généralement un -infinity, donc la valeur la plus négative reste -INFINITY.


Pour plus de portabilité, le code peut suivre la voie

// HUGE_VAL is designed to be infinity or DBL_MAX (when infinites are not implemented)
// .. yet is problematic with unsigned infinity.
double most_negative1 = -HUGE_VAL;  

// Fairly portable, unless system does not understand "INF"
double most_negative2 = strtod("-INF", (char **) NULL);

// Pragmatic
double most_negative3 = strtod("-1.0e999999999", (char **) NULL);

// Somewhat time-consuming
double most_negative4 = pow(-DBL_MAX, 0xFFFF /* odd value */);

// My suggestion
double most_negative5 = (-DBL_MAX)*DBL_MAX;
chux - Réintégrer Monica
la source
-1

Si vous n'avez pas activé les exceptions float (ce que vous ne devriez pas à mon humble avis), vous pouvez simplement dire:

double neg_inf = -1/0.0;

Cela donne une infinité négative. Si vous avez besoin d'un flotteur, vous pouvez soit lancer le résultat

float neg_inf = (float)-1/0.0;

ou utilisez l'arithmétique simple précision

float neg_inf = -1.0f/0.0f;

Le résultat est toujours le même, il y a exactement une représentation de l'infini négatif à la fois en simple et en double précision, et ils se convertissent l'un à l'autre comme vous vous en doutez.

cmaster - réintégrer monica
la source
Pourquoi feriez-vous cela au lieu d'écrire simplement-INFINITY
MM
En outre, l'infini peut exister ou non, et s'il existe, le positif et le négatif peuvent ne pas être distingués (dans la norme C).
MM le
Dans de nombreux compilateurs et / ou architectures, votre code C / C ++ ralentira beaucoup d'entre vous qui propagent des valeurs infinies et NaN.
markgalassi
@markgalassi Veuillez regarder de plus près: vous remarquerez qu'il neg_infest initialisé à une valeur constante . Le compilateur se chargera de calculer la infvaleur. Et lorsque vous l'utilisez comme valeur nulle pour calculer un maximum, la première itération l'écrasera généralement avec une valeur plus grande. Ie la performance n'est guère un problème. Et l'OP demande spécifiquement "par exemple utiliser l'infini négatif", et -infc'est en effet la seule réponse correcte à cela. Vous avez décliné une réponse correcte et utile.
cmaster - réintégrer monica le