2016年6月13日月曜日

[C/C++] 單精度浮點數四捨五入取整數的三種方法及速度

在做影像處理或是一般的電腦視覺運算的時候,很常會用到的 pixel 運算。

通常因為三角函數或其他運算,使得 pixel 的運算結果出現小數點。

但很不幸的是,通常 pixel 只能是整數,所以必須將結果從浮點數轉為整數。

雖然有時候會有負數的運算,但這篇先暫時不討論,只研究正數的運算。

第一種作法: 整數 + 0.5

float f = 1.5;
int i = static_cast<int>(f + 0.5f);


第二種做法: cmath library 的 roundf 函數

#include <cmath>

float f = 1.5;
int i = roundf(f);



第三種作法: Streaming SIMD Extensions (SSE) 指令內建函數

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

float f = 1.5;
int i = _mm_cvtss_si32(_mm_load_ss(&f));


Visual Studio 2015 關閉最佳化時,1億次迴圈的10次測試結果和平均:

Method Method1 Method2 Method3
1 450.635 2863.75 651.554
2 277.212 2734.84 642.859
3 307.044 2847.59 637.882
4 322.505 2802.01 641.209
5 306.707 2853.88 642.388
6 313.872 2778.64 662.927
7 308.213 2762.08 635.335
8 326.224 2790.67 627.892
9 324.849 2744.77 650.551
10 306.833 2830.59 668.719
average 324.409 2800.88 646.132

測試結果竟然和預期的不一樣Σ( ̄□ ̄|||)!!

我原本以為 SSE 指令的速度應該要是最快的。

不過看起來直接做 +0.5 運算的速度更快。

後來看了一下 ASM code,

第三種方法的 pointer 在 copy reference 的時候

和 __mm_cvtss_si32 和 _mm_load_ss 兩個 function 進出花了太多時間。

所以最後才會造成在速度上遠比直接做靜態轉換慢很多。