7
votes

C99: une partie imaginaire peut-elle être un zéro négatif

est-il possible de stocker zéro négatif dans une partie imaginaire du float complexe C99?

Comment je devrais initialiser statiquement des constantes complexes avec une partie imaginaire signée? p>

J'ai un petit exemple, mais je peux ' T Comprendre, pourquoi A code> et C code> sont identiques et pourquoi -std = c99 code> change les résultats. p>

$ cat zero1.c
int main() {
    float _Complex a;a = 0.0 + (__extension__ 0.0iF);
    float _Complex b;b = 0.0 + (__extension__ -0.0iF);
    float _Complex c;c = -0.0 + (__extension__ 0.0iF);
    float _Complex d;d = -0.0 + (__extension__ -0.0iF);
    printf("a= 0x%016llx\n", *(long long*)(&a));
    printf("b= 0x%016llx\n", *(long long*)(&b));
    printf("c= 0x%016llx\n", *(long long*)(&c));
    printf("d= 0x%016llx\n", *(long long*)(&d));
}

$ gcc-4.5.2 -w -std=c99 zero1.c ; ./a.out
a= 0x0000000000000000
b= 0x0000000000000000
c= 0x0000000000000000
d= 0x0000000080000000

$ gcc-4.5.2 -w zero1.c ; ./a.out
a= 0x0000000000000000
b= 0x8000000000000000
c= 0x0000000000000000
d= 0x8000000080000000


2 commentaires

Il est potentiellement pertinent que sans ASTD = option GCC fonctionnera comme si vous aviez spécifié -STD = GNU89 ou -STD = GNU90 (ils sont identiques) afin que cela puisse être pertinent ici puisque les types _complex et _imaginaires sont de C99


Spudd86, non, le gcc -std = gnu99 était identique que juste gcc , comme je me souviens


5 Réponses :


1
votes

Cela concerne le comportement de point flottant IEEE tel que spécifié par la norme ISO C, qui est plus strict sur les zéros négatifs. La compilation d'une forme plus native permet au compilateur d'optimiser et de ne pas tenir compte des règles plus strictes, de telles choses.

addendum

Je ne me souviens pas des détails, mais cela est discuté en profondeur à l'annexe F de la norme ISO C99. PDF disponible à: http: //www.open-std .org / jtc1 / sc22 / wg14 / www / docs / n1124.pdf .

rétracté

Désolé, je me suis souvenu de mal. La norme ISO C ne dicte apparemment rien des zéros négatifs. Il est probablement à voir avec la manière dont les opérations IEEE FP sont strictes.


7 commentaires

L'annexe F de N1256 ne dit rien sur zéro négatif dans une partie imaginaire du complexe.


Désolé, je pensais que je me suis souvenu de ça. Il s'agit probablement d'une opération de comportement IEEE strict, puis.


LoadMaster, existe-t-il un PDF IEEE754 gratuitement disponible (E.G. Draft)?


Désolé, je ne peux pas localiser un. Quelqu'un avec Google-Fu plus puissant que moi peut probablement.


IEEE 754 n'aide pas, car il ne couvre pas les valeurs complexes ni l'arithmétique complexe.


Correct; IEEE-754 ne couvre pas l'arithmétique complexe (ni la norme d'origine de 1985 ni la norme révisée 2008). C99 Annexe G (surtout le signe de zéro) repose principalement autour des idées énoncées dans le papier de Kahan: "Branchez les coupures dans le plan complexe; ou: beaucoup d'ADO à propos de la signification de rien" (non disponible en ligne aussi loin que je suis conscient, malheureusement). L'annexe G n'est toutefois pas normative.


Voir << a href = "http://754r.ucbebest.org/" rel = "nOfollow noreferrer"> 754r.ucbbebest.org > pour le texte du 754-1985 et un brouillon (version 1.2.5 ) de 754-2008; Certaines changements importants ont été modifiés avant la version finale (1.9.0).



1
votes

Utilisation de

GCC version 4.7.0 20110504 (expérimental) (GCC) (GCC)

