Kayan Nokta Aritmetiği için IEEE 754-2008 Standardı ve ISO / IEC 10967 Dilden Bağımsız Aritmetik (LIA) Standardı, Bölüm 1 bunun neden böyle olduğunu yanıtlıyor.
IEEE 754 § 6.3 İşaret biti
Bir girdi veya sonuç NaN olduğunda, bu standart bir NaN'nin işaretini yorumlamaz. Bununla birlikte, bit dizelerindeki işlemlerin - copy, negate, abs, copySign - bazen bir NaN işleneninin işaret bitine bağlı olarak bir NaN sonucunun işaret bitini belirttiğini unutmayın. TotalOrder mantıksal yüklemi ayrıca bir NaN işleneninin işaret bitinden de etkilenir. Diğer tüm işlemler için, bu standart, yalnızca bir NaN girişi olduğunda veya geçersiz bir işlemden NaN üretildiğinde bile bir NaN sonucunun işaret bitini belirtmez.
Ne girdiler ne de sonuç NaN olmadığında, bir çarpımın veya bölümün işareti işlenenlerin işaretlerinin dışlayıcı VEYA'sıdır; x + (xy) toplamı olarak kabul edilen bir toplamın veya bir x - y farkının işareti, en fazla toplananların işaretlerinden birinden farklıdır; ve dönüşümlerin sonucunun işareti, niceleme işlemi, roundTo-Integral işlemleri ve roundToIntegralExact (bkz. 5.3.1), ilk veya tek işlenenin işaretidir. Bu kurallar, işlenenler veya sonuçlar sıfır veya sonsuz olduğunda bile geçerli olacaktır.
Karşıt işaretli iki işlenen toplamı (veya benzer işaretli iki işlenen arasındaki fark) tam olarak sıfır olduğunda, bu toplamın (veya farkın) işareti roundTowardNegative hariç tüm yuvarlama yönü özelliklerinde +0 olacaktır; bu nitelik altında, tam bir sıfır toplamın (veya farkın) işareti −0 olacaktır. Bununla birlikte, x + x = x - (−x), x sıfır olduğunda bile x ile aynı işareti korur.
Ekleme Durumu
Varsayılan yuvarlama modu altında (Gidiş-to-yakın, Kravatlar-to-bile) bunu görmek x+0.0
üreten x
dışında, x
bir -0.0
: Bu durumda biz toplamı sıfırdır ters işaretli iki işlenen bir miktar var ve §6.3 paragraf Bu eklemenin ürettiği 3 kural +0.0
.
Yana +0.0
değildir bit düzeyinde orijinal aynıdır -0.0
ve bu -0.0
girdi olarak oluşabilir meşru bir değerdir, derleyici potansiyel negatif sıfır dönüştürecek bu kodu koymak zorundadır+0.0
.
Özet: Varsayılan yuvarlama modunda, içinde x+0.0
, eğerx
- değil
-0.0
, o zaman x
kendisi kabul edilebilir bir çıktı değeridir.
- olduğu
-0.0
, daha sonra çıkış değeri olmalıdır +0.0
bitler aynı olmadığı, -0.0
.
Çarpma Durumu
Varsayılan yuvarlama modunda , ile böyle bir sorun oluşmaz x*1.0
. Eğer x
:
- bir (alt) normal sayıdır,
x*1.0 == x
her zaman .
- olduğu
+/- infinity
, daha sonra sonucudur +/- infinity
aynı işaretin.
olduğu NaN
sonra göre,
IEEE 754 § 6.2.3 NaN Yayılımı
Bir NaN işlenenini sonucuna yayan ve giriş olarak tek bir NaN'ye sahip olan bir işlem, hedef biçiminde gösterilebiliyorsa, giriş NaN'nin yüküyle bir NaN üretmelidir.
bunlardan üs ve mantis (değil işareti) bu araçlar NaN*1.0
vardır önerilen girişinden değişmemesini NaN
. İşaret, yukarıdaki §6.3p1'e göre belirtilmemiştir, ancak bir uygulama bunun kaynak ile aynı olduğunu belirtebilir NaN
.
- ise
+/- 0.0
sonuç, §6.3p2 ile uyumlu olarak 0
işaret biti 1.0
ile XORed işaret biti ile bir olur. İşaret biti olduğu 1.0
için 0
, çıkış değeri girişten değişmez. Böylece, (negatif) sıfır x*1.0 == x
olduğunda bile x
.
Çıkarma Durumu
Varsayılan yuvarlama kipinde , çıkarma işlemi x-0.0
de işlemsizdir çünkü eşdeğerdir x + (-0.0)
. Eğer x
DİR
- bu durumda
NaN
, §6.3p1 ve §6.2.3, toplama ve çarpma ile hemen hemen aynı şekilde uygulanır.
- olduğu
+/- infinity
, daha sonra sonucudur +/- infinity
aynı işaretin.
x-0.0 == x
her zaman bir (alt) normal sayıdır .
- bir
-0.0
"O §6.3p2 ile biz, [...], veya bir fark X bir toplamın işareti - olarak y toplamı x + (y), addends' işaretleri en az biri farklıdır; ". Bu bizi -0.0
sonuç olarak atamaya zorlar (-0.0) + (-0.0)
, çünkü -0.0
işarette hiçbir eklentiden farklıyken, +0.0
işaret ikiden farklıdır. Bu maddeye aykırı olarak addends arasında.
- olduğunu
+0.0
, o zaman bu ekleme duruma düşürür (+0.0) + (-0.0)
yukarıda kabul İlavesi Durumunda §6.3p3 tarafından vermeye almaması nedeniyle, +0.0
.
Tüm durumlar için girdi değeri çıktı olarak yasal olduğundan x-0.0
, x == x-0.0
işlemsiz ve totolojinin dikkate alınmasına izin verilir .
Değeri Değiştiren Optimizasyonlar
IEEE 754-2008 Standardı aşağıdaki ilginç alıntıya sahiptir:
IEEE 754 § 10.4 Birebir anlam ve değer değiştiren optimizasyonlar
[...]
Aşağıdaki değer değiştiren dönüşümler, diğerlerinin yanı sıra, kaynak kodun gerçek anlamını korur:
- X sıfır olmadığında ve bir sinyal NaN olmadığında ve sonuç x ile aynı üsse sahip olduğunda, 0 + x kimlik özelliğini uygulamak.
- X bir sinyal NaN olmadığında ve sonuç x ile aynı üsse sahip olduğunda 1 × x kimlik özelliğini uygulamak.
- Sessiz bir NaN'nin yükünü veya işaret bitini değiştirme.
- [...]
Tüm NaN'ler ve tüm sonsuzluklar aynı üssü paylaştığından x+0.0
ve x*1.0
sonlu için doğru yuvarlatılmış sonuç x
tam olarak aynı büyüklüğe sahip x
olduğundan, üsleri aynıdır.
sNaNs
Sinyalizasyon NaN'leri kayan nokta tuzak değerleridir; Kayan noktalı işlenen olarak kullanılması geçersiz bir işlem istisnasına (SIGFPE) neden olan özel NaN değerleridir. Bir istisnayı tetikleyen bir döngü optimize edilmiş olsaydı, yazılım artık aynı şekilde davranmazdı.
Bununla birlikte, user2357112'nin yorumlarda işaret ettiği gibi, C11 Standardı, NaN'lerin ( sNaN
) sinyalizasyonunun davranışını açıkça tanımsız bırakır , böylece derleyicinin bunların meydana gelmediğini varsaymasına izin verilir ve böylece ortaya çıkan istisnalar da meydana gelmez. C ++ 11 standardı, NaN'leri işaretlemek için bir davranışı tanımlamaz ve bu nedenle onu tanımsız bırakır.
Yuvarlama Modları
Alternatif yuvarlama modlarında, izin verilen optimizasyonlar değişebilir. Örneğin, Round-to-Negative-Infinity modunda, optimizasyona x+0.0 -> x
izin verilebilir, ancakx-0.0 -> x
yasaklanır.
GCC'nin varsayılan yuvarlama modlarını ve davranışlarını üstlenmesini önlemek için deneysel bayrak -frounding-math
GCC'ye geçirilebilir.
Sonuç
Clang ve GCC , olsa bile -O3
IEEE-754 uyumludur. Bu, IEEE-754 standardının yukarıdaki kurallarına uyması gerektiği anlamına gelir. x+0.0
olduğu bit aynı değil için x
tüm x
bu kurallar altında, ama x*1.0
böyle olması tercih edilebilir : ne zaman, Yani
x
Bir NaN olduğunda , yükün değiştirilmeden geçirilmesi önerisine uyun .
- NaN sonucunun işaret bitini ile değiştirmeden bırakın
* 1.0
.
- Zaman, işaret biti bir bölüm / ürün esnasında XOR emre itaat
x
olduğunu değil bir NaN.
IEEE-754-güvenli olmayan optimizasyonu etkinleştirmek için (x+0.0) -> x
, bayrağın -ffast-math
Clang veya GCC'ye geçirilmesi gerekir.