C++ SSE舍入精度

C++ SSE舍入精度,c++,optimization,rounding,sse,C++,Optimization,Rounding,Sse,我有一个小问题。代码是不言自明的,我试图获得293.05694580中0.0001s的计数,包括一些舍入(例如,5.21中有52个0.1s) #包括 #包括 内部主(空) { 浮动值=(浮动)293.05694580; 浮动大小=(浮动)0.0001; __m128 _val=_mm_set_ps1(val); __m128 _shift=_mm_set _ps1(1/尺寸); /*293.0569480*10000应为2930569.480*/ __m128 _mul=_mm_mul ps(_

我有一个小问题。代码是不言自明的,我试图获得293.05694580中0.0001s的计数,包括一些舍入(例如,5.21中有52个0.1s)

#包括
#包括
内部主(空)
{
浮动值=(浮动)293.05694580;
浮动大小=(浮动)0.0001;
__m128 _val=_mm_set_ps1(val);
__m128 _shift=_mm_set _ps1(1/尺寸);
/*293.0569480*10000应为2930569.480*/
__m128 _mul=_mm_mul ps(_val,_shift);
/*取整2930569.480应该得到2930569,但返回2930570。为什么*/
__m128i _ticks=_mm_cvtps_epi32(_mul);
}
最后,如何恢复_ticks中结果的顺序? 非常感谢,,
丹尼尔

检查中间结果,不要假设它

检查/设置sse舍入模式


要计算某些东西,请使用整数来提高性能和精度,也许您可以:

  • 仅在精度异常处理程序中使用双精度(取消掩码精度异常)
  • 如果要求是“美元美分需要X位数”,则可以将大的货币放入双数组,将小的货币放入浮点数组。在那之前,从X开始计算,你把它分成多少份

如果有人在乎,最后的代码是

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++;
}
};
inline void QTickCalcer::tickCountsFromDoubleArray(
常数双*src,int*dest,常数无符号int elemCount)常数
{
/*src和dest需要对齐*/
__m128i*r=(u m128i*)目的地;
__m128i-r1;
__m128i-r2;
__m128i-rTot;
__m128d*d1=(u m128d*)和src[0];
__m128d*d2=(u m128d*)和src[2];
__m128d-tmp1;
__m128d-tmp2;
for(寄存器无符号整数i=0;i_d换档器);
tmp2=_mm_mul_pd(*d2,此->_d换档器);
/*交织-http://msdn.microsoft.com/en-us/library/c8c5hx3b(v=vs.71)。aspx*/
r1=_mm_cvtpd_epi32(tmp1);
r2=_mm_cvtpd_epi32(tmp2);
rTot=mm_Unplo_epi32(r1,r2);
/*洗牌以匹配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++;
}
};

谢谢你的评论。

这与苏格兰和南方能源公司无关。这只是常见的浮点陷阱。@CAFxY:你能详细介绍一下可维护和可工作的代码吗?我渴望学习,但正如我在下面所写的,我通常会执行一万亿次或更多,所以我需要它的速度,因此SSE。@Mystical:所以应该有一个简单的解决方法,对吗?@DanBencik:不太可能。解决方法是理解您的代码,这并不简单。并不是所有的值都可以用二进制(或十进制)表示法精确表示。因此,您需要以一种避免这种表示的方式编写代码,或者能够处理精度损失的方式Hey bla,“用于计算使用整数”-您的意思是从零开始递增一些临时值,直到我达到val,并记下递增的数量吗?我想做的这个操作通常要做一万亿次,占总运行时间的25%,所以我需要它的速度。如果你有其他的想法,我会很高兴学到一些新的东西。至于sse舍入模式,它通常应该设置为“舍入到最近的”(round to nearest),这是正确的。对不起,这不是我所说的计数。首先,你的打字错误是4580而不是480。您可能应该使用ss(单标量),而不是ps函数,或者根本不使用sse,它并不总是更快。您应该启动调试器(VisualC++),并通过它,查看舍入控制位并确保它设置为您喜欢的(FPU有默认值,但例如在插件开发中,您必须检查/设置)。你的例子给出了一个不精确的结果,它是正常的(精确标志指示这个BTW),2930569.5是不精确的,但预期的,舍入到最近的XX3057。对于MXCSR,可以看到MXCSR在Visual C++调试中。用c或sd/pd代替sse的ss/ps指令。在您的双精度示例中,最终结果可能是正确的。bla,谢谢您的建议。这个例子只使用一个数字,但是在现实生活中,我将在大型数组上计算这些值。因此,我需要使用SSE。至于double/float,由于显而易见的原因,float的性能大约是double/float的两倍。我已经做了双打,SSE的加速比是普通码的10倍,所以我很高兴。但也非常感谢你*r=(tmp1),(tmp2),;
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++;
}
};