2010-03-21 34 views
23

Sau khi tìm kiếm một lỗi thời gian dài, tôi đọc về các giá trị dấu phẩy động bất thường.Tránh các giá trị bất thường trong C++

Rõ ràng denormalized giá trị dấu chấm động có thể là một mối quan tâm thực hiện chính như được minh họa trong câu hỏi này: Why does changing 0.1f to 0 slow down performance by 10x?

Tôi có một lý Intel Core 2 Duo và tôi đang biên soạn với gcc, sử dụng -O2.

Vì vậy, tôi phải làm gì? Tôi có thể bằng cách nào đó hướng dẫn g ++ để tránh các giá trị bất thường? Nếu không, tôi có thể kiểm tra bằng cách nào đó nếu một số float là không bình thường?

+0

Bạn có thực sự có bất kỳ giá trị chuẩn nào trong chương trình của mình không? Dù sao, bạn có thể vô hiệu hóa chúng ở cấp CPU như @nobugz nói. Nếu bạn thiết lập đúng cờ, CPU sẽ cắt tất cả các denormals về 0, loại bỏ vấn đề. – jalf

+1

Xem câu hỏi này để thảo luận sâu về các biến thể và đối phó với chúng: http://stackoverflow.com/questions/9314534/why-does-changing-0-1f-to-0-slow-down-performance-by -10x – fig

Trả lời

13

Bạn có thể kiểm tra xem một phao được denormal sử dụng

#include <cmath> 

if (std::fpclassify(flt) == FP_SUBNORMAL) 

(Nên biết trước:. Tôi không chắc rằng điều này sẽ thực hiện ở tốc độ cao trong thực tế)

Trong C++ 03 và mã này đã hoạt động đối với tôi trong thực tế,

#include <cmath> 
#include <limits> 

if (flt != 0 && std::fabsf(flt) < std::numeric_limits<float>::min()) { 
    // it's denormalized 
} 

Để quyết định nơi áp dụng điều này, bạn có thể sử dụng máy phân tích dựa trên mẫu như Sha rk, VTune hoặc Zoom, để làm nổi bật các hướng dẫn bị làm chậm bởi các giá trị bất thường. Tối ưu hóa vi mô, thậm chí nhiều hơn các tối ưu hóa khác, là hoàn toàn vô vọng mà không cần phân tích cả trước và sau.

+1

Ý của bạn là gì, không có hình phạt về hiệu suất? Bạn có chắc không? Tôi đã viết một chương trình thử nghiệm nhỏ, cho thấy rằng việc thêm các dấu phẩy động với giá trị exp (-100) chậm hơn 10 lần so với khi giá trị là 0,1. Tôi hoàn toàn sai ở đây? – Nathan

+0

@Nathan: Không, bạn sẽ đúng lúc đó. Lấy làm tiếc. – Potatoswatter

+0

@Nathan: chỉ trong đó hình phạt thực sự lớn hơn 10x =) –

0

Bạn dường như muốn một số lệnh CPU được gọi là FTZ (Flush To Zero) và DAZ (Denormals Are Zero).

Tôi đã tìm thấy thông tin trên trang web âm thanh nhưng liên kết của họ với tài liệu của Intel bị thiếu. Chúng rõ ràng là các chỉ lệnh SSE2 nên chúng nên hoạt động trên các CPU AMD hỗ trợ điều đó.

Tôi không biết bạn có thể làm gì trong GCC để ép buộc điều đó theo cách di động. Bạn luôn có thể viết mã lắp ráp nội tuyến để sử dụng chúng. Bạn có thể buộc GCC chỉ sử dụng SSE2 cho phép toán dấu chấm động.

+0

Tất cả các FPU IEEE-754 đều có hướng dẫn như vậy không? Hay điều này cụ thể đối với một hoặc nhiều kiến ​​trúc bộ hướng dẫn? –

23

Đợi. Trước khi bạn làm bất cứ điều gì, bạn có thực sự biết rằng mã của bạn đang gặp phải các giá trị bất thường và chúng có tác động hiệu suất có thể đo lường không?

Giả sử bạn biết rằng, bạn có biết liệu thuật toán bạn đang sử dụng có ổn định không nếu hỗ trợ không chính xác bị tắt? Nhận được câu trả lời sai 10x nhanh hơn thường không phải là một tối ưu hóa hiệu suất tốt.

Những vấn đề sang một bên:

  • Nếu bạn muốn để phát hiện giá trị denormal để xác nhận rằng sự hiện diện của họ, bạn có một vài lựa chọn. Nếu bạn có thư viện chuẩn C99 hoặc Boost, bạn có thể sử dụng macro fpclassify. Ngoài ra, bạn có thể so sánh các giá trị tuyệt đối của dữ liệu với số bình thường dương nhỏ nhất.

  • Bạn có thể đặt phần cứng để tuôn ra các giá trị không chuẩn đoán về không (FTZ) hoặc xử lý các đầu vào không chính xác bằng 0 (DAZ). Cách dễ nhất, nếu nó được hỗ trợ đúng trên nền tảng của bạn, có lẽ là sử dụng hàm fesetenv() trong tiêu đề C fenv.h. Tuy nhiên, đây là một trong những tính năng được hỗ trợ rộng rãi nhất của tiêu chuẩn C và vốn dĩ là nền tảng cụ thể. Bạn có thể muốn chỉ sử dụng một số lắp ráp nội tuyến để trực tiếp thiết lập trạng thái FPU (DAZ/FTZ).

7

Hầu hết các bộ xử lý đối tượng toán học đều có tùy chọn cắt ngắn các giá trị bất thường về 0. Trên x86 nó là cờ FZ (Flush to Zero) trong thanh ghi điều khiển MXCSR. Kiểm tra việc triển khai CRT của bạn để có chức năng hỗ trợ để đặt thanh ghi điều khiển. Nó phải ở trong <float.h>, giống như _controlfp(). Bit tùy chọn thường có "FLUSH" trong biểu tượng #defined.

Kiểm tra kỹ kết quả toán học của bạn sau khi bạn đặt kết quả này. Đó là một cái gì đó bạn nên làm anyway, nhận được denormals là một dấu hiệu của vấn đề sức khỏe.

1

Giống như một sự bổ sung cho các câu trả lời khác, nếu bạn thực sự gặp vấn đề với các giá trị dấu phẩy động, bạn có thể gặp vấn đề về độ chính xác ngoài vấn đề hiệu suất của bạn.

Có thể nên kiểm tra xem bạn có thể cơ cấu lại các tính toán của mình để giữ cho các con số lớn hơn để tránh mất đi độ chính xác và hiệu suất hay không.

3

Để có (tuôn ra-to-zero) FTZ (giả sử underflow được đeo mặt nạ theo mặc định) trong gcc:

#define CSR_FLUSH_TO_ZERO   (1 << 15) 
unsigned csr = __builtin_ia32_stmxcsr(); 
csr |= CSR_FLUSH_TO_ZERO; 
__builtin_ia32_ldmxcsr(csr); 

Trong trường hợp nó không phải là rõ ràng từ tên, __builtin_ia32_stmxcsr__builtin_ia32_ldmxcsr chỉ khả dụng nếu bạn' đang nhắm mục tiêu một bộ xử lý x86. ARM, Sparc, MIPS, v.v. mỗi người sẽ cần một mã riêng cho từng nền tảng với phương pháp này.

+0

Đây có phải là nội trang cụ thể cho bộ vi xử lý không? Có vẻ như nó, từ tên ... –

+0

Có cần có thanh ghi MXCSR, cũng là 32bit. – dashesy

Các vấn đề liên quan