2013-04-03 39 views
5

Tôi đã kiểm tra một số mã sử dụng các cờ /fp:precise/fp:fast.Lạ/fp Dấu chấm động Hành vi mô hình điểm

Theo MSDN documentation cho /fp:precise:

Với/fp: chính xác trên các bộ xử lý x86, trình biên dịch sẽ thực hiện làm tròn trên các biến kiểu float với độ chính xác thích hợp cho các bài tập và các cặn lắng và khi đi qua các tham số để một chức năng. Việc làm tròn này đảm bảo rằng dữ liệu không giữ lại bất kỳ ý nghĩa nào lớn hơn khả năng loại của nó. Một chương trình được biên dịch với/fp: chính xác có thể chậm hơn và lớn hơn một biên dịch không có/fp: chính xác./fp: chính xác vô hiệu hóa nội tại; các thói quen thư viện thời gian chạy chuẩn được sử dụng thay thế. Để biết thêm thông tin, xem/Oi (Generate Intrinsic Functions).

Nhìn vào tháo của một cuộc gọi đến sqrtf (gọi với /arch:SSE2, nhắm mục tiêu nền tảng x86/Win32):

0033185D cvtss2sd xmm0,xmm1 
00331861 call  __libm_sse2_sqrt_precise (0333370h) 
00331866 cvtsd2ss xmm0,xmm0 

Từ this question Tôi tin rằng các bộ xử lý x86/x64 hiện đại không sử dụng thanh ghi 80-bit (hoặc ít nhất là không khuyến khích sử dụng của họ) để trình biên dịch thực hiện những gì tôi sẽ giả định là điều tốt nhất tiếp theo và làm các phép tính với đôi 64-bit. Và vì nội tại bị vô hiệu hóa, có một cuộc gọi đến một hàm sqrtf của thư viện.

Ok, công bằng, điều này dường như tuân thủ những gì tài liệu nói.

Tuy nhiên, khi tôi biên dịch cho các kiến ​​trúc x64, một cái gì đó kỳ lạ xảy ra:

000000013F2B199E movups  xmm0,xmm1 
000000013F2B19A1 sqrtps  xmm1,xmm1 
000000013F2B19A4 movups  xmmword ptr [rcx+rax],xmm1 

Các tính toán không được thực hiện với đôi 64-bit, và intrinsics đang được sử dụng. Theo như tôi có thể nói, kết quả chính xác giống như cờ /fp:fast được sử dụng.

Tại sao có sự khác biệt giữa hai? Không /fp:precise chỉ đơn giản là không hoạt động với nền tảng x64?

Bây giờ, như một kiểm tra tính chính xác, tôi đã thử nghiệm cùng một mã trong VS2010 x86 với /fp:precise/arch:SSE2. Đáng ngạc nhiên là, sqrtpd nội tại đang được sử dụng!

00AF14C7 cvtps2pd xmm0,xmm0 
00AF14CA sqrtsd  xmm0,xmm0 
00AF14CE cvtpd2ps xmm0,xmm0 

Điều gì đang xảy ra ở đây? Tại sao VS2010 sử dụng nội tại trong khi VS2012 gọi một thư viện hệ thống?

Thử nghiệm VS2010 nhắm mục tiêu nền tảng x64 có kết quả tương tự như VS2012 (/fp:precise dường như bị bỏ qua).

Tôi không có quyền truy cập vào bất kỳ phiên bản cũ nào của VS nên tôi không thể thực hiện bất kỳ thử nghiệm nào trên các nền tảng này.

Để tham khảo, tôi đang thử nghiệm trong Windows 7 64 bit với bộ xử lý Intel i5-m430.

+2

Điều này thật kỳ lạ. Tôi biết thực tế là '/ fp: exact' đôi khi sẽ khiến trình biên dịch quảng bá trung gian cho độ chính xác cao hơn theo ý mình. Nhưng điều đó không giải thích sự mâu thuẫn tuyệt đối ở đây. – Mysticial

+0

"Từ câu hỏi này tôi tin rằng kiến ​​trúc x86 không có thanh ghi 80 bit" Hãy đến một lần nữa? –

+0

Vâng, từ ngữ kỳ lạ. Cập nhật để làm rõ các khuyến nghị chung chống lại việc sử dụng chúng. – helloworld922

Trả lời

3

Trước hết bạn nên đọc this bài đăng blog thực sự tốt về độ chính xác của dấu phẩy động trung gian. Bài viết này chỉ xử lý mã tạo ra studio trực quan (nhưng đó là câu hỏi của bạn).Và bây giờ đến các ví dụ:

0033185D cvtss2sd xmm0,xmm1 
00331861 call  __libm_sse2_sqrt_precise (0333370h) 
00331866 cvtsd2ss xmm0,xmm0 

Mã lắp ráp này đã được tạo ra với /fp:precise /arch:SSE2 cho nền tảng x86. Theo documentation, mô hình điểm nổi chính xác thúc đẩy tất cả các phép tính để tăng gấp đôi nội bộ trên nền tảng x86. Nó cũng ngăn cản việc sử dụng nội tại (tôi nghĩ bạn đã đọc this information rồi). Do đó mã bắt đầu với một chuyển đổi từ phao sang gấp đôi theo sau là một cuộc gọi sqrt chính xác kép và cuối cùng kết quả được chuyển đổi trở lại float.

000000013F2B199E movups  xmm0,xmm1 
000000013F2B19A1 sqrtps  xmm1,xmm1 
000000013F2B19A4 movups  xmmword ptr [rcx+rax],xmm1 

Ví dụ thứ hai đã được biên dịch cho nền tảng x64 (amd64) và nền tảng này hoạt động hoàn toàn khác! Theo tài liệu:

Vì lý do hiệu suất, hoạt động trung gian được tính theo độ chính xác rộng nhất của toán hạng thay vì với độ chính xác rộng nhất có sẵn.

Do đó, các phép tính sẽ được thực hiện với độ chính xác đơn trong nội bộ. Tôi nghĩ rằng họ cũng quyết định sử dụng nội tại bất cứ khi nào có thể để sự khác biệt giữa /fp:precise/fp:fast có phần nhỏ hơn trên nền tảng x64. Hành vi mới dẫn đến mã nhanh hơn nó cho phép người lập trình kiểm soát nhiều hơn những gì xảy ra chính xác (họ có thể thay đổi các quy tắc của trò chơi vì vấn đề tương thích không quan tâm đến nền tảng x64 mới). Thật không may, những thay đổi/khác biệt này không được nêu rõ trong tài liệu.

00AF14C7 cvtps2pd xmm0,xmm0 
00AF14CA sqrtsd  xmm0,xmm0 
00AF14CE cvtpd2ps xmm0,xmm0 

Cuối cùng, ví dụ cuối cùng đã được biên soạn với Visual biên dịch Studio 2010 và tôi nghĩ rằng họ vô tình sử dụng một nội tại cho sqrt khi họ nên tốt hơn không có (ít nhất là cho chế độ /fp:precise), nhưng họ quyết định thay đổi/sửa chữa hành vi này trong Visual Studio 2012 một lần nữa (xem here).

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