2008-10-24 73 views
31

Cách tốt nhất để sử dụng NaN trong C++ là gì?Sử dụng NaN trong C++?

Tôi tìm thấy std::numeric_limits<double>::quiet_NaN()std::numeric_limits<double>::signaling_NaN(). Tôi muốn sử dụng signaling_NaN để đại diện cho một biến chưa được khởi tạo như sau:

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

Tuy nhiên, tín hiệu này (nêu ra một ngoại lệ) khi chuyển nhượng. Tôi muốn nó đưa ra một ngoại lệ về sử dụng, chứ không phải về nhiệm vụ.

Có cách nào để sử dụng signaling_NaN mà không tăng ngoại lệ khi chuyển nhượng không? Có một thay thế tốt, di động để signaling_NaN sẽ tăng ngoại lệ dấu chấm động khi được sử dụng?

+0

hmm ... Tôi đang chơi với điều này bởi vì tôi tò mò bây giờ nhưng tôi không thể có được tôi để đưa ra một ngoại lệ. Bạn đã làm gì để có ngoại lệ? –

+0

@JeffreyMartinez Nó không phải là một ngoại lệ C++ bình thường, nếu đó là những gì bạn đang suy nghĩ. Đó là một ngoại lệ dấu chấm động: xem ghi chú [ở đây] (http://en.cppreference.com/w/cpp/numeric/fenv). – bames53

Trả lời

11

Sau khi xem xét một số chi tiết này, có vẻ như signaling_NaN là vô ích theo quy định. Nếu các ngoại lệ dấu phẩy động được bật, thì việc gọi nó được tính là xử lý tín hiệu NaN, vì vậy nó ngay lập tức làm tăng một ngoại lệ. Nếu các ngoại lệ dấu phẩy động bị vô hiệu hóa, thì việc xử lý một tín hiệu NaN sẽ tự động chuyển nó thành một NaN yên tĩnh, vì vậy signaling_NaN không hoạt động theo cách nào.

Menkboy's code công trình, nhưng cố gắng sử dụng tín hiệu Nans chạy vào các vấn đề khác: không có cách nào di động để kích hoạt hoặc vô hiệu hóa ngoại lệ điểm nổi (như ám chỉ herehere), và nếu bạn đang dựa vào trường hợp ngoại lệ được kích hoạt, thứ ba mã bên có thể vô hiệu hóa chúng (như được mô tả here).

Vì vậy, có vẻ như Motti's solution thực sự là lựa chọn tốt nhất.

3

Bạn có thể viết một NaN tín hiệu vào một biến mà không gây ra một ngoại lệ với một cái gì đó như thế này (nb: chưa được kiểm tra)

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

Nó sẽ làm việc hầu hết các nơi, nhưng không, nó không phải là 100% xách tay.

0

Việc triển khai C++ của bạn có thể có API để truy cập môi trường dấu chấm động để kiểm tra và xóa một số ngoại lệ dấu phẩy động. Xem my answer to a related question để biết thêm thông tin.

3

Vâng, sau khi định nghĩa cả NaN yên tĩnh và tín hiệu, tôi thực sự không thể tạo ra bất kỳ sự khác biệt nào.

Bạn có thể sử dụng mã được sử dụng trong các hàm đó, có thể ngăn chặn ngoại lệ theo cách đó, nhưng không thấy ngoại lệ trong hai hàm đó, tôi nghĩ nó có thể liên quan đến một thứ khác.

Nếu bạn muốn trực tiếp giao cho NaN:

double value = _Nan._Double; 
9

tín hiệu gì NAN có nghĩa là khi CPU gặp nó một tín hiệu được bắn, (vì vậy tên). Nếu bạn muốn phát hiện các biến chưa được khởi tạo thì việc tăng mức cảnh báo trên trình biên dịch của bạn thường phát hiện tất cả các đường dẫn sử dụng các giá trị không được tài trợ. Không mà bạn có thể sử dụng một lớp wrapper mà các cửa hàng một boolean nói nếu giá trị được khởi tạo:

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; 
    } 
}; 
+4

'boost :: optional ' là một lựa chọn tốt cho điều này, và hoạt động tốt cho các giá trị trả về, biến cục bộ và thành viên. Hơn nữa, nó không gọi hàm khởi tạo mặc định, và làm việc cho hầu hết các phần với các kiểu tham chiếu. – rvalue

3

câu trả lời đơn giản: Do something như thế này trong các tập tin header và sử dụng nó ở khắp mọi nơi khác:

#define NegativeNaN log(-1) 

Nếu bạn muốn làm một số loại thao tác trên chúng viết tốt hơn một số chức năng bao bọc kéo dài xung quanh exp() như extended_exp() và như vậy!