0
votes

Détournez la représentation binaire du nombre de points flottants -0.0

Je fais un programme pour vérifier le signe d'un numéro de double / flotteur, tout d'abord, je jette tout d'abord le pointeur du nombre dans une longue int, alors je vérifie le piqué de signalisation s'il est 0 ou 1. Je ne le fais pas Comprenez pourquoi l'impression du bit de signalisation avec cette opération * Pointeur >> 63 est -1 au lieu de 1? (En supposant que * Pointeur est le INT64_T que j'ai lancé mon double / flotteur dans)

Ceci est le code complet: P>

    double d = -0.0;
    int64_t *pointer = (int64_t *) &d;
    if (*pointer >> 63)
       printf("negative number\n");
    else
       printf("positive number\n");
    // if i print the result of (*pointer >> 63), it gives me -1
    // so how can this go inside my if condition?


7 commentaires

intz_t * pointeur = (int64_t *) & d; est un comportement non défini en raison de la stricte règle d'aliasing.


Qu'entendez-vous par règle d'aliasing stricte?


Lisez-vous What-the-strict-aliasing-règle


En C, il est explicitement autorisé à utiliser un «code> union pour type punning (à la suite de la règle d'aliasing stricte).


Évitez d'utiliser des entiers signés avec des opérations de changement de bits. Depuis que le bit de signalisation a une signification particulière, cela n'agit pas comme "un peu". Les entiers non signés sont plus proches de «juste des bits simples» et sont donc généralement plus appropriés pour les opérations biteux. Le changement de droite une valeur négative est défini par la mise en œuvre. Votre implémentation, comme beaucoup, réplique le bit de signalisation tel qu'il change. Dans un entier signé, cela provoque 10000 ... 0000 pour devenir 11111 ... 1111, qui représente -1.


déplacer un entier signé 64 bits par 63 endroits à droite est U.B. Pourquoi ne cochez-vous pas simplement le bit en le masquant avec si (* pointeur et 0x800000000000000000) ???


Vous pouvez simplement vérifier si (* pointeur <0) car le bit de signe dans un intz_t integer est au même endroit que le bit de signalisation dans un double .


3 Réponses :


3
votes

Ceci est difficile à faire en pleine généralité en raison de l'existence de zéros signés dans des types de points flottants et la possibilité de compléter les types d'intégration de 1.

Mis à part l'indéfinie de (intz_t *) & d (que vous pouvez adresser avec un "code> union type-pun), cette approche retournera le mauvais signe pour -0.0 .

Heureusement, vous pouvez utiliser Signat () à partir de math.h qui implémente probablement la fonction de manière non portable.


0 commentaires

0
votes

Premièrement, le changement d'entier négatif est défini la mise en œuvre. La déséroferience suivante Un pointeur d'un type différent du type réel est un comportement explicitement non défini en raison de la règle d'aliasing stricte (Google pour cela que vous ne le savez pas).

Si vous voulez que votre code soit portable, le seul moyen infaillible est d'utiliser MEMCY pour transporter la représentation de la valeur. Cela suppose seulement que:

  • Tailleof (Double) est identique à celui Tailleof (uint64_T) :
  • Le bit de signe est bit63 d'un uint64_t ayant cette représentation

    code: xxx


2 commentaires

@Numlock vous obtenez toujours -1?


J'obtiens 0, car un long double est supérieur à 64 bits, je pense!



0
votes

Alors, comment cela peut-il aller à l'intérieur de ma condition si? p>

1 Utilisez Signbit (d) code> p> xxx pré>

ou p>

2 Utilisez un composé littéral et Union .

// Test size
_Static_assert(sizeof(int64_t) == sizeof(double), "Mis-match size");


1 commentaires

Salut! Je ne comprends pas cette syntaxe: Si ((Union {double DD; INT64_T I64;}) {.dd = d} .i64 <0), pouvez-vous s'il vous plaît; TY!