2015-10-14 21 views
7

Tôi đang làm việc trên một ứng dụng chuyển đổi mẫu Float trong phạm vi từ -1.0 đến 1.0 thành 16bit đã ký, để đảm bảo đầu ra của các thường trình được tối ưu hóa (SSE) chính xác mà tôi đã viết một tập hợp các thử nghiệm chạy phiên bản không được tối ưu hóa dựa trên phiên bản SSE và so sánh đầu ra của chúng.SSE khoanh tròn khi nó tròn lên

Trước khi bắt đầu, tôi đã xác nhận rằng chế độ làm tròn SSE được đặt gần nhất.

Trong trường hợp thử nghiệm của tôi công thức là:

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

Đối với hầu hết các phần kết quả là chính xác, nhưng trên một đầu vào đặc biệt tôi nhìn thấy một sự thất bại cho một đầu vào của -0.8499908447265625.

-0.8499908447265625 * (65536/2) = -27852.5 

Mã bình thường viên đạn một cách chính xác này để -27853, nhưng mã SSE vòng này để -27852.

Đây là mã SSE sử dụng:

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); 
    } 
} 

khép kín Ví dụ như yêu cầu:

/* 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

Bạn có thể giảm bớt điều này thành một chương trình ví dụ độc lập thể hiện sự cố không? –

+1

Có thể hữu ích khi lưu các giá trị của các đối số trước và sau khi thực thi. – VermillionAzure

+3

Đó là hành vi mặc định cho ** tất cả ** xử lý điểm nổi, không chỉ SSE. [Làm tròn một nửa thậm chí hoặc làm tròn của ngân hàng] (https: //en.wikipedia.org/wiki/Rounding # Round_half_to_even) là chế độ làm tròn mặc định theo tiêu chuẩn IEEE 754. Lý do là điều này giảm thiểu sai số làm tròn khi áp dụng trên nhiều số trong khi đảm bảo vòng tròn có lỗi nửa điểm. –

Trả lời

13

Mặc dù SSE chế độ làm tròn mặc định là "tròn đến gần nhất", nó không phải là cũ quen thuộc phương pháp làm tròn mà tất cả chúng ta đã học ở trường, nhưng một biến thể hiện đại hơn được gọi là Banker's rounding (còn gọi là làm tròn không thiên vị, làm tròn hội tụ, làm tròn số liệu thống kê, làm tròn tiếng Hà Lan, làm tròn Gauss hoặc làm tròn kỳ quặc). giá trị ger. Phương pháp làm tròn này được cho là tốt hơn phương pháp truyền thống, từ góc độ thống kê. Bạn sẽ thấy hành vi tương tự với các chức năng như rint() và cũng là default rounding mode for IEEE-754.

Cũng lưu ý rằng trong khi hàm thư viện chuẩn round() sử dụng phương thức làm tròn truyền thống, lệnh SSE ROUNDPS (_mm_round_ps) sử dụng làm tròn của ngân hàng.

+1

Cần lưu ý rằng làm tròn của ngân hàng là mặc định cho bất kỳ xử lý dấu phẩy động nào, không chỉ cho SSE –

+0

@PanagiotisKanavos: cảm ơn - Tôi chỉ đang trong quá trình thêm ghi chú về phương pháp làm tròn mặc định cho IEEE-754. –

7

Đó là hành vi mặc định cho tất cả xử lý điểm nổi, không chỉ SSE. Round half to even or banker's rounding là chế độ làm tròn mặc định theo tiêu chuẩn IEEE 754.

Lý do được sử dụng này là luôn làm tròn lên (hoặc xuống) dẫn đến lỗi nửa điểm tích lũy khi áp dụng cho dù số lượng hoạt động vừa phải. Điểm nửa có thể dẫn đến một số lỗi khá đáng kể - đủ lớn để trở thành điểm cốt truyện trong Superman 3.

Một nửa còn lại hoặc lẻ, dẫn đến cả hai lỗi nửa điểm âm và dương. áp dụng trên nhiều hoạt động.

Điều này cũng mong muốn trong các hoạt động SSE. Các hoạt động SSE thường được sử dụng trong xử lý tín hiệu (âm thanh, hình ảnh), các kịch bản kỹ thuật và thống kê trong đó một lỗi làm tròn nhất quán sẽ xuất hiện dưới dạng tiếng ồn và yêu cầu xử lý bổ sung để loại bỏ (nếu có thể). Làm tròn của ngân hàng đảm bảo tiếng ồn này bị loại bỏ

+0

Tôi nghĩ rằng một ví dụ thực sự, thay vì bộ phim siêu nhân là thú vị hơn. –

+1

Từ liên kết wiki. "Một trường hợp nổi tiếng liên quan đến một chỉ số mới được thành lập bởi Sở giao dịch chứng khoán Vancouver năm 1982. Ban đầu nó được đặt ở 1000.000 (ba chữ số thập phân chính xác), và sau 22 tháng đã giảm xuống còn 520 - trong khi giá cổ phiếu thường tăng lên Vấn đề là do chỉ số được tính toán lại hàng nghìn lần mỗi ngày và luôn được làm tròn xuống đến 3 chữ số thập phân, theo cách mà các lỗi làm tròn tích lũy. cùng kỳ. " –