Apa sebenarnya ffast-matematika gcc sebenarnya?

144

Saya mengerti bahwa --ffast-mathflag gcc dapat sangat meningkatkan kecepatan untuk float ops, dan melampaui standar IEEE, tetapi sepertinya saya tidak dapat menemukan informasi tentang apa yang sebenarnya terjadi saat diaktifkan. Adakah yang bisa menjelaskan beberapa detail dan mungkin memberikan contoh yang jelas tentang bagaimana sesuatu akan berubah jika bendera dihidupkan atau dimatikan?

Saya memang mencoba menggali SO untuk pertanyaan serupa tetapi tidak dapat menemukan apa pun yang menjelaskan cara kerja matematika cepat.

Ponml
sumber

Jawaban:

86

Seperti yang Anda sebutkan, ini memungkinkan optimisasi yang tidak mempertahankan kepatuhan IEEE yang ketat.

Contohnya adalah ini:

x = x*x*x*x*x*x*x*x;

untuk

x *= x;
x *= x;
x *= x;

Karena aritmatika floating-point tidak asosiatif, pemesanan dan anjak operasi akan mempengaruhi hasil karena pembulatan. Oleh karena itu, pengoptimalan ini tidak dilakukan berdasarkan perilaku FP yang ketat.

Saya belum benar-benar memeriksa untuk melihat apakah GCC benar-benar melakukan optimasi khusus ini. Tapi idenya sama.

Mistikal
sumber
25
@ Andrew: Untuk contoh ini, Anda beralih dari 7 kali lipat menjadi 3.
Mysticial
4
@ Andrew: Secara matematis, itu akan benar. Tetapi hasilnya mungkin sedikit berbeda dalam beberapa bit terakhir karena pembulatan yang berbeda.
Mysticial
1
Dalam kebanyakan kasus, perbedaan kecil ini tidak masalah (relatif pada urutan 10 ^ -16 untuk double, tetapi bervariasi tergantung pada aplikasi). Satu hal yang perlu diperhatikan adalah optimisasi ffast-matematika tidak serta merta menambahkan "lebih". Satu-satunya alasan mengapa itu tidak sesuai dengan IEEE adalah karena jawabannya berbeda (walaupun sedikit) dari apa yang tertulis.
Mysticial
1
@ pengguna: Besarnya kesalahan tergantung pada input data. Itu harus relatif kecil terhadap hasilnya. Misalnya, jika xlebih kecil dari 10, kesalahan dalam contoh Mystical akan turun sekitar 10 ^ -10. Tetapi jika x = 10e20, kesalahannya mungkin jutaan.
Ben Voigt
3
@stefanct itu sebenarnya tentang -fassociative-mathyang termasuk dalam -funsafe-math-optimizationsyang pada gilirannya diaktifkan dengan -ffast-math Mengapa tidak GCC mengoptimalkan a*a*a*a*a*ake (a*a*a)*(a*a*a)?
phuclv
256

-ffast-math tidak lebih dari sekedar melanggar kepatuhan IEEE yang ketat.

Pertama-tama, tentu saja, itu benar- benar melanggar kepatuhan IEEE, memungkinkan misalnya penataan ulang instruksi untuk sesuatu yang secara matematis sama (idealnya) tetapi tidak persis sama di floating point.

Kedua, ini menonaktifkan pengaturanerrno setelah fungsi matematika instruksi tunggal, yang berarti menghindari penulisan ke variabel thread-lokal (ini dapat membuat perbedaan 100% untuk fungsi-fungsi pada beberapa arsitektur).

Ketiga, itu membuat asumsi bahwa semua matematika terbatas , yang berarti bahwa tidak ada pemeriksaan untuk NaN (atau nol) dibuat di tempat di mana mereka akan memiliki efek yang merugikan. Secara sederhana diasumsikan bahwa ini tidak akan terjadi.

Keempat, ini memungkinkan pendekatan timbal balik untuk pembagian dan akar kuadrat resiprokal.

Lebih jauh lagi, ia menonaktifkan ditandatangani nol (kode menganggap nol ditandatangani tidak ada, bahkan jika target mendukungnya) dan pembulatan matematika, yang memungkinkan antara lain lipat konstan pada waktu kompilasi.

