@Angew'in belirttiği gibi , !=operatörün her iki tarafta da aynı türe ihtiyacı var.
(float)i != iRHS'nin de dalgalanması ile sonuçlanır, bu yüzden var (float)i != (float)i.
g ++ ayrıca sonsuz bir döngü oluşturur, ancak içindeki işi optimize etmez. Bunu birlikte int-> şamandıra dönüştürür görebilirsiniz cvtsi2ssve yapar ucomiss xmm0,xmm0karşılaştırmak için (float)ikendisiyle. (Bu, C ++ kaynağınızın sandığınız şeyi ifade etmediğine dair ilk ipucunuzdu @ Angew'in cevabı açıklıyor.)
x != xxNaN olduğundan yalnızca "sırasız" olduğunda doğrudur . ( INFINITYIEEE matematiğinde kendisine eşittir, ancak NaN değildir. NAN == NANyanlıştır, NAN != NANdoğrudur).
gcc7.4 ve daha eski sürüm, kodunuzu jnpdöngü dalı olarak doğru şekilde optimize eder ( https://godbolt.org/z/fyOhW1 ): işlenenler x != x NaN olmadığı sürece döngüye devam . (gcc8 ve sonraki sürümler ayrıca jedöngüde bir kesinti olup olmadığını kontrol eder ve NaN olmayan herhangi bir girdi için her zaman doğru olacağı gerçeğine dayanarak optimizasyon yapamaz). x86 FP, set PF'yi sırasız olarak karşılaştırır.
Ve BTW, bu clang'ın optimizasyonunun da güvenli olduğu anlamına gelir : sadece CSE'ye ihtiyaç duyar(float)i != (implicit conversion to float)i aynı olduğu ve i -> floatbunun olası aralık için asla NaN olmadığını kanıtlaması gerekir int.
(Bu döngünün işaretli taşma UB'ye çarpacağı göz önüne alındığında, ud2yasadışı bir talimat veya döngü gövdesinin gerçekte ne olduğuna bakılmaksızın boş bir sonsuz döngü dahil olmak üzere, kelimenin tam anlamıyla istediği herhangi bir asm yayınlamasına izin verilir .) , bu optimizasyon hala% 100 yasaldır.
GCC , işaretli tamsayı taşmasını iyi tanımlanmış yapmak için bile-fwrapv döngü gövdesini optimize edemiyor (2'nin tamamlayıcı sarmalaması olarak). https://godbolt.org/z/t9A8t_
Etkinleştirmek bile -fno-trapping-mathyardımcı olmuyor. (GCC'nin varsayılanı, maalesef GCC'nin uygulaması bozuk / hatalı
-ftrapping-math olsa bile etkinleştirmektir .) İnt-> float dönüşümü, kesin olmayan bir FP istisnasına neden olabilir (tam olarak temsil edilemeyecek kadar büyük sayılar için), bu nedenle, muhtemelen maskelenmemiş istisnalar dışında, makul değildir. döngü gövdesini optimize edin. (Çünkü gerçek olmayan istisna maskelenmemişse, float türüne dönüştürmek gözlemlenebilir bir yan etkiye sahip olabilir.)16777217
Ancak -O3 -fwrapv -fno-trapping-math, bunu boş bir sonsuz döngüye derlememek% 100 eksik optimizasyondur. Aksi #pragma STDC FENV_ACCESS ONtakdirde, maskelenmiş FP istisnalarını kaydeden yapışkan bayrakların durumu, kodun gözlemlenebilir bir yan etkisi değildir. Hayır int-> floatdönüştürme NaN ile sonuçlanabilir, bu nedenlex != x doğru olamaz.
Bu derleyicilerin tümü, IEEE 754 tek duyarlıklı (binary32) floatve 32-bit kullanan C ++ uygulamaları için optimize ediyorint .
Hata düzeltilmiş(int)(float)i != i döngü, dar 16 bit intve / veya daha geniş olan C ++ uygulamalarında UB'ye sahip olacaktır float, çünkü tam olarak gösterilemeyen ilk tamsayıya ulaşmadan önce işaretli tamsayı taşması UB'ye ulaşırsınızfloat .
Ancak, farklı bir uygulama tanımlı seçimler kümesi altındaki UB, x86-64 System V ABI ile gcc veya clang gibi bir uygulama için derlerken herhangi bir olumsuz sonuç doğurmaz.
BTW, statik olarak bu döngünün sonucu hesaplamak olabilir FLT_RADIXve FLT_MANT_DIGtanımlanan <climits>. Ya da en azından teoride yapabilirsin, eğerfloat bir Pozit / unum gibi başka bir tür gerçek sayı temsilinden ziyade bir IEEE kayan modeline .
ISO C ++ standardının floatdavranış hakkında ne kadar bilgi verdiğinden ve sabit genişlikli üs ve anlamlı alanlara dayalı olmayan bir formatın standartlara uygun olup olmayacağından emin değilim .
Yorumlarda:
@geza Ortaya çıkan sayıyı duymak isterim!
@nada: 16777216
Yazdırmak / geri dönmek için bu döngüye sahip olduğunuzu mu iddia ediyorsunuz 16777216 ?
Güncelleme: bu yorum silindiğinden, sanmıyorum. Muhtemelen OP, floattam olarak 32 bit olarak temsil edilemeyen ilk tam sayıdan önceki alıntıdır float. https://en.wikipedia.org/wiki/Single-precision_floating-point_format#Precision_limits_on_integer_values yani bu buggy koduyla neyi doğrulamayı umuyorlar.
Hata düzeltilmiş sürüm elbette yazdırılır 16777217, ilk tam sayı değildir doğrusu bundan önce değerinden daha tam olarak gösterilemeyecek.
(Tüm yüksek kayan değerler tam sayılardır, ancak anlamlı ve genişliğinden daha yüksek üslü değerler için 2'nin, sonra 4'ün, ardından 8'in vb. Katlarıdır. Daha yüksek birçok tam sayı değeri gösterilebilir, ancak son sırada 1 birim (anlamlı) 1'den büyük olduğundan bitişik tamsayı değillerdir. En büyük sonlu float2 ^ 128'in hemen altındadır ve bu bile çift için çok büyüktürint64_t .)
Herhangi bir derleyici orijinal döngüden çıkıp bunu yazdırırsa, bu bir derleyici hatası olur.