2008-11-27 35 views
11

Tôi có một ứng dụng được phát triển cho Linux 32 bit x86. Có rất nhiều thao tác dấu phẩy động và rất nhiều thử nghiệm tùy thuộc vào kết quả. Bây giờ chúng ta đang chuyển nó sang x86_64, nhưng kết quả kiểm tra lại khác nhau trong kiến ​​trúc này. Chúng tôi không muốn giữ một tập hợp các kết quả riêng biệt cho mỗi kiến ​​trúc.Độ chính xác của dấu phẩy động khi di chuyển từ i386 đến x86_64

Theo bài viết An Introduction to GCC - for the GNU compilers gcc and g++ vấn đề là GCC trong x86_64 giả fpmath = SSE khi x86 giả fpmath = 387. FPU 387 sử dụng chính xác nội bộ 80 bit cho tất cả các hoạt động và chỉ chuyển đổi kết quả thành loại dấu phẩy động (nổi, đôi hoặc dài gấp đôi) trong khi SSE sử dụng loại toán hạng để xác định độ chính xác nội bộ của nó.

Tôi có thể force -mfpmath = 387 khi biên dịch mã của riêng mình và tất cả hoạt động của tôi hoạt động chính xác, nhưng bất cứ khi nào tôi gọi hàm thư viện (sin, cos, atan2, v.v.) Tôi cho rằng đó là vì libm được biên dịch mà không có ghi đè fpmath.

Tôi đã cố gắng xây dựng libm bản thân mình (glibc) bằng cách sử dụng mô phỏng 387, nhưng nó gây ra rất nhiều sự cố xung quanh (không biết nếu tôi đã làm điều gì sai).

Có cách nào để buộc tất cả mã trong quá trình sử dụng mô phỏng 387 trong x86_64 không? Hoặc có thể một số thư viện trả về cùng các giá trị như libm hiện trên cả hai kiến ​​trúc? Bất kỳ đề xuất?

Về câu hỏi "Bạn có cần độ chính xác 80 bit" không, tôi phải nói rằng đây không phải là vấn đề đối với một hoạt động riêng lẻ. Trong trường hợp đơn giản này, sự khác biệt là rất nhỏ và không có sự khác biệt. Tuy nhiên, khi kết hợp nhiều thao tác, lỗi truyền và sai số trong kết quả cuối cùng không quá nhỏ và tạo ra sự khác biệt. Vì vậy, tôi đoán tôi cần độ chính xác 80 bit.

Trả lời

17

Tôi muốn nói rằng bạn cần sửa các thử nghiệm của mình. Bạn thường đặt mình lên cho sự thất vọng nếu bạn cho rằng toán học dấu chấm động là chính xác. Thay vì thử nghiệm cho chính xác bình đẳng, hãy kiểm tra xem liệu nó có đủ gần với kết quả mong đợi hay không. Những gì bạn đã tìm thấy không phải là một lỗi, sau khi tất cả, vì vậy nếu các bài kiểm tra của bạn báo cáo lỗi, các bài kiểm tra là sai. ;)

Như bạn đã biết, mọi thư viện bạn dựa vào sẽ giả định điểm nổi SSE, vì vậy trừ khi bạn dự định biên dịch mọi thứ theo cách thủ công, ngay bây giờ và mãi mãi, để bạn có thể đặt chế độ FP thành x87, bạn nên giải quyết vấn đề ngay bây giờ, và chỉ chấp nhận rằng toán học FP không chính xác 100% và sẽ không mang lại kết quả tương tự trên hai nền tảng khác nhau. (Tôi tin rằng CPU của AMD mang lại kết quả hơi khác nhau về tính toán x87).

Bạn có hoàn toàn cần chính xác 80 bit không? (Nếu có, rõ ràng không có nhiều lựa chọn thay thế, ngoài việc tự biên dịch mọi thứ mình để sử dụng FP 80 bit.)

Nếu không, hãy điều chỉnh kiểm tra để thực hiện các phép so sánh và kiểm tra bình đẳng trong một số epsilon nhỏ. Nếu sự khác biệt nhỏ hơn epsilon đó, các giá trị được coi là bằng nhau.

2

Điểm nổi SSE và điểm nổi 387 sử dụng các hướng dẫn hoàn toàn khác nhau và do đó không có cách nào thuyết phục hướng dẫn SSE fp sử dụng 387.Có lẽ cách tốt nhất để giải quyết vấn đề này là từ chức bộ thử nghiệm của bạn để nhận được các kết quả hơi khác nhau, và không phụ thuộc vào kết quả giống với kết quả cuối cùng.

5

Độ chính xác 80 bit thực sự nguy hiểm. Vấn đề là nó thực sự được bảo quản miễn là biến được lưu trữ trong thanh ghi CPU. Bất cứ khi nào nó bị ép ra RAM, nó bị cắt ngắn về độ chính xác của loại. Vì vậy, bạn có thể có một biến thực sự thay đổi giá trị của nó mặc dù không có gì xảy ra với nó trong mã.

3

Nếu bạn muốn long double chính xác, hãy sử dụng long double cho tất cả các biến số dấu phẩy động của bạn, thay vì mong đợi float hoặc double để có thêm độ chính xác ma thuật. Điều này thực sự là không có trí tuệ.

+2

Chính xác. Tùy thuộc vào độ chính xác nội bộ mở rộng chỉ có thể dẫn đến đau lòng. –

+0

Tôi đang tìm một giải pháp không yêu cầu thay đổi quá nhiều mã và tăng gấp đôi yêu cầu bộ nhớ. Nhưng, như bạn nói, điều này rõ ràng sẽ khắc phục được vấn đề. –

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