Mã sau giả định rằng chúng tôi đang sử dụng hệ thống tương thích x86 và long double
bản đồ với định dạng 80 bit của x87 FPU.Tại sao giá trị này được in mặc dù là NaN?
#include <cmath>
#include <array>
#include <cstring>
#include <iomanip>
#include <iostream>
int main()
{
std::array<uint8_t,10> data1{0x52,0x23,0x6f,0x24,0x8f,0xac,0xd1,0x43,0x30,0x02};
std::array<uint8_t,10> data2{0x52,0x23,0x6f,0x24,0x8f,0xac,0xd1,0xc3,0x30,0x02};
std::array<uint8_t,10> data3{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x30,0x02};
long double value1, value2, value3;
static_assert(sizeof value1 >= 10,"Expected float80");
std::memcpy(&value1, data1.data(),sizeof value1);
std::memcpy(&value2, data2.data(),sizeof value2);
std::memcpy(&value3, data3.data(),sizeof value3);
std::cout << "isnan(value1): " << std::boolalpha << std::isnan(value1) << "\n";
std::cout << "isnan(value2): " << std::boolalpha << std::isnan(value2) << "\n";
std::cout << "isnan(value3): " << std::boolalpha << std::isnan(value3) << "\n";
std::cout << "value1: " << std::setprecision(20) << value1 << "\n";
std::cout << "value2: " << std::setprecision(20) << value2 << "\n";
std::cout << "value3: " << std::setprecision(20) << value3 << "\n";
}
Output:
isNaN (value1): true
isNaN (value2): false
isNaN (value3): false
value1: 3.3614005946481929011e- 4764
giá trị2: 9.705 6260598879139386e-4764
value3: 6.3442254652397210376e-4764
Đây value1
được phân loại là "không được hỗ trợ" bởi 387 và cao hơn, bởi vì nó có khác không và không phải tất cả-những số mũ - đó là thực chất là một "unnormal" . Và isnan
hoạt động như mong đợi với nó: giá trị thực sự là không có gì của một số (mặc dù không chính xác là một NaN). Giá trị thứ hai, value2
, có bộ bit số nguyên đó và cũng hoạt động như mong đợi: không phải là NaN. Giá trị thứ ba là giá trị của bit số nguyên còn thiếu.
Nhưng bằng cách nào đó cả hai số value1
và value2
xuất hiện được in và các giá trị khác nhau chính xác bởi bit số nguyên bị thiếu! Tại sao vậy? Tất cả các phương pháp khác tôi đã thử, như printf
và to_string
chỉ cung cấp 0.00000
.
Ngay cả người lạ, nếu tôi thực hiện bất kỳ số học nào với value1
, trong các bản in tiếp theo, tôi nhận được nan
. Tính đến điều này, làm cách nào để operator<<(long double)
thậm chí quản lý thực sự in bất kỳ thứ gì trừ nan
? Liệu nó có thiết lập một cách rõ ràng bit nguyên, hay có thể nó phân tích số thay vì thực hiện bất kỳ số học FPU nào trên nó? (giả sử g ++ 4.8 trên Linux 32 bit).
Điều này có thể tương tự như http://stackoverflow.com/questions/4518951/engineered-bool-compares-equal-to-both-true-and-false-why. Việc thực hiện có quyền giả định rằng những gì bạn cung cấp cho nó chứa một biểu diễn 'long double' hợp lệ (hoặc' bool' trong câu hỏi được liên kết). Nếu bạn vượt qua nó một đại diện không hợp lệ, tất cả các cược được tắt. –
UB là U. Tại sao bạn nên mong đợi bất kỳ hành vi cụ thể nào? –
“trên thực tế nó là" không bình thường ". Và isnan hoạt động như mong đợi với nó: giá trị thực sự không là gì cả. ”Đây không phải là ý nghĩa của“ NaN ”. NaN là một giá trị dấu phẩy động sẽ truyền qua các tính toán theo một cách xác định. Một giá trị không bình thường là một dấu tích lịch sử và nó không được hỗ trợ để truyền một cho một lệnh dấu phẩy động kể từ 387. Vì mục đích thực tế, một giá trị không bình thường nên được coi là một “đại diện bẫy”. . –