Pourquoi le zéro négatif est-il important?

64

Je ne comprends pas pourquoi nous nous soucions de différentes représentations pour un zéro positif et un zéro négatif.

Je me souviens vaguement de la lecture des affirmations selon lesquelles la représentation négative égale à zéro est extrêmement importante dans les programmes impliquant des nombres complexes. Je n'ai jamais eu l'occasion d'écrire du code impliquant des nombres complexes, alors je suis un peu déconcerté de savoir pourquoi.

L'article de Wikipedia sur le concept n'est pas particulièrement utile. il ne fait que de vagues affirmations sur le zéro signé, rendant certaines opérations mathématiques plus simples en virgule flottante, si je comprends bien. Cette réponse répertorie quelques fonctions qui se comportent différemment. Vous pouvez peut-être en déduire quelque chose à partir des exemples si vous savez comment les utiliser. (Bien que, l'exemple particulier des racines carrées complexes semble plat fausse, puisque les deux nombres sont mathématiquement équivalents, à moins que je n’aie un malentendu.) Mais j’ai été incapable de trouver une déclaration claire du genre de problème que vous auriez eu si cela n’était pas là. Les ressources les plus mathématiques que j'ai pu trouver indiquent qu'il n'y a pas de distinction mathématique entre les deux, et l'article de Wikipedia semble suggérer que cela est rarement vu en dehors de l'informatique en dehors de la description des limites.

Alors, pourquoi un zéro négatif est-il précieux en informatique? Je suis sûr que je manque juste quelque chose.

jpmc26
la source
6
Un zéro négatif peut signaler un dépassement de capacité dans un nombre à virgule flottante IEEE, mais au-delà, son utilisation semble être controversée et obscure. Si je devais deviner, je dirais que le zéro négatif est représenté en virgule flottante IEEE car ... eh bien, vous le pouvez. Pour une conduite encore plus intéressante, recherchez les informations sur la signalisation NaN en virgule flottante.
Robert Harvey
1
Si l'exemple donné est "1 / 0.0" / "1 / -0.0", 0 est une branche coupée pour 1 / x et la limite dépend de si vous vous en approchez par le bas ou par le haut.
Vatine
@Vatine Non, l'exemple donné est sqrt(-1+0i) = iet sqrt(-1-0i) = -i, bien que maquillé avec la syntaxe appropriée pour certains langages de programmation, je crois. Je vais éditer pour être plus clair.
jpmc26
3
J'ai cherché programmeurs , débordement de pile , informatique , mathématiques et ingénierie . La seule question que je pouvais trouver était celle des utilisations pour une valeur à virgule flottante à zéro négatif? . Cela ne peut pas être que la deuxième fois que cela se produit!
Je suis vraiment surpris que les nombres complexes n'aient pas du tout été soulevés dans les réponses, surtout compte tenu de l'exemple de racine carrée que j'ai cité.
jpmc26

Réponses:

69

Vous devez garder à l'esprit que dans l'arithmétique FPU, 0 ne doit pas nécessairement signifier exactement zéro, mais aussi une valeur trop petite pour être représentée à l'aide d'un type de données donné, par exemple

a = -1 / 1000000000000000000.0

a est trop petit pour être représenté correctement par float (32 bits), il est donc "arrondi" à -0.

Maintenant, supposons que notre calcul continue:

b = 1 / a

Parce que a est float, il en résultera -infinity qui est assez loin de la réponse correcte de -1000000000000000000.0

Calculons maintenant b s'il n'y a pas -0 (donc a est arrondi à +0):

b = 1 / +0
b = +infinity

Le résultat est encore faux à cause des arrondis, mais maintenant, il est "plus faux" - non seulement numériquement, mais surtout à cause du signe différent (le résultat du calcul est + infini, le résultat correct est -1000000000000000000.0).

Vous pouvez toujours dire que cela n'a pas vraiment d'importance, car les deux ont tort. L'important est qu'il existe de nombreuses applications numériques dans lesquelles le résultat le plus important du calcul est le signe. Par exemple, lorsque vous décidez de tourner à gauche ou à droite au croisement à l'aide d'un algorithme d'apprentissage automatique, vous pouvez interpréter une valeur positive => tourner gauche, valeur négative => tourner à droite, la "magnitude" réelle de la valeur est simplement un "coefficient de confiance".

qbd
la source
Avez-vous une idée quant à savoir si le signe de débordement pourrait être particulièrement important dans les calculs de nombres imaginaires / complexes?
jpmc26
@qbd: Savez-vous quelles sont ces applications numériques? Je dirais que les programmes qui se déclenchent et utilise +infet -infen fonctionnement normal sont bugués.
Björn Lindqvist le
@ BjörnLindqvist Si vous voulez des applications concrètes téléchargeables, alors je n'en connais aucune. Je ne pense pas que ce soit nécessairement un buggy - au lieu de float / double, vous pouvez utiliser quelque chose comme BigDecimal avec une précision illimitée. Mais cela vaut-il la peine quand le programme donnera exactement les mêmes résultats que celui avec float / double, mais avec des performances bien pires?
QDB
Vous avez écrit "des applications numériques dont le résultat le plus important du calcul est le signe", je peux le croire, mais je ne peux pas croire qu'il existe des applications bien écrites qui s'appuient sur -0 et sur les valeurs étant +infet -inf. Si votre programme provoque un dépassement de virgule flottante, c'est le bogue et ce qui se passe après n'est pas si intéressant, à mon humble avis. Il nous manque encore des exemples pratiques dans lesquels -0 est utile.
Björn Lindqvist le
1
@ BjörnLindqvist Une grande partie de x265 est réalisée en assemblage, en s'appuyant sur ses détails obscurs (qui dépendent de l'architecture de la CPU), que peu de gens connaissent au nom de la performance. Est-ce faux? S'appuyer sur la norme largement utilisée depuis 30 ans (qui est là pour rester) pour une fonction simple et bien comprise au nom de la performance ne semble soudainement plus si mauvais.
QDB
8

