Gcc ffast-math aslında ne yapar?


144

Gcc'nin --ffast-mathbayrağının float ops için hızını büyük ölçüde artırabildiğini ve IEEE standartlarının dışına çıktığını anlıyorum, ancak açıkken gerçekten neler olduğu hakkında bilgi bulamıyorum. Herkes lütfen bazı ayrıntıları açıklayabilir ve bayrak açık veya kapalı olsaydı bir şeyin nasıl değişeceğine dair net bir örnek verebilir mi?

Benzer sorular için SO'yu araştırmayı denedim, ancak ffast-math'un çalışmalarını açıklayan hiçbir şey bulamadım.

Yanıtlar:


86

Bahsettiğiniz gibi, katı IEEE uyumluluğunu korumayan optimizasyonlara izin verir.

Bir örnek şudur:

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

için

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

Kayan nokta aritmetiği ilişkisel olmadığından, işlemlerin sıralaması ve çarpanlarına alınması, yuvarlama nedeniyle sonuçları etkileyecektir. Bu nedenle, bu optimizasyon katı FP davranışı altında yapılmaz.

Aslında GCC'nin gerçekten bu özel optimizasyonu yapıp yapmadığını kontrol etmedim. Ama fikir aynı.


25
@Andrey: Bu örnek için 7'den 3'e 3'e
çarpıyorsunuz

4
@Andrey: Matematiksel olarak doğru olacak. Ancak sonuç, farklı yuvarlama nedeniyle son birkaç bitte biraz farklı olabilir.
Gizemli

1
Çoğu durumda, bu küçük fark önemli olmayacaktır (nispeten 10 ^ -16 sırasına göre double, ancak uygulamaya bağlı olarak değişir). Dikkat edilmesi gereken bir nokta, ffast-math optimizasyonlarının mutlaka "daha fazla" yuvarlama eklememesi. IEEE uyumlu olmamasının tek nedeni, cevabın yazılandan farklı (biraz da olsa) farklı olmasıdır.
Gizemli

1
@ kullanıcı: Hatanın büyüklüğü giriş verilerine bağlıdır. Sonuca göre küçük olmalıdır. Örneğin, x10'dan küçükse, Mystical örneğindeki hata 10 ^ -10 civarında olacaktır. Ama eğer x = 10e20hata muhtemelen milyonlarca olacak.
Ben Voigt

3
@stefanct aslında var hakkında -fassociative-mathhangi dahildir -funsafe-math-optimizationsbunun da birlikte etkindir -ffast-math does not GCC optimize Why a*a*a*a*a*aiçin (a*a*a)*(a*a*a)?
phuclv

256

-ffast-math sıkı IEEE uyumluluğunu kırmaktan çok daha fazlasını yapar.

Her şeyden önce, tabii, kırıldığında matematiksel olarak kayan nokta aynı (ideal olarak) ancak tam olarak aynıdır şeye talimatların yeniden sıralama örneğin sağlayan sıkı IEEE uyumu.

İkincisi, tek komutlu matematik işlevlerinden sonra ayarlamayı devre dışı bırakırerrno , bu da yerel bir değişkene yazma işleminden kaçınmak anlamına gelir (bu, bazı mimarilerde bu işlevler için% 100 fark yaratabilir).

Üçüncüsü, tüm matematiğin sonlu olduğu varsayımını yapar, bu da zararlı etkilere sahip olacakları yerde NaN (veya sıfır) kontrolü yapılmadığı anlamına gelir. Bunun gerçekleşmeyeceği varsayılır.

Dördüncüsü, bölünme ve karşılıklı karekök için karşılıklı yaklaşımlar sağlar .

Ayrıca, imzalı sıfırı devre dışı bırakır (kod, imzalı sıfırın var olmadığını varsayar, hedef desteklese bile) ve yuvarlama matematiği, diğer şeylerin yanı sıra derleme zamanında sürekli katlanmayı sağlar.

