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]);
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? –
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
Đó 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. –