sur cible: x86_64-inconnu-linux-gnu

Avec et sans -std = c99 impression xxx

donc je suppose que ceci est un bug de 4.5.2 qui a depuis été corrigé. Peut-être une recherche dans les listes de bugzilla et / ou de courrier gcc p>

Edit2 Le signe de la partie réelle de C est perdu car l'initialisateur contient une addition afin que l'expression soit évaluée comme type flottant _complex, donc xxx

AS -0,0 + 0,0 est 0,0, sauf si le mode arrondi est rond vers une infinité négative.

Par conséquent, pour générer le littéral (-0, 0), vous avez besoin de quelque chose comme xxx

Voir aussi PR 24581


5 commentaires

Non, Mystère principal est de trouver des documents normatifs sur la droite ( Standard ) Comportement . De plus, les liens vers des bus / maillistes de GCC sont les bienvenus, à la fois pour les changements de 4.7.0 et à ~ 4,5 (GCC <4.4 n'a pas enregistré le signe de la partie imaginaire, il doit donc y avoir plusieurs correctifs). J'ai fait des recherches (peu) dans Maillist, mais ne trouvez rien.


Selon C99 (N1256 ANNEXE G) Les valeurs complexes ont la même sémantique pour les zéros signés que les parties constitutives réelles isolément. Ainsi, il semble clair que c'est un bogue dans la GCC.


... c'est-à-dire que l'annexe G ne contient rien qui suggérerait que la mise en œuvre est autorisée à gérer les zéros signés différemment dans des variables complexes que dans de véritables variables.


Après une creuse supplémentaire, il n'y a pas de bogue dans la GCC actuelle. J'ai édité mon post en conséquence.


Quelle est la bonne façon d'initialiser la variable _complex avec (+ 0 -0.0i) ?



3
votes

Si une mise en œuvre est conforme à l'annexe G et implémente les types _imaginy code>, l'expression xxx pré>

est évaluée comme (double) 0,0 + (double _Imaginaire) (- 0.0i) code> en fonction des règles de G.5.2 et des rendements 0,0 - 0.0i code>. P>

si la mise en œuvre ne fournit pas de _Imaginary code> type (qui est autorisé) ou ne correspond pas à l'annexe G (également autorisée), cette expression est généralement évaluée comme suit: p> xxx pré>

parce que 0.0 - 0.0 code> est zéro em> zéro dans l'arrondi par défaut IEEE-754, la signature est perdue. P>

morale de l'histoire: si vous vous souciez du signe de zéro, n'utilisez pas d'arithmétique dans des initialiseurs complexes. Puisque vous utilisez GCC, vous pouvez le faire à la place: P>

__real__ c =  0.0f;
__imag__ c = -0.0f;


0 commentaires

3
votes

fait _imaginy_i * -0.0 fonctionne mieux que (__ extension__ -0.0if) ?

La norme C1X à venir inclura le CMLLX macros, qui "agissent comme si les types imaginaires pris en charge et les définitions étaient:
#define cmplx (x, y) ((double complexe) ((double) (x) + _imaginy_i * (double) (y) (Y)))) . "

voir N1570 , §7.3. 9.3.


2 commentaires

Si c'est défini, ce sera dans ; Avez-vous inclus cela?


Oui, complexes.h a été inclus, mais c'est de très vieux glibc.



0
votes

de l'annexe J (problèmes de portabilité):

J.1 Comportement non spécifié
  1. Les éléments suivants sont non spécifiés:
    [...]
    - si [...] un zéro négatif devient un zéro normal lorsqu'il est stocké dans un objet (6.2.6.2).

    Cela va faire ce que vous voulez juste que plus compliqué.


1 commentaires

J'ai testé mes compilateurs (5+) et chaque compilateur est capable de stocker une plaine de +0 ou -0 dans n'importe quelle partie du complexe, à la fois imaginaire et réel. Donc, le 6.2.6.2 est pour le soutien optionnel de zéro signé et ce support est ici dans chaque compilateur testé.