cdm*_*dmh 3 c++ opencv rounding-error visual-c++
在使用MSVC2013的x64 Windows上,我使用的cvRound是OpenCV 的功能,目的是从x.5值向上舍入.我遇到了一个不一致的cvRound(17.5f)回报18(好!),但cvRound(20.5f)回报20并没有21像预期的那样
因此简单地实现了cvRound,所以它似乎是微软的不一致_mm_cvtsd_si32().
int cvRound( double value )
{
__m128d t = _mm_set_sd( value );
return _mm_cvtsd_si32(t);
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以建议如何/为什么这样做?
FWIW,cvRound(20.5f + 1e-3f)返回21.
小半整数可以用二进制浮点精确表示 - 0.5是2的幂.
真正发生的是"四舍五入到均匀".这是一种消除半整数总是向上舍入时发生的偏差的方法.
http://en.wikipedia.org/wiki/Rounding#Round_half_to_even
SSE指令的舍入行为可通过浮点环境(特别是MXCSR寄存器)进行配置.有几种IEEE舍入模式.默认的舍入模式是round-to-nearest,tie-to-even,因此如果该值恰好位于两个可表示值的中间,则结果将四舍五入为最接近的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)));
}
Run Code Online (Sandbox Code Playgroud)
输出:
Default: 20
FE_DOWNWARD: 20
FE_UPWARD: 21
FE_TONEAREST: 20
FE_TOWARDZERO: 20
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
746 次 |
| 最近记录: |