Terakhir, ini menghasilkan kode yang mengasumsikan bahwa tidak ada gangguan hardware yang dapat terjadi karena pensinyalan / penjebakan matematika (yaitu, jika ini tidak dapat dinonaktifkan pada arsitektur target dan akibatnya terjadi , mereka tidak akan ditangani).

Damon
sumber
15
Damon, terima kasih! Bisakah Anda menambahkan beberapa referensi? Seperti gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html " -ffast-math Set -fno-math-errno, -funsafe-math-optimization, -finite-math-only, -fno-rounding-matematika, -fno-signaling -nans dan -fcx-limited-range. Opsi ini menyebabkan makro preprocessor FAST_MATH didefinisikan. "dan sesuatu dari glibc, seperti ( math.hnear math_errhandling)" Secara default semua fungsi mendukung errno dan penanganan pengecualian. Dalam mode matematika cepat gcc dan jika fungsi sebaris didefinisikan, ini mungkin tidak benar. "
osgx
4
@javapowered: Apakah itu "berbahaya" tergantung pada jaminan apa yang Anda butuhkan. -ffast-mathmemungkinkan kompiler untuk memotong beberapa sudut dan melanggar beberapa janji (seperti yang dijelaskan), yang secara umum tidak berbahaya seperti itu dan bukan masalah bagi kebanyakan orang. Bagi kebanyakan orang, itu sama, hanya lebih cepat. Namun, jika kode Anda mengasumsikan dan mengandalkan janji-janji ini, maka kode Anda mungkin berperilaku berbeda dari yang Anda harapkan. Biasanya, ini berarti bahwa program akan tampak berfungsi dengan baik, sebagian besar, tetapi beberapa hasil mungkin "tidak terduga" (katakanlah, dalam simulasi fisika, dua objek mungkin tidak bertabrakan dengan benar).
Damon
2
@ Royi: Keduanya harus independen satu sama lain. -O2umumnya memungkinkan "setiap" optimasi hukum, kecuali yang bertukar ukuran untuk kecepatan. -O3juga memungkinkan optimasi yang memperdagangkan ukuran untuk kecepatan. Itu masih mempertahankan kebenaran 100%. -ffast-mathmencoba untuk membuat operasi matematika lebih cepat dengan memungkinkan perilaku "sedikit salah" yang biasanya tidak berbahaya, tetapi akan dianggap salah oleh kata-kata standar. Jika kode Anda memang jauh berbeda dalam kecepatan pada dua kompiler (tidak hanya 1-2%) maka periksa bahwa kode Anda benar-benar sesuai standar dan ...
Damon
1
... menghasilkan nol peringatan. Juga, pastikan Anda tidak menghalangi aliasing aturan dan hal-hal seperti auto-vektorisasi. Pada prinsipnya, GCC harus melakukan setidaknya sama baiknya (biasanya lebih baik dalam pengalaman saya) seperti MSVC. Jika bukan itu masalahnya, Anda mungkin telah membuat kesalahan halus yang diabaikan oleh MSVC tetapi yang menyebabkan GCC menonaktifkan pengoptimalan. Anda harus memberikan kedua opsi jika Anda menginginkan keduanya, ya.
Damon
1
@ Royi: Kode itu tidak terlihat sangat kecil dan sederhana bagi saya, bukan sesuatu yang bisa dianalisis secara mendalam dalam beberapa menit (atau bahkan berjam-jam). Di antara hal-hal lain, ini melibatkan sesuatu yang tampaknya tidak berbahaya #pragma omp parallel for, dan di dalam lingkaran Anda membaca dan menulis ke alamat yang ditunjukkan oleh argumen fungsi, dan melakukan percabangan yang tidak sepele. Sebagai dugaan yang tidak berpendidikan, Anda mungkin meronta-ronta cache dari dalam invokasi yang ditentukan oleh implementasi Anda, dan MSVC mungkin secara keliru menghindari toko perantara yang diamanatkan oleh aturan alias. Mustahil untuk diceritakan.
Damon