0
votes

Conversion entre les nombres à virgule fixe de 64 bits et 32 ​​bits

Comment convertir des données du format Q33.31 au format Q2.30? Je sais que nous devons utiliser des opérateurs de décalage si l'entrée et la sortie sont de même taille. Mais comment calculer si elles sont de taille différente?


4 commentaires

Vos données peuvent-elles être converties sans perdre la plupart des bits significatifs? (En supposant qu'une perte de bit la plus faible n'est pas significative.)


Non. Une partie des données sera perdue. Ce n'est pas un problème


Ici, j'ajoute simplement deux nombres de bits Q1.31. Et je veux que la sortie soit au format Q2.30. Pour ce faire, je stocke le résultat en variable 64 bits (Q33.31), puis en essayant de convertir en Q2.30. Mais comment convertir cela? Si je me suis laissé sur 31 bits, le résultat s'avère au format Q2.62. De nouveau, de 32 bits, le transfert de 32 bits a lieu à Q34.30 / Q2.30? Est-ce le processus correct?


Vous n'avez pas besoin de faire un ajout de 64 bits dans ce cas. Tout peut être fait en mathématiques 32 bits. Voir ma réponse


3 Réponses :


0
votes

Que diriez-vous:

uint32_t convert(uint64_t x)
{
    uint32_t hi = (uint32_t)(x >> 32);
    uint32_t lo = (uint32_t)(x);
    if (hi >= (1 << 2) || lo >= (1 << 30))
        // handle input-too-large-or-too-accurate error and exit
    return (hi << 30) | lo;
}


7 commentaires

Bonjour, pouvez-vous expliquer ce que vous faites dans la condition si?


@RKC: Je ne fais rien. Je l'ai laissé pour vous de déterminer, car vous n'avez pas encore spécifié l'exigence de ce scénario de votre question (c.-à-d. Évidemment, vous ne pouvez évidemment pas correspondre à chaque combinaison 64 bits dans une unité de stockage 32 bits, de sorte que si < / Code> attrape tous ces cas où vous perdrez des informations au cours de cette conversion).


Bonjour, j'ajoute simplement deux numéros Q1.31 et stocker le résultat dans un numéro de 64 bits. Plus tard, je souhaite convertir au format Q2.30 à nouveau.


@RKC: J'ai ajouté une alternative pour que vous puissiez simplement ignorer la perte d'informations. Voir la réponse mise à jour.


La conversion entre un format ".31" et un format ".30" se transforme principalement sur 1 bit droite (ainsi que l'arrondissement et le débordement de la manutention). Ce code change hi 2 bits à droite (NET, premier décalage 32 puis à gauche 30) et ne déplace pas lo du tout. Comment cela a-t-il de sens?


@Ericpostpischil: le déplaçant un bit, comme cela peut entraîner le bit le plus élevé (lorsqu'il est réglé sur 1) pour contaminer le bit le plus bas de la partie entière lors du ornement des deux parties. Mais vous avez raison dans le fait que j'ai éliminé le bit le plus significatif au lieu du moins important, que j'ai essayé d'éviter pour des cas où aucun peu doit être éliminé. Dans tous les cas, j'ai ajouté la deuxième partie de la réponse plus tard. Voyez-vous des problèmes avec la première partie de celui-ci (en dehors de ne pas dire comment la perte de données devrait être traitée, car il n'y a aucune condition de spécification pour cela dans la question)?


Si l'entrée (paramètre x ) est un seul numéro Q33.31, puis sur le déplacement de tout cela à droite 1 bit ne contamine pas la partie basse; Il déplace un bit désiré dans le bit bas. Si l'entrée est un nombre 64 bits contenant deux numéros Q2.30 32 bits (que l'OP souhaite ajouter), le décalage net de la partie haute par deux bits est fausse; Il ne devrait y avoir aucun changement (par rapport au mot 32 bits) (et les pièces seraient ajoutées, non orées). De toute façon, cette réponse est fausse.



2
votes

Dans un commentaire sur la réponse de @ Goodvibration Vous déclarez que vous ajoutez deux numéros Q1.31. Étant donné que, vous savez que votre résultat est représentable en tant que Q2.31, afin de convertir votre numéro Q2.31 en Q2.30, vous devez simplement modifier le résultat à droite par un bit:

uint32_t convert_q231_q230(uint64_t x)
  {
  return (uint32_t) (x >> 1);
  }


3 commentaires

Si nous stockons le résultat dans une variable 32 bits après avoir ajouté deux valeurs Q1.31 (considérez le débordement durera), le résultat sera corrompu? Comment vous indiquez que le résultat sera au format Q2.31?


Vous avez dit que vous stockiez le résultat de l'ajout des deux valeurs Q1.31 dans une variable de 64 bits en tant que valeur Q33.31. Vous devriez lancer les vals Q1.31 sur 64 bits avant pour effectuer l'addition. En ce qui concerne "Comment savoir ce sera le format Q2.31" - L'ajout de deux entiers non signés 32 bits ne peuvent que déborder d'un bit - ainsi, vous obtiendrez une valeur Q2.31 (33 bits).


Vous pouvez également modifier vos valeurs Q1.31 à droite d'un bit avant de les ajouter, ce qui entraîne des valeurs Q2.30. Ajoutez ensuite ces deux valeurs Q2.30, que vous savez avoir au maximum une 1 dans les deux bits à haut ordre, et votre résultat sera Q2.30 sans jamais avoir à passer par une conversion 64 bits. Cela vient au coût d'une éventuelle perte de précision si vous avez déplacé une seule des bits à faible ordre des valeurs d'origine.



3
votes

La clé ici est juste déplacer le point Radix au bon endroit em>. Prenez un exemple simple à partir du format Q9.7 à Q2.6 comme celui-ci

uint32_t A2_30 = A1_31 >> 1; // types must be unsigned so that the shifts are logical
uint32_t B2_30 = B1_31 >> 1; // instead of arithmetic

// if only one of the values is 1 then their sum is 0.5 ULP which will be rounded to 1
uint32_t carry = (A1_31 & 1) | (B1_31 & 1); // if both of them are 1 then sum = 1 ULP

Q2_30 sum = A2_30 + B2_30 + carry;


0 commentaires