8
votes

Contraindre flotter dans un bloot non signé au bras vs. Intel

Lorsque j'exécute le code C suivant sur une machine Intel ... xxx pré>

... La sortie est la suivante: p> xxx pré> Cependant, lorsque j'exécute le même code sur un appareil à bras (dans mon cas, un iPad), les résultats sont assez différents: P>

-512.000000 -> 0
-448.000000 -> 0
-384.000000 -> 0
-320.000000 -> 0
-256.000000 -> 0
-192.000000 -> 0
-128.000000 -> 0
-64.000000 -> 0
0.000000 -> 0
64.000000 -> 64
128.000000 -> 128
192.000000 -> 192
256.000000 -> 0
320.000000 -> 64
384.000000 -> 128
448.000000 -> 192
512.000000 -> 0


3 commentaires

Je ne connaissais pas très bien ce genre de choses, mais ma première réaction est que c'est une mauvaise idée d'essayer de contraindre un flotteur dans un caractère non signé sur n'importe quelle plate-forme sur n'importe quelle architecture.


Je ne suis pas d'accord avec toi Brian. La précision n'est pas un problème ici, mais la performance est. J'utilise la nature "Emballage" du caractère non signé pour rester dans les 0-255 frontières. Ceci est, Afaik (et ont lu plusieurs articles) non pas une technique rare.


@ZMIPPIE: Le comportement que vous voyez est la nature "saturation", qui est assez courante par ex. Ensembles d'instructions SIMD.


3 Réponses :


1
votes

Je vais répondre à 3 dans ma propre question mais ne signalera pas cela comme la réponse acceptée. L'astuce semble être un simple casting dans la coercition: xxx

utiliser (int) ou (court) fonctionne aussi. Je suis toujours intéressé de savoir où se trouve la cause de ce problème: compilateur ou processeur.


1 commentaires

Notez que ce n'est pas réellement un correctif portable. Vous êtes dans un comportement indéfini dès que vous dépassez la plage représentable du type de destination pour toute conversion du flotteur entier. Si vous voulez vraiment Garantie Comportement multi-plateformes, vous pouvez faire quelque chose comme c = f <0? 0: F> uchar_max? Uchar_max: f; , mais même cela ne perturbe pas le comportement des nans.



-1
votes

Le problème spécifique que vous avez affaire à l'endansion. Essayez de remplacer l'une ou l'autre implémentation avec C = * ((char *) et F + taille de taille de (flotteur) - 1); ou quelque chose de similaire pour obtenir le dernier octet du flotteur et voir s'il correspond à le résultat pour l'autre plate-forme.

En général, le comportement dépendra de l'endansnité, de la longueur des mots et des capacités de points flottants du processeur et de la manière dont le compilateur cible cela. Le bras est bi-endian, de sorte que cela pourrait ou ne pas correspondre à la commande IA octet. Il semble qu'il n'y ait pas non plus de garantie générale qu'une implémentation C prend en charge le même format de point flottant que d'autres: fixe- Taille Types de points flottants .

Utilisez-vous cela dans le code de production? Je serais très fort pour la raison pour laquelle cela doit être fait. Un ou l'autre type n'est probablement pas utilisé comme prévu. Les solutions de contournement ne vont pas être élégantes.


1 commentaires

L'endansion n'affectera pas ce problème. En outre, le processeur iPad et les croustilles Intel sont à la fois petit-Endian.



9
votes

La norme C n'a pas de règles très difficiles pour ce que vous essayez de faire. Voici le paragraphe en question, de la section 6.3.1 opérandes arithmétiques (spécifiquement section 6.3.1.4 réel flottant et entier ):

Lorsqu'une valeur finie de type flottant réel est convertie en un type d'entier autre que _bool , la partie fractionnée est rejetée (c.-à-d. La valeur est tronquée vers zéro) . Si la valeur de la partie intégrale ne peut pas être représentée par le type entier, le comportement est indéfini.

Il y a même une note de bas de page plus spécifique sur le cas exact que vous posez sur:

L'opération de reste effectuée lorsqu'une valeur de type entier est convertie en type non signé, il n'est pas nécessaire de ne pas être effectuée lorsqu'une valeur de type flottant réel est convertie en type non signé. Ainsi, la gamme de valeurs flottantes véritables portables est (- 1, utype_max + 1) .

utypemax + 1 pour votre cas est 256 . Vos cas incompatibles sont tous des nombres négatifs. Après la troncature, ils sont toujours négatifs et sont en dehors de la plage (-1, 256), de sorte qu'ils sont fermement dans la zone de «comportement indéfini». Même certains des cas correspondants que vous avez montrés, où le numéro de point flottant est supérieur ou égal à 256 , ne sont pas garantis pour travailler - vous obtenez juste de la chance.

Les réponses à vos questions numérotées, donc:

  1. Oui, tu as eu tort.
  2. C'est un problème de compilateur dans le sens où vos différents compilateurs donnent des résultats différents, mais comme ils sont autorisés par la spécification, je n'appellerais pas vraiment que la faute du compilateur.
  3. Cela dépend de ce que vous voulez faire - si vous pouvez expliquer cela mieux, une personne sur cette communauté est presque certaine de pouvoir vous aider.

2 commentaires

Exactement. Ceci est un comportement indéfini, simple et simple.


Merci pour les réponses les gars (le commentaire de Stephen Canon à ma propre réponse ci-dessous). Je vais probablement mettre la valeur du flotteur dans une gamme saines avant la coercition, à partir de vos commentaires, je comprends que c'est une mauvaise pratique de compter sur le «comportement indéfini».