SSE точность округления

У меня небольшая проблема с округлением SSE. Код не требует пояснений, я пытаюсь получить число 0,0001 с в 293,05694580, включая некоторое округление (например, 52 в 5,21) …

#include <xmmintrin.h>
#include <emmintrin.h>

int main(void)
{
float val       = (float) 293.05694580;
float tickSize  = (float)   0.0001;

__m128 _val     = _mm_set_ps1( val );
__m128 _shift   = _mm_set_ps1( 1 / tickSize );

/* 293.0569480 * 10000 should be 2930569.480 */
__m128 _mul     = _mm_mul_ps(_val, _shift);

/* Rounding 2930569.480 should get 2930569, but returns 2930570 instead. Why? */
__m128i _ticks  = _mm_cvtps_epi32( _mul );
}

Наконец, как я могу изменить порядок результатов в _ticks?
Большое спасибо,
Даниил

1

Решение

проверьте промежуточный результат, не принимайте его

проверить / установить режим округления

для подсчета чего-либо используйте целые числа

1

Другие решения

Окончательный код, если кого-то волнует, это

inline void QTickCalcer::tickCountsFromDoubleArray(
const double * src, int * dest, const unsigned int elemCount) const
{
/*  src and dest need to be align_malloced              */
__m128i * r  = (__m128i*)dest;

__m128i r1;
__m128i r2;
__m128i rTot;

__m128d * d1 = (__m128d*) & src[0];
__m128d * d2 = (__m128d*) & src[2];

__m128d tmp1;
__m128d tmp2;

for ( register unsigned int i = 0; i < elemCount/4; i++ )
{
tmp1    = _mm_mul_pd( *d1,  this->_dshiftor);
tmp2    = _mm_mul_pd( *d2,  this->_dshiftor);

/*  Interleave - http://msdn.microsoft.com/en-us/library/c8c5hx3b(v=vs.71).aspx                 */
r1  = _mm_cvtpd_epi32 ( tmp1 );
r2  = _mm_cvtpd_epi32 ( tmp2 );
rTot = _mm_unpacklo_epi32 ( r1, r2 );

/*  Shuffle to match the ordering in src - http://software.intel.com/en-us/forums/topic/309988  */
*r = _mm_shuffle_epi32( rTot, _MM_SHUFFLE(3,1,2,0));

d1 += 2;
d2 += 2;
r++;
}
};

Спасибо за все комментарии.

1

Для производительности и точности, возможно, вы могли бы:

  • использовать двойную точность только в обработчике исключений точности (снимите маску с исключений точности)
  • если требование «нужно X цифр для долларовых центов», вы можете поместить большие деньги в двойные массивы, а небольшие — в массивы с плавающей точкой. перед этим рассчитать по X на какое число вы его разбили
0
По вопросам рекламы [email protected]