Standar IEEE 754-2008 untuk Floating-Point Arithmetic dan ISO / IEC 10967 Language Independent Arithmetic (LIA) Standard, Bagian 1 menjawab mengapa demikian.
IEEE 754 § 6.3 Tanda itu sedikit
Ketika input atau hasil adalah NaN, standar ini tidak menafsirkan tanda NaN. Perhatikan, bagaimanapun, bahwa operasi pada string bit - copy, negate, abs, copySign - tentukan bit tanda dari hasil NaN, kadang-kadang berdasarkan bit tanda operan NaN. TotalOrder predikat logis juga dipengaruhi oleh bit tanda operan NaN. Untuk semua operasi lain, standar ini tidak menentukan bit tanda hasil NaN, bahkan ketika hanya ada satu input NaN, atau ketika NaN dihasilkan dari operasi yang tidak valid.
Ketika input atau hasil bukan NaN, tanda suatu produk atau hasil bagi adalah OR eksklusif atau dari tanda operan; tanda penjumlahan, atau perbedaan x - y dianggap sebagai penjumlahan x + (−y), berbeda dari paling banyak salah satu dari tanda-tanda tambahan; dan tanda hasil konversi, operasi kuantisasi, operasi roundTo-Integral, dan roundToIntegralExact (lihat 5.3.1) adalah tanda operan pertama atau satu-satunya. Aturan-aturan ini akan berlaku bahkan ketika operan atau hasilnya nol atau tidak terbatas.
Ketika jumlah dua operan dengan tanda-tanda yang berlawanan (atau perbedaan dari dua operan dengan tanda-tanda serupa) adalah nol, tanda dari jumlah (atau perbedaan) tersebut harus +0 dalam semua atribut arah pembulatan kecuali roundTowardNegative; di bawah atribut itu, tanda jumlah nol yang tepat (atau perbedaan) harus −0. Namun, x + x = x - (−x) mempertahankan tanda yang sama dengan x bahkan ketika x adalah nol.
Kasus Penambahan
Di bawah mode pembulatan standar (Round-to-Nearest, Ties-to-Even) , kita melihat bahwa x+0.0
menghasilkan x
, KECUALI ketika x
adalah -0.0
: Dalam hal itu kita memiliki jumlah dua operan dengan tanda-tanda berlawanan yang jumlahnya adalah nol, dan §6,3 paragraf 3 aturan yang dihasilkan tambahan ini +0.0
.
Karena bitwise+0.0
tidak identik dengan aslinya , dan itu adalah nilai yang sah yang dapat terjadi sebagai input, kompiler wajib memasukkan kode yang akan mengubah nol potensial menjadi negatif .-0.0
-0.0
+0.0
Ringkasan: Di bawah mode pembulatan default, dalam x+0.0
, jikax
- tidak
-0.0
, maka x
itu sendiri adalah nilai output yang dapat diterima.
- adalah
-0.0
, maka nilai output harus +0.0
, yang tidak identik dengan bitwise -0.0
.
Kasus Multiplikasi
Di bawah mode pembulatan default , tidak ada masalah seperti itu terjadi x*1.0
. Jika x
:
Kasus Pengurangan
Di bawah mode pembulatan default , pengurangan x-0.0
juga merupakan larangan, karena setara dengan x + (-0.0)
. Jika x
ada
- adalah
NaN
, maka §6.3p1 dan §6.2.3 berlaku dengan cara yang sama seperti untuk penambahan dan penggandaan.
- adalah
+/- infinity
, maka hasilnya adalah +/- infinity
dari tanda yang sama.
- adalah (normal) angka normal,
x-0.0 == x
selalu.
- adalah
-0.0
, maka oleh §6.3p2 kita memiliki " [...] tanda penjumlahan, atau perbedaan x - y dianggap sebagai penjumlahan x + (fromy), berbeda dari paling banyak salah satu dari tanda tambahan; ". Ini memaksa kita untuk menetapkan -0.0
sebagai hasil dari (-0.0) + (-0.0)
, karena -0.0
berbeda dalam tanda dari tidak ada tambahan, sementara +0.0
berbeda dalam tanda dari dua dari tambahan, yang melanggar pasal ini.
- adalah
+0.0
, maka ini mengurangi kasus penambahan yang (+0.0) + (-0.0)
dipertimbangkan di atas dalam Kasus Penambahan , yang oleh §6.3p3 diperintahkan untuk diberikan +0.0
.
Karena untuk semua kasus, nilai input legal sebagai output, diizinkan untuk mempertimbangkan x-0.0
larangan, dan x == x-0.0
tautologi.
Optimalisasi Perubahan Nilai
Standar IEEE 754-2008 memiliki kutipan menarik berikut:
IEEE 754 § 10.4 Arti literal dan optimisasi yang mengubah nilai
[...]
Transformasi yang mengubah nilai berikut, antara lain, mempertahankan makna literal kode sumber:
- Menerapkan properti identitas 0 + x ketika x bukan nol dan bukan NaN pensinyalan dan hasilnya memiliki eksponen yang sama dengan x.
- Menerapkan properti identitas 1 × x ketika x bukan NaN pensinyalan dan hasilnya memiliki eksponen yang sama dengan x.
- Mengubah muatan atau masuk sedikit NaN yang tenang.
- [...]
Karena semua NaN dan semua infinities berbagi eksponen yang sama, dan hasil benar bulat x+0.0
dan x*1.0
untuk yang terbatas x
memiliki tepat besarnya sama x
, eksponen mereka adalah sama.
sNaNs
Signalling NaNs adalah nilai perangkap floating-point; Mereka adalah nilai NaN khusus yang digunakan sebagai operan titik-mengambang menghasilkan pengecualian operasi tidak valid (SIGFPE). Jika loop yang memicu pengecualian dioptimalkan, perangkat lunak tidak akan lagi berperilaku sama.
Namun, seperti yang ditunjukkan oleh user2357112 dalam komentar , Standar C11 secara eksplisit membiarkan perilaku pensinyalan NaNs ( sNaN
), sehingga penyusun diizinkan untuk menganggap mereka tidak terjadi, dan dengan demikian pengecualian yang mereka ajukan juga tidak terjadi. C ++ 11 menghilangkan standar yang menggambarkan perilaku untuk memberi sinyal NaN, dan dengan demikian juga membiarkannya tidak terdefinisi.
Mode Pembulatan
Dalam mode pembulatan alternatif, optimisasi yang diizinkan dapat berubah. Misalnya, dalam mode Round-to-Negative-Infinity , optimasi x+0.0 -> x
menjadi diizinkan, tetapi x-0.0 -> x
menjadi terlarang.
Untuk mencegah GCC dari mengasumsikan mode dan perilaku pembulatan default, bendera eksperimental -frounding-math
dapat diteruskan ke GCC.
Kesimpulan
Dentang dan GCC , bahkan pada -O3
, tetap sesuai IEEE-754. Ini berarti harus mematuhi aturan standar IEEE-754 di atas. x+0.0
adalah tidak bit-identik untuk x
semua x
di bawah aturan-aturan, tetapi x*1.0
dapat dipilih untuk menjadi begitu : Yaitu, ketika kita
- Patuhi rekomendasi untuk meneruskan payload yang tidak berubah
x
ketika itu adalah NaN.
- Biarkan sedikit tanda hasil NaN tidak diubah oleh
* 1.0
.
- Mematuhi perintah untuk XOR tanda sedikit selama quotient / produk, saat
x
ini tidak NaN.
Untuk mengaktifkan pengoptimalan yang tidak aman dari IEEE-754 (x+0.0) -> x
, flag tersebut -ffast-math
harus diteruskan ke Dentang atau GCC.