C++ SSE舍入精度
我有一个小问题。代码是不言自明的,我试图获得293.05694580中0.0001s的计数,包括一些舍入(例如,5.21中有52个0.1s)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.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++;
}
};