2 votes

AVX/SSE arrondissent les flottants vers le bas et renvoient un vecteur d'ints ?

Existe-t-il un moyen d'utiliser AVX/SSE pour prendre un vecteur de flottants, arrondir à l'inférieur et produire un vecteur d'ints ? Toutes les méthodes intrinsèques de floor semblent produire un vecteur final en virgule flottante, ce qui est étrange car l'arrondi produit un entier !

3voto

zx485 Points 12145

Une méthode simple consisterait à utiliser ce qui suit ROUNDPS et en appliquant ensuite l'instruction CVTPS2DQ pour convertir le float à mots entiers doubles signés . Le code ressemblerait à ceci :

; xmm0 is assumed to be packed float input vector
roundps  xmm0, xmm0, 3    ; truncate mode, see below as requested in comment on the other answer   
cvtps2dq xmm0, xmm0
; xmm0 now contains the (rounded) packed integer vector

Pour les vecteurs AVX ymm, préfixez les instructions par "V" et remplacez les xmm par des ymm.

ROUNDPS fonctionne comme suit

Arrondir les valeurs en virgule flottante de simple précision dans xmm2/m128 et placer le résultat dans xmm1. Le mode d'arrondi est déterminé par imm8.

le mode d'arrondi (l'opérande immédiat/le troisième opérande) peut avoir les valeurs suivantes (tirées du tableau 4-15 - Rounding Modes and Encoding of Rounding Control (RC) Field des documents actuels d'Intel) :

Rounding Mode               RC Field Setting   Description
----------------------------------------------------------
Round to nearest (even)     00B                Rounded result is the closest to the infinitely precise result. If two values are equally close, the result is nearest (even) the even value (i.e., the integer value with the least-significant bit of zero).
Round down (toward −∞)      01B                Rounded result is closest to but no greater than the infinitely precise result.
Round up (toward +∞)        10B                Rounded result is closest to but no less than the infinitely precise result.
Round toward 0 (truncate)   11B                Rounded result is closest to but no greater in absolute value than the infinitely precise result.

La raison probable pour laquelle le vecteur de retour de l'opération d'arrondi est float et non int Il se peut que, de cette manière, les autres opérations puissent toujours être des opérations sur les flottants (sur des valeurs arrondies) et une conversion en int serait trivial, comme indiqué.

Les éléments intrinsèques correspondants se trouvent dans les documents référencés. Un exemple de transformation du code ci-dessus en éléments intrinsèques (qui dépendent de l'élément Rounding Control (RC) Field ) est :

__m128 dst = _mm_cvtps_epi32( _mm_floor_ps(__m128 src) );

En appliquant simplement une opération de "troncature" au fichier float du vecteur en les arrondissant à l'entier précédent le plus proche de zéro, une seule instruction/intrinsèque suffirait :

cvttps2dq xmm0, xmm0

ou comme intrinsèque :

__m128i _mm_cvttps_epi32(__m128 a)

1voto

doug65536 Points 1230

Utiliser les instructions de conversion :


int _mm_cvt_ss2si (__m128 a)

Convertit la composante flottante 32 bits de bas niveau de a en entier et renvoie cet entier. Les trois composantes supérieures de a sont ignorées.


__m128i _mm_cvtps_epi32 (__m128 a);

Convertit les quatre nombres flottants 32 bits en nombres entiers et renvoie un vecteur de 4 nombres entiers 32 bits.


Ce sont les plus fréquemment utilisés. Il y a variations supplémentaires pour gérer les conversions.

1voto

Peter Cordes Points 1375

Options d'instruction unique :

  • tronquer vers zéro : __m128i _mm_cvttps_epi32(__m128 a)
  • arrondir à la valeur la plus proche : __m128i _mm_cvtps_epi32(__m128 a)

Deux instructions, utilisant SSE4.1 ROUNDPS puis cvtps_epi32

  • Rond vers -INF : __m128 _mm_floor_ps(__m128 s1)
  • Rond vers +INF : __m128 _mm_ceil_ps(__m128 s1)

N'utilisez que les autres formes tronquées ou les formes les plus proches de roundps si vous souhaitez conserver les données au format FP.


Pour les nombres positifs, la troncature et le plancher sont identiques. Pour les nombres entiers négatifs, cvtt(-4.9) = -4 mais floor(-4.9) = -5.0 . Voir floorf() vs. truncf() .


Si la valeur de la PF est en dehors de l'intervalle INT_MIN a INT_MAX gamme, cvttps y cvtps vous donnera 0x80000000 (c'est-à-dire INT_MIN (juste le bit de signe), qu'Intel appelle la valeur "integer indefinite". Il soulèvera également l'exception FP invalid, mais les exceptions FP sont masquées par défaut.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X