8
votes

Comment byteswap un double?

J'essaie d'écrire une routine de byteswap pour un programme C ++ en cours d'exécution sur Win XP. Je compile avec Visual Studio 2008. C'est ce que j'ai proposé: xxx pré>

et une fonction à tester: p> xxx pré>

Obtenir ces chiffres ne correspondant pas: P>

-76.789999999988126 -76.790000000017230 0.000000000029104  
-30.499999999987718 -30.499999999994994 0.000000000007276  
 41.790000000014508  41.790000000029060 -0.000000000014552  
 90.330000000023560  90.330000000052664 -0.000000000029104


3 commentaires

Pourriez-vous clarifier ce qui a été inventé exactement dans la Quake 2? Sûrement pas l'idée d'avoir un double et un INT64 en tant que champs de la même union?


Désolé .. j'ai appris C de côté de la Quake2, j'aime donc prétendre que c'est le plus grand: D Je le vois (union) partout maintenant.


Associé: Stackoverflow.com/Questions/32573923/bylte-swap -with-an-array


5 Réponses :


6
votes

Bien qu'un double dans la mémoire principale est de 64 bits, sur X86 Les registres de double précision CPus sont de 80 bits de large. Donc, si l'une de vos valeurs est stockée dans un registre dans l'ensemble, mais l'autre fait un aller-retour à la mémoire principale et est tronqué à 64 bits, cela pourrait expliquer les petites différences que vous voyez.

Peut-être que vous puissiez forcer les variables à vivre dans la mémoire principale en prenant leur adresse (et en l'imprimant, pour empêcher le compilateur de l'optimiser), mais je ne suis pas certain que cela est garanti de travailler.


1 commentaires

+1: Je pense que c'est ce qui se passe ici: "A" est détenir dans un registre et est incrémenté là-bas alors que "C" est en mémoire.



5
votes
    b = byteswap(a);
That's a problem.  After swapping the bytes, the value is no longer a proper double.  Storing it back to a double is going to cause subtle problems when the FPU normalizes the value.  You have to store it back into an __int64 (long long).  Modify the return type of the method.

2 commentaires

Cela a du sens! D'accord, je vais regarder dans ça et vous revenir à vous


@Hans, je pense que vous êtes sur quelque chose ici. J'en ai fait mention dans ma réponse ici: Stackoverflow.com/a/64056527/4561887 . Je ne comprends pas complètement moi-même.



1
votes

ESSAYEZ 2

D'accord, ça marche! Hans Passant avait raison. Ils m'ont fait penser avec le commentaire "non plus double". Donc, vous ne pouvez donc pas bytewap un flotteur dans un autre float car il peut s'agir d'un format inapproprié, vous devez donc byteswap à un tableau de charcuterie et de retourner. Ceci est le code que j'ai utilisé: xxx

et une fonction de test simple: xxx


0 commentaires

5
votes

ESSAYE 3

D'accord, découvrez qu'il y a une meilleure façon. L'autre façon, vous devez vous inquiéter de l'ordre que vous emballez / décompressez des choses. De cette façon, vous ne: xxx

envoyer: xxx

recv: xxx < / pré>


3 commentaires

Débarrassez-vous de ceci: memcpy (in, v, 4); et simplement copier-swap directement dans out à partir de v , puis memcpy Les valeurs échangées de out dans v . Cela vous permet d'économiser une copie inutile en réduisant vos copies de l'ensemble de la matrice de 3 à 2.


Il existe également une optimisation supplémentaire pour réduire les copies de l'ensemble de la matrice de 2 à 1,5: Copier la moitié gauche de la matrice en variables temporaires et la moitié droite du tableau droit dans la moitié gauche, échangeant de manière appropriée. Ensuite, copiez des variables temporaires, qui contiennent l'ancienne moitié gauche de la matrice, dans la moitié droite du tableau, échange de manière appropriée. Cela se traduit par l'équivalent de seulement 1.5 opérations de copie de l'ensemble de la matrice, pour être plus efficace. Faites tout cela sur place dans la matrice d'origine, mis à part les variables temporaires dont vous avez besoin pour la moitié de la matrice.


Voir ma réponse: Stackoverflow.com/a/64056527/4561887



0
votes

Comment échanger les octets en place dans n'importe quel tableau, variable ou tout autre bloc de mémoire

(tel qu'un int16_t , uint16_t , uint32_t , float , double , etc.):

Voici un moyen d'améliorer l'efficacité de l'efficacité de 3 TOUTES COPY Opérations du tableau à 1.5 Opérations de copie enbles de la matrice. Voir aussi les commentaires que j'ai laissés sous votre réponse . xxx

utilisation : xxx

note, cependant, que @Hans Passant semble être sur quelque chose ici . Bien que ce qui précède fonctionne parfaitement sur tout type signé ou non signé entier et semble fonctionner sur float et double pour moi aussi, cela semble être cassé sur double long . Je pense que c'est parce que quand je stocke le double double retour dans un double variable , s'il est déterminé à être pas-a-valide long double Représentation plus, quelque chose change automatiquement quelques-uns des octets échangés ou quelque chose. Je ne suis pas tout à fait sûr.

sur de nombreux systèmes 64 bits, Long Double est de 16 octets, donc peut-être que la solution consiste à conserver la version échangée du long Double à l'intérieur d'un tableau de 16 octets et ne tentez pas de l'utiliser ou de le jeter à un Double à partir du tableau uint8_t 16 octet jusqu'à a) Il a été envoyé au récepteur (où l'endansion du système est opposée, de sorte qu'il est en forme maintenant) et / ou b) d'octet-levé à nouveau de sorte que c'est un double valide double à nouveau. < / p>

Gardez TH ci-dessus à l'esprit au cas où vous voyez des problèmes avec float ou double Types, comme je le vois avec seulement Long Double types.


0 commentaires