2015-10-14 125 views
7

我正在處理將-1.0到1.0範圍內的浮點取樣轉換爲帶符號16位的應用程序,以確保優化(SSE)例程的輸出準確無誤一組針對SSE版本運行非優化版本的測試,並比較它們的輸出。SSE向下取整

在我開始之前,我已確認SSE舍入模式設置爲最近。

在我的測試情況下,計算公式爲:

ratio = 65536/2 
output = round(input * ratio) 

在大多數情況下的結果是準確的,但在一個特定的輸入,我看到了的-0.8499908447265625輸入失敗。

-0.8499908447265625 * (65536/2) = -27852.5 

正常碼正確四捨五入這-27853,但上交所代碼輪這-27852

這裏是使用上證所代碼:

void Float_S16(const float *in, int16_t *out, const unsigned int samples) 
{ 
    static float ratio = 65536.0f/2.0f; 
    static __m128 mul = _mm_set_ps1(ratio); 

    for(unsigned int i = 0; i < samples; i += 4, in += 4, out += 4) 
    { 
    __m128 xin; 
    __m128i con; 

    xin = _mm_load_ps(in); 
    xin = _mm_mul_ps(xin, mul); 
    con = _mm_cvtps_epi32(xin); 

    out[0] = _mm_extract_epi16(con, 0); 
    out[1] = _mm_extract_epi16(con, 2); 
    out[2] = _mm_extract_epi16(con, 4); 
    out[3] = _mm_extract_epi16(con, 6); 
    } 
} 

自我的要求含有實施例:

/* standard math */ 
float ratio = 65536.0f/2.0f; 
float in [4] = {-1.0, -0.8499908447265625, 0.0, 1.0}; 
int16_t out[4]; 
for(int i = 0; i < 4; ++i) 
    out[i] = round(in[i] * ratio); 

/* sse math */ 
static __m128 mul = _mm_set_ps1(ratio); 
__m128 xin; 
__m128i con; 

xin = _mm_load_ps(in); 
xin = _mm_mul_ps(xin, mul); 
con = _mm_cvtps_epi32(xin); 

int16_t outSSE[4]; 
outSSE[0] = _mm_extract_epi16(con, 0); 
outSSE[1] = _mm_extract_epi16(con, 2); 
outSSE[2] = _mm_extract_epi16(con, 4); 
outSSE[3] = _mm_extract_epi16(con, 6); 

printf("Standard = %d, SSE = %d\n", out[1], outSSE[1]); 
+2

您可以將其減少爲一個自包含的示例程序來演示問題嗎? –

+1

在執行前後保存參數的值可能很有用。 – VermillionAzure

+3

這是** all **浮點處理的默認行爲,而不僅僅是SSE。 [半捨棄或銀行四捨五入](https://en.wikipedia。org/wiki/Rounding#Round_half_to_even)是根據IEEE 754標準的默認舍入模式。原因在於,當應用於許多數字時,這將舍入誤差最小化,而舍入保證存在半點誤差。 –

回答

13

雖然SSE舍入模式默認爲「輪最近的」,它不是老字號我們都在學校學到的四捨五入方法,但有一個稍微更現代的變化,稱爲Banker's rounding(又稱無偏舍入,收斂舍入,統計學舍入,荷蘭舍入,高斯舍入或奇偶舍入),其中舍入到最近的偶數ger價值。從統計角度來看,這種舍入方法應該比傳統方法更好。您將看到與rint()等功能相同的行爲,並且它也是default rounding mode for IEEE-754

另請注意,雖然標準庫函數round()使用傳統舍入方法,但SSE指令ROUNDPS (_mm_round_ps)使用銀行家舍入。

+1

應該注意的是,銀行家的四捨五入是任何浮點處理的默認值,不僅僅是SSE –

+0

@PanagiotisKanavos:謝謝 - 我只是在爲IEEE-754添加關於默認舍入方法的說明。 –

7

這就是所有浮點處理的默認行爲,而不僅僅是SSE。根據IEEE 754標準,Round half to even or banker's rounding是默認舍入模式。

使用這個的原因是,始終向上(或向下)舍入(或向下)會導致即使在中等數量的操作中也會累積的半點錯誤。半點可能會導致一些非常顯着的錯誤 - 足夠顯着,以至於它們成爲超人3中的繪圖點。

雖然半週期爲偶數或奇數,但會導致消除對方的負面和正面的半點錯誤適用於許多操作。

這在SSE操作中也是可取的。 SSE操作通常用於信號處理(音頻,圖像),工程和統計方案,其中一致的舍入誤差會顯示爲噪音,需要額外處理才能移除(如果可能)。銀行家的舍入可以確保消除這種噪音

+0

我認爲一個真實的例子,而不是超人電影更有趣。 –

+1

來自維基鏈接。 「一個着名的例子涉及溫哥華證券交易所於1982年設立的一個新指數。它最初定在1000.000(準確性小數點後三位),22個月後降至520左右 - 而股票價格普遍上漲問題是由於指數每天重新計算數千次,並且總是舍入到小數點後三位,這樣就會導致舍入誤差累積。重新計算更好的四捨五入使得指數值爲1098.892同一時期。「 –