Premièrement, comment créez-vous un -0? Il existe deux manières: (1) d'effectuer une opération en virgule flottante dans laquelle le résultat mathématique est négatif, mais si proche de zéro qu'il est arrondi à zéro et non à un nombre non nul. Ce calcul donnera un -0. (b) Certaines opérations impliquant des zéros: multiplier un zéro positif par un nombre négatif ou diviser un zéro positif par un nombre négatif ou annuler un zéro positif.

Avoir un zéro négatif simplifie un peu la multiplication et la division, le signe de x * y ou x / y est toujours le signe de x, exclusif ou le signe de y. Sans zéro négatif, il faudrait une vérification supplémentaire pour remplacer -0 par +0.

Il existe de très rares situations où cela est utile. Vous pouvez vérifier si le résultat d'une multiplication ou d'une division est mathématiquement supérieur ou inférieur à zéro, même en cas de dépassement négatif (tant que vous savez que le résultat n'est pas un zéro mathématique). Je ne me souviens pas avoir jamais écrit du code où cela fait une différence.

Optimiser les compilateurs déteste -0. Par exemple, vous ne pouvez pas remplacer x + 0.0 par x, car le résultat ne devrait pas être x si x est -0.0. Vous ne pouvez pas remplacer x * 0.0 par 0.0 car le résultat devrait être -0.0 si x <0 ou x est -0.0.

gnasher729
la source
7
J'aurais aimé que IEEE-754 comprenne quatre zéros: "exact", infinitésimal positif, infinitésimal négatif et non signé (ce dernier étant la différence entre des valeurs indiscernables). Faire cela aurait fait fonctionner beaucoup d'axiomes à virgule flottante - parmi eux, x + 0,0 équiv x-0,0 équiv x, xy équiv x + (- 1,0) * y et 1,0 / x équiv -1,0 / (- 1,0 * x) [si x est zéro positif, les deux seraient pos-inf; si neg-zéro, les deux neg-inf; si exact ou non signé, les deux NaN].
Supercat
J'ai réussi à obtenir un zéro négatif en passant -5et 5en fmod(). C'est assez énervant pour mon cas d'utilisation.
Aaron Franke
6

C # Double conforme à IEEE 754

    double a = 3.0;
    double b = 0.0;
    double c = -0.0;

    Console.WriteLine(a / b);
    Console.WriteLine(a / c);

impressions:

Infinity
-Infinity

en fait pour expliquer un peu ...

Double d = -0.0; 

Cela signifie quelque chose de beaucoup plus proche de d = The Limit of x as x approaches 0-ou The Limit of x as x approaches 0 from the negatives.


Pour répondre au commentaire de Philipp ...

Fondamentalement, zéro négatif signifie un débordement.

Il y a très peu d'utilisation pratique pour le zéro négatif, le cas échéant ...

par exemple, ce code (encore C #):

double a = -0.0;
double b = 0.0;

Console.WriteLine(a.Equals(b));
Console.WriteLine(a==b);
Console.WriteLine(Math.Sign(a));

donne ce résultat:

True
True
0

Pour expliquer de manière informelle, toutes les valeurs spéciales qu'une virgule flottante IEEE 754 peut avoir (infini positif, infini négatif, NAN, -0,0) n'ont aucune signification au sens pratique. Ils ne peuvent représenter aucune valeur physique, ni aucune valeur ayant un sens dans le calcul "réel". Ce qu'ils veulent dire est fondamentalement ceci:

  • l'infini positif signifie un débordement à l'extrémité positive, une virgule flottante peut représenter
  • l'infini négatif signifie un débordement à l'extrémité positive, une virgule flottante peut représenter
  • un zéro négatif signifie un débordement et les opérandes avaient des signes opposés
  • un zéro positif peut signifier un débordement et les opérandes avaient le même signe
  • NAN signifie que votre calcul est compliment non défini, comme sqrt(-7), ou qu'il n'a pas de limite comme 0/0ou commePositiveInfinity/PositiveInfinity
AK_
la source
7
Oui, mais pourquoi est-ce important? Pouvez-vous donner un exemple concret et réel où la différence compte?
Philipp
5

La question de savoir comment cela se rapporte aux calculs de nombres complexes montre clairement pourquoi les deux valeurs +0 et -0 existent en virgule flottante. Si vous étudiez l’analyse complexe, vous découvrez rapidement que les fonctions continues de complexe à complexe ne peuvent généralement pas être traitées comme des «valeurs uniques», à moins d’adopter la «fiction polie» selon laquelle les sorties forment ce qu’on appelle une «surface de Riemann». Par exemple, le logarithme complexe attribue à chaque entrée un nombre infini de sorties. Lorsque vous les connectez pour former une sortie continue, vous obtenez toutes les parties réelles formant une surface de tire-bouchon infinie autour de l'origine. Une courbe continue qui traverse l'axe réel "du côté de l'imaginaire positif" vers le bas et une autre courbe qui "entoure le pôle" et traverse l'axe réel "

Appliquez maintenant cela à un programme numérique qui calcule en utilisant une virgule flottante complexe. L'action entreprise après un calcul donné peut être très différente selon la "feuille" sur laquelle le programme est actuellement "activé", et le signe du dernier résultat calculé vous indique probablement quelle "feuille". Supposons maintenant que le résultat était nul? Rappelez-vous qu'ici, «zéro» signifie vraiment «trop petit pour être correctement représenté». Mais si le calcul peut permettre de conserver le signe (c.-à-d. Mémoriser quelle feuille) lorsque le résultat est égal à zéro, le code peut alors vérifier le signe et effectuer la bonne action, même dans cette situation.

PJM
la source
1

La raison est plus simple que d'habitude

Bien sûr, il y a beaucoup de hacks qui ont l'air vraiment sympa et qui sont utiles (comme arrondir à -0.0ou +0.0mais supposons que nous ayons une représentation de int signé avec un signe moins / plus au début (je sais que cela est résolu par le code binaire U2 en nombres entiers généralement mais supposons une représentation moins complexe de double):

0 111 = 7
^ sign

Et s'il y a un nombre négatif?

1 111 = -7

Ok, c'est simple. Alors représentons 0:

0 000 = 0

C'est bien aussi. Mais qu'en est-il 1 000? Est-ce que ce doit être un numéro interdit? Mieux vaut non.

Supposons donc qu'il existe deux types de zéro:

0 000 = +0
1 000 = -0

Eh bien, cela simplifiera nos calculs et fournira fort heureusement quelques fonctionnalités additionnelles. Donc, les +0et -0viennent seulement de problèmes de représentation binaire.

Dawid Pura
la source
6
Si je comprends bien, vous dites simplement que les personnes qui définissent ou appliquent les normes ne veulent pas s’empêcher de les interdire. Je ne pense pas que ce raisonnement tienne le fait que le complément à 2 utilise la représentation "zéro négatif" pour un nombre entièrement différent et n'a aucune représentation de zéro négatif. Voir l'article de Wikipedia que j'ai lié.
jpmc26
1
@ jpmc26 Je pense qu'il y a en réalité une part de vérité dans le fait que ne pas l'interdire signifie ne pas nécessiter d'implémentations pour avoir un cas particulier. En l'état, chaque numéro a un bit de signe et peut être annulé en basculant le bit de signe. Même les NaN sont signés et les implémentations peuvent (sans y être obligées) choisir un signe approprié lors de la production d'un NaN. Si le zéro négatif n'existait pas, chaque calcul qui aboutissait à 0 devrait faire un travail supplémentaire pour réparer le bit de signe, etc.
hobbs
4
@ jpmc26 (c'est-à-dire que dans chaque multiplication sur deux, le signe du résultat est le xor du signe des multiplicandes et la magnitude est le produit des deux grandeurs. Dans la vie réelle, cela fonctionne pour -1 * 0 = - 0. Mais si zéro avec le bit de signe retourné était une valeur spéciale non nulle, chaque produit pouvant produire 0 devrait vérifier et s'assurer qu'il ne produisait pas cette valeur spéciale par erreur.)
Hobbs