Apprentissage du C : un problème déroutant de décalage de nombres non signés

Apprentissage du C : un problème déroutant de décalage de nombres non signés

fond de problème


Lors du processus de décalage en virgule fixe d'un algorithme, j'ai rencontré un problème étrange : le décalage à droite par des nombres non signés et signés respectivement, et les résultats de res1 et res2 sont les mêmes quelle que soit l'entrée. code afficher comme ci-dessous:

    int64_t tmp = -16;
    int32_t res1 = (int32_t)(((uint64_t)tmp) >> 1);
    int32_t res2 = (int32_t)(tmp >> 1);
    if (res1 != res2) {
    
    
        printf("res1=%d, res2=%d\n", res1, res2);
    }

D'après l'analyse du blog précédent, C learning : analyse et résumé du problème de décalage des nombres non signés et signés , ce n'est pas conforme à la science, ce qui équivaut à l'analyse à l'aveugle du blog précédent.

Analyse de validation


Ensuite, j'ai vérifié les changements individuels de tmp pour voir s'il y a une différence entre les changements non signés et signés. code afficher comme ci-dessous:

    int16_t a = -16;
    printf("0x%hx\n", a);
    a >>= 1;
    printf("0x%hx\n", a);
    printf("%d\n", a);

    a = -16;
    uint16_t b = (uint16_t)a;
    printf("0x%hx\n", b);
    b >>= 1;
    printf("0x%hx\n", b);
    printf("%hu\n", b);

D'après les résultats de la vérification auxiliaire, on peut voir que lors du décalage par nombre signé, le bit de signe change, ce qui montre que l'analyse de blog précédente est correcte.

Voici le problème. . .

Théoriquement, dans la deuxième ligne du premier code, la conversion 64 bits non signée forcée **(uint64_t)** est ajoutée. Le résultat du décalage doit être différent du résultat de la troisième ligne. Pourquoi res1 et res2 sont-ils égaux ? encore?

Donc, après avoir démonté davantage le premier morceau de code, j'ai trouvé la réponse.

    int64_t tmp = -16;
    int64_t a;
    uint64_t b;
    a = tmp >> 1;
    b = ((uint64_t)tmp) >> 1;
    printf("0x%llx\n", a);
    printf("0x%llx\n", b);

    int32_t res1 = (int32_t)b; // 31 shift
    int32_t res2 = (int32_t)a;
    printf("res1=%d, res2=%d\n", res1, res2);

insérez la description de l'image ici

Le résultat du décalage tmp est en effet différent, mais la clé du problème est la troncature . Lors de la troncation de 64 bits à 32 bits, les octets inférieurs de 32 bits sont pris, de sorte que les résultats sont cohérents. Donc, les points de connaissance les plus importants ici sont de consulter le blog C Learning: Analysis of Integer Expansion Problems with Different Bit Widths .

En bref, il y a bien une différence dans le résultat après le décalage du nombre signé, mais cette différence est masquée après la troncature.La clé réside dans le principe de conversion des données de grande largeur en données de faible largeur. Il convient de noter que s'il y a trop de chiffres décalés, il peut encore y avoir des différences après troncature. Par exemple, dans le code ci-dessus, si tmp est affecté d'une valeur de -2147483648 et décalé vers la droite de 33 bits, le résultat sera ont une énorme différence.

Un autre problème notable est qu'en pratique, le décalage vers la droite et le décalage vers la gauche sont souvent utilisés pour remplacer la multiplication et la division par des puissances de 2, mais dans les scénarios de nombres signés, en raison de la relation entre les compléments négatifs, c'est souvent contraire aux attentes. Par exemple, si -2 est décalé de deux bits vers la droite, s'il est traité comme un décalage arithmétique, le résultat n'est pas égal au quotient divisé par 4, qui est 0, mais -1. De plus, lorsque le décalage vers la droite est supérieur ou égal à deux bits, le résultat est toujours -1. Par conséquent, dans la scène où le quotient est de 0 après le décalage, vous devez faire attention à ce qu'il réponde aux attentes.

Les références


  1. Apprentissage C : analyse des problèmes d'expansion d'entiers avec différentes largeurs de bits, lien
  2. Apprentissage du C : Analyse et résumé du problème de décalage des nombres non signés et signés, lien

Je suppose que tu aimes

Origine blog.csdn.net/qq_17256689/article/details/129962079
conseillé
Classement