Sudah diketahui umum bahwa NaN menyebar dalam aritmatika, tetapi saya tidak dapat menemukan demonstrasi, jadi saya menulis tes kecil:
#include <limits>
#include <cstdio>
int main(int argc, char* argv[]) {
float qNaN = std::numeric_limits<float>::quiet_NaN();
float neg = -qNaN;
float sub1 = 6.0f - qNaN;
float sub2 = qNaN - 6.0f;
float sub3 = qNaN - qNaN;
float add1 = 6.0f + qNaN;
float add2 = qNaN + qNaN;
float div1 = 6.0f / qNaN;
float div2 = qNaN / 6.0f;
float div3 = qNaN / qNaN;
float mul1 = 6.0f * qNaN;
float mul2 = qNaN * qNaN;
printf(
"neg: %f\nsub: %f %f %f\nadd: %f %f\ndiv: %f %f %f\nmul: %f %f\n",
neg, sub1,sub2,sub3, add1,add2, div1,div2,div3, mul1,mul2
);
return 0;
}
Contoh ( menjalankan langsung di sini ) pada dasarnya menghasilkan apa yang saya harapkan (yang negatif sedikit aneh, tapi agak masuk akal):
neg: -nan
sub: nan nan nan
add: nan nan
div: nan nan nan
mul: nan nan
MSVC 2015 menghasilkan sesuatu yang serupa. Namun, Intel C ++ 15 menghasilkan:
neg: -nan(ind)
sub: nan nan 0.000000
add: nan nan
div: nan nan nan
mul: nan nan
Secara khusus qNaN - qNaN == 0.0
,.
Ini ... tidak mungkin benar, bukan? Apa yang dikatakan oleh standar yang relevan (ISO C, ISO C ++, IEEE 754), dan mengapa ada perbedaan perilaku di antara kompiler?
Nan-NaN
adalahNaN
. Perl dan Scala juga berperilaku serupa.-ffast-math
pada gcc)?Jawaban:
Default floating point penanganan di Intel C ++ compiler
/fp:fast
, yang menanganiNaN
's tidak aman (yang juga menghasilkanNaN == NaN
menjaditrue
misalnya). Coba tentukan/fp:strict
atau/fp:precise
dan lihat apakah itu membantu.sumber
/fp:fast
: jika Anda menginginkan sesuatu yang aman , Anda mungkin sebaiknya menghindari NaN muncul di tempat pertama, dan umumnya tidak digunakan==
dengan angka floating-point. Mengandalkan semantik aneh yang diberikan IEEE754 ke NaN meminta masalah.NaN==NaN
kembalifalse
?Ini . . tidak mungkin benar, kan? Pertanyaan saya: apa yang dikatakan oleh standar yang relevan (ISO C, ISO C ++, IEEE 754) tentang ini?
Petr Abdulin sudah menjawab mengapa kompiler memberikan
0.0
jawaban.Inilah yang dikatakan IEEE-754: 2008:
Jadi satu-satunya hasil yang valid untuk pengurangan dua operan NaN yang tenang adalah NaN yang tenang; hasil lainnya tidak valid.
Standar C mengatakan:
(di mana di sini NaN menunjukkan NaN yang tenang sesuai F.2.1p1 "Spesifikasi ini tidak menentukan perilaku pensinyalan NaN. Biasanya menggunakan istilah NaN untuk menunjukkan NaN yang tenang")
sumber
Karena saya melihat jawaban yang mengganggu kepatuhan standar pada kompiler Intel, dan tidak ada orang lain yang menyebutkan ini, saya akan menunjukkan bahwa baik GCC dan Dentang memiliki mode di mana mereka melakukan sesuatu yang sangat mirip. Perilaku default mereka adalah sesuai dengan IEEE -
- tetapi jika Anda meminta kecepatan dengan mengorbankan kebenaran, Anda mendapatkan apa yang Anda minta -
Saya pikir itu sepenuhnya adil untuk mengkritik pilihan default ICC , tapi saya tidak akan membaca seluruh perang Unix kembali ke keputusan itu.
sumber
-ffast-math
,gcc
tidak mematuhi ISO 9899: 2011 sehubungan dengan aritmatika floating point lagi.