Son olarak, sinyalleme / yakalama matematiği nedeniyle hiçbir donanım kesintisinin olmayacağını varsayan kod üretir (yani, bunlar hedef mimaride devre dışı bırakılamaz ve sonuç olarak gerçekleşmezse , ele alınmaz).


15
Damon, teşekkürler! Bazı referanslar ekleyebilir misiniz? Gibi gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html " -ffast-math Setleri -fno-matematik-errno, -funsafe-matematik-optimizasyonlar, -ffinite-matematik-only, -fno viziteni-matematik, -fno-sinyalizasyon -nans ve -fcx-limited-range. Bu seçenek, FAST_MATH önişlemci makrosunun tanımlanmasına neden olur . "ve math.hglibc'den ( math_errhandling yakınında) gibi bir şey " Varsayılan olarak tüm işlevler hem errno hem de istisna işlemeyi destekler. gcc'nin hızlı matematik modunda ve satır içi işlevler tanımlanmışsa bu doğru olmayabilir. "
osgx

4
@javapowered: "Tehlikeli" olup olmadığı, ihtiyacınız olan garantiye bağlıdır. -ffast-mathderleyicinin bazı köşeleri kesmesine ve (açıklandığı gibi) bazı vaatleri kırmasına izin verir, bu da genel olarak bu kadar tehlikeli değildir ve çoğu insan için sorun değildir. Çoğu insan için aynı, sadece daha hızlı. Ancak, kodunuz bu vaatleri varsayar ve ona bağlı kalırsa, kodunuz beklediğinizden farklı davranabilir. Genellikle, bu araçlar programın olacağı görünüyor çoğunlukla çalışma cezası için, ancak bazı sonuçlar "beklenmedik" olabilir (mesela bir fizik simülasyonu, iki nesne değil çarpışır düzgün olabilir).
Damon

2
@Royi: İkisi birbirinden bağımsız olmalı. -O2hız için ticaret boyutu olanlar hariç genel olarak "her" yasal optimizasyon sağlar. -O3hız için işlem yapan optimizasyonları da mümkün kılar. Hala% 100 doğruluk sağlar. -ffast-mathgenellikle zararlı olmayan, ancak standardın ifadesi ile yanlış kabul edilen "biraz yanlış" davranışa izin vererek matematiksel işlemleri daha hızlı yapmaya çalışır. Kodunuz gerçekten iki derleyicide hız olarak çok farklıysa (sadece% 1-2 değil), kodunuzun kesinlikle standartlara uygun olup olmadığını kontrol edin ve ...
Damon

1
... sıfır uyarı verir. Ayrıca, kuralları ve otomatik vektörleştirme gibi şeyleri yumuşatmadığınızdan emin olun. Prensip olarak, GCC, en azından MSVC kadar iyi (genellikle benim deneyimimde daha iyi) performans göstermelidir. Durum böyle olmadığında, MSVC'nin görmezden geldiği ancak GCC'nin bir optimizasyonu devre dışı bırakmasına neden olan ince bir hata yaptınız. İkisini de istiyorsanız her iki seçeneği de vermelisiniz, evet.
Damon

1
@Royi: Bu kod benim için gerçekten küçük ve basit görünmüyor, birkaç dakika (hatta saat) içinde derinlemesine analiz edebilecek bir şey değil. Diğer şeylerin yanı sıra, görünüşte zararsızdır #pragma omp parallel forve döngü gövdesi içinde, işlev argümanlarının işaret ettiği adreslerden hem okuyup hem de yazıyorsunuz ve önemsiz olmayan bir dallanma yapıyorsunuz. Eğitimsiz bir tahmin olarak, uygulama tanımlı iş parçacığı çağrınızda önbellekleri atmış olabilirsiniz ve MSVC, diğer adlandırma kurallarının zorunlu kılacağı ara depoları yanlış şekilde önleyebilir. Söylemek imkansız.
Damon
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.