2009-12-25 30 views
7

HI,Hành vi làm tròn toán học khác nhau giữa Linux, Mac OS X và Windows

Tôi đã phát triển một số mã C/C++ hỗn hợp, với một số tính toán số chuyên sâu. Khi được biên dịch trong Linux và Mac OS X, tôi nhận được kết quả rất giống nhau sau khi mô phỏng kết thúc. Trong Windows chương trình biên dịch là tốt, nhưng tôi nhận được kết quả rất khác nhau và đôi khi chương trình dường như không hoạt động.

Tôi đã sử dụng trình biên dịch GNU trong tất cả các hệ thống. Một số người bạn đề nghị tôi để thêm -frounding-math và bây giờ các phiên bản cửa sổ dường như làm việc ổn định hơn, nhưng Linux và Os X, kết quả của họ, không thay đổi ở tất cả.

Bạn có thể đề xuất một tùy chọn khác để có được sự phù hợp hơn giữa các phiên bản Win và Linux/OSX không?

Cảm ơn

P.D. Tôi cũng đã thử -O0 (không tối ưu hóa) và chỉ định -m32

+0

Linux và OS X đều sử dụng GCC, vì vậy tôi mong đợi chính xác kết quả tương tự - miễn là cả hai đều chạy trên cùng một kiến ​​trúc bộ vi xử lý. Bạn có thực sự chỉ nhận được kết quả 'tương tự' ở đó không? Nếu vậy, một số ngẫu nhiên dường như được tiêm vào tính toán của bạn. Bất kỳ biến uninitialized ?! –

Trả lời

9

Có bốn loại làm tròn khác nhau cho số dấu phẩy động: vòng về 0, làm tròn, làm tròn và làm tròn số gần nhất. Tùy thuộc vào trình biên dịch/hệ điều hành, mặc định có thể khác nhau trên các hệ thống khác nhau. Để thay đổi phương pháp làm tròn theo chương trình, hãy xem fesetround. Nó được chỉ định theo tiêu chuẩn C99, nhưng có thể có sẵn cho bạn.

Bạn cũng có thể thử tùy chọn -ffloat-store gcc. Điều này sẽ cố gắng ngăn gcc sử dụng các giá trị dấu phẩy động 80-bit trong thanh ghi.

Ngoài ra, nếu kết quả của bạn thay đổi tùy thuộc vào phương pháp làm tròn và sự khác biệt là đáng kể, điều đó có nghĩa là các phép tính của bạn có thể không ổn định. Vui lòng xem xét phân tích khoảng thời gian hoặc sử dụng một số phương pháp khác để tìm sự cố. Để biết thêm thông tin, hãy xem How Futile are Mindless Assessments of Roundoff in Floating-Point Computation? (pdf) và The pitfalls of verifying floating-point computations (liên kết ACM, nhưng bạn có thể nhận được PDF từ nhiều nơi nếu điều đó không hiệu quả với bạn).

+0

+1 cho tính ổn định số: Nếu kết quả thay đổi đáng kể dựa trên làm tròn, có điều gì đó sai với các tính toán. Và chỉ để loại trừ rõ ràng: Bạn đã sử dụng 'double' và không chỉ là 'float' cho các biến của bạn ?! –

9

Tôi không thể nói với việc triển khai trong Windows, nhưng chip Intel chứa thanh ghi dấu phẩy động 80 bit và có độ chính xác cao hơn tiêu chuẩn được chỉ định trong tiêu chuẩn điểm nổi IEEE-754. Bạn có thể thử gọi thói quen này trong main() của ứng dụng của bạn (trên nền tảng chip Intel):

inline void fpu_round_to_IEEE_double() 
{ 
    unsigned short cw = 0; 
    _FPU_GETCW(cw);  // Get the FPU control word 
    cw &= ~_FPU_EXTENDED; // mask out '80-bit' register precision 
    cw |= _FPU_DOUBLE;  // Mask in '64-bit' register precision 
    _FPU_SETCW(cw);  // Set the FPU control word 
} 

tôi nghĩ này là khác biệt với các phương thức làm tròn thảo luận bởi @Alok.

+2

+1 để đề cập đến thanh ghi 80 bit. Tôi không biết về '_FPU_ *'. –

+0

và đó là trên x87, không nên sử dụng nữa. Toán SSE nhanh hơn nhiều –

1

Ngoài cài đặt làm tròn thời gian chạy mà mọi người đã đề cập, bạn có thể kiểm soát cài đặt trình biên dịch Visual Studio trong Thuộc tính> C++> Tạo mã> Mô hình điểm nổi. Tôi đã thấy các trường hợp đặt cài đặt này thành "Nhanh" có thể gây ra một số hành vi số kém (ví dụ: các phương pháp lặp lại không hội tụ).

Các thiết lập được giải thích ở đây: http://msdn.microsoft.com/en-us/library/e7s85ffb%28VS.80%29.aspx

+0

cảm ơn tôi sử dụng eclipse – asdf

+0

Điều này cũng có cùng một vấn đề. Thiết lập mô hình điểm nổi VC++ có thể được thiết lập để ép buộc các biểu diễn nội bộ 80 bit được làm tròn đến các bit tương đương 64 bit của chúng tại các thời điểm xác định rõ ràng, và điều đó sẽ làm cho kết quả phù hợp với các triển khai khác sử dụng 64 bit xuyên qua. –

0

IEEE và C++ tiêu chuẩn C/để lại một số khía cạnh của floating-point toán không xác định. Có, kết quả chính xác của việc thêm vào phao được xác định, nhưng tính toán phức tạp hơn thì không. Ví dụ, nếu bạn thêm ba phao thì trình biên dịch có thể thực hiện đánh giá ở độ chính xác nổi, độ chính xác gấp đôi hoặc cao hơn. Tương tự, nếu bạn thêm ba đôi thì trình biên dịch có thể thực hiện đánh giá ở độ chính xác kép hoặc cao hơn.

VC++ mặc định để đặt độ chính xác của x87 FPU thành gấp đôi. Tôi tin rằng gcc lá nó ở độ chính xác 80-bit.Không rõ ràng hơn, nhưng chúng có thể dễ dàng đưa ra các kết quả khác nhau, đặc biệt nếu có bất kỳ sự bất ổn nào trong các phép tính của bạn. Đặc biệt 'nhỏ + lớn - lớn' có thể cho kết quả rất khác nhau nếu bạn có thêm bit chính xác (hoặc nếu thứ tự đánh giá thay đổi). Những tác động của thay đổi độ chính xác trung gian sẽ được thảo luận ở đây:

http://randomascii.wordpress.com/2012/03/21/intermediate-floating-point-precision/

Những thách thức xác định dấu chấm động sẽ được thảo luận ở đây:

http://randomascii.wordpress.com/2013/07/16/floating-point-determinism/

Floating-point toán là khéo léo. Bạn cần phải tìm hiểu khi tính toán của bạn phân kỳ và kiểm tra mã được tạo ra để hiểu tại sao. Chỉ khi đó bạn mới có thể quyết định hành động cần thực hiện.

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