48 votes

Est-ce que float a un zéro négatif? (-0f)

Les nombres à virgule flottante IEEE ont un bit assigné pour indiquer le signe, ce qui signifie que vous pouvez techniquement avoir des représentations binaires différentes de zéro (+0 et -0). Y a-t-il une opération arithmétique que je pourrais faire, par exemple en C, qui donnerait une valeur de zéro flottante négative?

Cette question est inspirée d'une autre qui remettait en question la possibilité de comparer en toute sécurité 0.0f en utilisant ==, et je me demandais en outre s'il existe d'autres façons de représenter zéro qui pourraient provoquer la rupture de float1 == 0.0f pour des valeurs apparemment parfaitement égales.

[Edit] S'il vous plaît, ne commentez pas sur la sécurité de la comparaison des flottants pour l'égalité! Je n'essaie pas d'ajouter à ce seau débordant de questions en double.

39voto

Rosh Oxymoron Points 6965

Selon la norme, le zéro négatif existe mais il est égal au zéro positif. Pour presque tous les usages, les deux se comportent de la même manière et beaucoup considèrent l'existence d'un zéro négatif comme un détail d'implémentation. Il existe cependant certaines fonctions qui se comportent de manière assez différente, à savoir la division et atan2 :

#include 
#include 

int main() {
    double x = 0.0;
    double y = -0.0;
    printf("%.08f == %.08f: %d\n", x, y, x == y);
    printf("%.08f == %.08f: %d\n", 1 / x, 1 / y, 1 / x == 1 / y);
    printf("%.08f == %.08f: %d\n", atan2(x, y), atan2(y, y), atan2(x, y) == atan2(y, y));
}

Le résultat de ce code est :

0.00000000 == -0.00000000: 1
1.#INF0000 == -1.#INF0000: 0
3.14159265 == -3.14159265: 0

Cela signifierait que le code gérerait correctement certaines limites sans avoir besoin d'une gestion explicite. Il n'est pas certain de pouvoir compter sur cette fonctionnalité pour des valeurs proches des limites, car une simple erreur de calcul peut changer le signe et rendre la valeur loin de la correcte, mais vous pouvez toujours en tirer avantage si vous évitez les calculs qui changeraient le signe.

16voto

Stephen Canon Points 58003

Y a-t-il une opération arithmétique que je pourrais faire, par exemple en C, qui donnerait une valeur flottante zéro négative?

Bien sûr:

float zeroNegatif = -10.0e-30f * 10.0e-30f;

Le résultat mathématiquement précis de la multiplication n'est pas représentable sous forme de valeur flottante, donc il est arrondi à la valeur représentable la plus proche, qui est -0.0f.

Les sémantiques de zéro négatif sont bien définies par la norme IEEE-754; la seule véritable manière observable dont son comportement diffère de celui de zéro dans une expression arithmétique est que si vous divisez par lui, vous obtiendrez une infinité de signe différent. Par exemple:

1.f / 0.f --> +infini
1.f / -0.f --> -infini

Les comparaisons et les additions et soustractions avec -0.f donnent le même résultat qu'avec +0.f (en mode d'arrondi par défaut). La multiplication peut préserver le signe de zéro, mais comme indiqué, elle n'est généralement pas observable.

Il existe certaines fonctions de bibliothèque mathématique dont le comportement peut varier en fonction du signe de zéro. Par exemple:

copysignf(1.0f, 0.0f) --> 1.0f
copysignf(1.0f,-0.0f) --> -1.0f

Cela est plus courant dans les fonctions complexes:

csqrtf(-1.0f + 0.0f*i) --> 0.0f + 1.0f*i
csqrtf(-1.0f - 0.0f*i) --> 0.0f - 1.0f*i

En général, cependant, vous ne devriez pas avoir à vous soucier de zéro négatif.

8voto

Martin Beckett Points 60406

Oui, zéro peut être signé mais la norme exige que zéro positif et zéro négatif soient considérés comme égaux

5voto

rowan194 Points 99

Il existe quelques opérations arithmétiques simples qui donnent une réponse zéro négative (du moins sur les systèmes i386/x64/ARMv7/ARMv8 sur lesquels je les ai testées) :

  • -1 * 0
  • 0 / -1

Ces cas m'ont surpris quand j'écrivais un optimiseur pour simplifier les expressions arithmétiques. Optimiser "a = b * 0" en "a = 0" donnera la mauvaise réponse (+0) si b s'avère être négatif (la réponse correcte est -0).

2voto

Mehrdad Points 70493

Oui, float a un zéro négatif, mais non, vous n'avez pas à vous inquiéter de cela lors de la comparaison des valeurs en virgule flottante.

L'arithmétique en virgule flottante est définie pour fonctionner correctement sur les cas spéciaux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X