Pertanyaan Menggunakan NaN di C ++?


Apa cara terbaik untuk menggunakan NaN di C ++?

saya menemukan std::numeric_limits<double>::quiet_NaN() dan std::numeric_limits<double>::signaling_NaN(). Saya ingin menggunakannya signaling_NaN untuk merepresentasikan variabel terinisialisasi sebagai berikut:

double diameter = std::numeric_limits<double>::signaling_NaN();

Ini, bagaimanapun, sinyal (menimbulkan pengecualian) pada tugas. Saya ingin memunculkan pengecualian pada penggunaan, bukan pada tugas.

Apakah ada cara untuk menggunakannya signaling_NaN tanpa meningkatkan pengecualian pada tugas? Apakah ada alternatif yang bagus dan portabel untuk signaling_NaN yang akan menaikkan pengecualian floating point saat digunakan?


32
2017-10-24 21:56


asal


Jawaban:


Setelah melihat ini lebih banyak, sepertinya signaling_NaN tidak berguna sebagaimana yang disediakan. Jika pengecualian titik mengambang diaktifkan, maka memanggilnya dihitung sebagai memproses sinyal NaN, sehingga segera memunculkan pengecualian. Jika pengecualian titik mengambang dinonaktifkan, maka memproses sinyal NaN secara otomatis mendemosikannya menjadi NaN yang tenang, jadi signaling_NaN tidak berfungsi dengan baik.

Kode Menkboy bekerja, tetapi mencoba menggunakan menandakan NaN berjalan ke masalah lain: tidak ada cara portabel untuk mengaktifkan atau menonaktifkan pengecualian titik mengambang (seperti yang disinggung sini dan sini), dan jika Anda mengandalkan pengecualian yang diaktifkan, kode pihak ketiga dapat menonaktifkannya (seperti yang dijelaskan sini).

Jadi sepertinya Solusi Motti benar-benar pilihan terbaik.


11
2017-11-11 18:32



Apa yang menandakan NAN berarti bahwa ketika CPU bertemu, sinyal akan diaktifkan, (maka dari itu namanya). Jika Anda ingin mendeteksi variabel terinisialisasi, maka menaikkan level peringatan pada kompiler Anda biasanya mendeteksi semua jalur yang menggunakan nilai yang tidak diinisialisasi. Kegagalan bahwa Anda dapat menggunakan kelas pembungkus yang menyimpan pepatah boolean jika nilai diinisialisasi:

template <class T>
class initialized {
    T t;
    bool is_initialized;
public:
    initialized() : t(T()), is_initialized(false) { }
    initialized(const T& tt) : t(tt), is_initialized(true) { }
    T& operator=(const T& tt) { t = tt; is_initialized = true; return t; }
    operator T&() {
         if (!is_initialized)
             throw std::exception("uninitialized");
         return t; 
   }
};

9
2017-10-25 20:02



Anda dapat menulis sinyal NaN menjadi variabel tanpa memicu pengecualian dengan sesuatu seperti ini (nb: belum diuji)

void set_snan( double &d )
{
    long long *bits = (long long *)&d;
    *bits = 0x7ff0000080000001LL;
}

Ini akan berfungsi di banyak tempat, tetapi tidak, itu tidak 100% portabel.


3
2017-10-24 22:35



Nah, perhatikan definisi diam dan memberi sinyal NaN, saya tidak bisa benar-benar membuat perbedaan.

Anda bisa menggunakan kode yang digunakan dalam fungsi-fungsi itu sendiri, mungkin itu mencegah pengecualian seperti itu, tetapi tidak melihat pengecualian dalam kedua fungsi itu, saya pikir itu mungkin terkait dengan sesuatu yang lain.

Jika Anda ingin langsung menetapkan NaN:

double value = _Nan._Double;

3
2017-10-25 19:57



Jawaban sederhana: Lakukan sesuatu seperti ini di file header dan gunakan di tempat lain:

#define NegativeNaN log(-1)

Jika Anda ingin melakukan beberapa jenis manipulasi, lebih baik tuliskan beberapa fungsi pembungkus tambahan exp() seperti extended_exp() dan seterusnya!


3
2017-11-05 15:49



Implementasi C ++ Anda mungkin memiliki API untuk mengakses lingkungan floating point untuk menguji dan menghapus pengecualian titik apung tertentu. Lihat jawaban saya untuk pertanyaan terkait untuk informasi lebih lanjut.


0
2017-10-24 22:42