在使用MSVC2013的x64 Windows上,我使用的是OpenCV的cvRound
功能,目的是从x.5
值向上舍入。我发现cvRound(17.5f)
返回18
(好!)的不一致,但cvRound(20.5f)
按预期返回20
而不是21
cvRound因此被简单实现,因此它似乎是_mm_cvtsd_si32()
中的Microsoft不一致。
int cvRound( double value )
{
__m128d t = _mm_set_sd( value );
return _mm_cvtsd_si32(t);
}
任何人都可以建议如何/为什么这样做?
FWIW,cvRound(20.5f + 1e-3f)
返回21
。
答案 0 :(得分:7)
小的半整数可以用二进制浮点精确表示 - 0.5是2的幂。
真正发生的是"将一半舍入到均匀。"这是一种消除半整数总是向上舍入时出现偏差的方法。
答案 1 :(得分:5)
SSE指令的舍入行为可通过浮点环境(特别是MXCSR寄存器)进行配置。有several IEEE rounding modes。默认的舍入模式是round-to-nearest,tie-to-even,因此如果该值恰好位于两个可表示值的中间,则结果将舍入到最接近的偶数值。
考虑以下测试程序,演示不同的舍入模式:
#include <fenv.h>
#include <immintrin.h>
#include <stdio.h>
int main()
{
printf("Default: %d\n", _mm_cvtsd_si32(_mm_set_sd(20.5)));
fesetround(FE_DOWNWARD);
printf("FE_DOWNWARD: %d\n", _mm_cvtsd_si32(_mm_set_sd(20.5)));
fesetround(FE_UPWARD);
printf("FE_UPWARD: %d\n", _mm_cvtsd_si32(_mm_set_sd(20.5)));
fesetround(FE_TONEAREST);
printf("FE_TONEAREST: %d\n", _mm_cvtsd_si32(_mm_set_sd(20.5)));
fesetround(FE_TOWARDZERO);
printf("FE_TOWARDZERO: %d\n", _mm_cvtsd_si32(_mm_set_sd(20.5)));
}
输出:
Default: 20
FE_DOWNWARD: 20
FE_UPWARD: 21
FE_TONEAREST: 20
FE_TOWARDZERO: 20
答案 2 :(得分:1)
舍入的工作方式与此相同,原因与此代码打印的值相同(使用MSVC2012测试)
float f1 = 20.4999999f;
float f2 = 20.5f;
if(f1==f2)
printf("equal\n");
http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html