Gần đây, tôi đang đọc bài: Double or Nothing from GOTW by Herb Sutter Tôi là một chút nhầm lẫn với các giải thích về chương trình sau đây:Hiểu biết về Guru của Tuần # 67: Đôi hoặc có gì
int main()
{
double x = 1e8;
while(x > 0)
{
--x;
}
}
Giả sử rằng mã này chạy 1 giây trong một số máy. Tôi đồng ý với điểm rằng mã như thế này là ngớ ngẩn.
Tuy nhiên, theo giải thích về vấn đề nếu chúng tôi thay đổi x
từ float
thành double
, sau đó trên một số trình biên dịch, nó sẽ giữ cho máy tính chạy mãi mãi. Giải thích được dựa trên báo giá sau đây từ tiêu chuẩn.
Trích dẫn từ phần 3.9.1/8 của chuẩn C++:
Có ba loại dấu chấm động: float, double, và dài gấp đôi. Kiểu double cung cấp độ chính xác ít nhất là float, và kiểu double double cung cấp độ chính xác tối thiểu gấp đôi. Tập hợp các giá trị của kiểu float là một tập con của tập các giá trị của kiểu double; tập hợp các giá trị của kiểu double là một tập hợp con của tập hợp các giá trị của loại dài gấp đôi.
Câu hỏi cho mã là:
bao lâu bạn mong chờ nó để thực hiện nếu bạn thay đổi "đôi" thành "phao"? Tại sao?
Dưới đây là lời giải thích đưa ra:
Nó có lẽ sẽ mất một trong hai khoảng 1 giây (trên một phao nổi thực hiện cụ thể có thể hơi nhanh hơn, càng nhanh, hoặc hơi chậm hơn so với đôi), hoặc mãi mãi , tùy thuộc vào việc float có thể đại diện chính xác tất cả các giá trị nguyên từ 0 đến 1e8 không.
Trích dẫn trên từ tiêu chuẩn có nghĩa là có thể có các giá trị có thể được biểu thị bằng dấu hai chấm nhưng không thể đại diện bằng dấu phẩy. Đặc biệt, trên một số nền tảng và trình biên dịch phổ biến, double có thể biểu diễn chính xác tất cả các giá trị số nguyên trong [0,1e8] nhưng float không thể.
Điều gì xảy ra nếu float không thể đại diện chính xác tất cả các giá trị số nguyên từ 0 đến 1e8? Sau đó, chương trình sửa đổi sẽ bắt đầu đếm ngược, nhưng cuối cùng sẽ đạt đến giá trị N không thể được biểu diễn và N-1 == N (do không đủ độ chính xác) ... và
Câu hỏi của tôi là:
Nếu float thậm chí không thể đại diện cho 1e8
, thì chúng tôi sẽ có tràn khi chúng tôi khởi tạo float x = 1e8
; thì làm thế nào chúng ta sẽ làm cho máy tính chạy mãi mãi?
Tôi đã thử một ví dụ đơn giản ở đây (mặc dù không double
nhưng int
)
#include <iostream>
int main()
{
int a = 4444444444444444444;
std::cout << "a " << a << std::endl;
return 0;
}
It outputs: a -1357789412
Điều này có nghĩa rằng nếu trình biên dịch không có khả năng đại diện cho số lượng nhất định với int
loại, nó sẽ gây ra tràn.
Vì vậy, tôi đã đọc sai? Điểm nào tôi nhớ? Đang thay đổi x
từ double
đến float
hành vi chưa xác định?
Cảm ơn bạn!
cảm ơn vì thông tin tốt đẹp, nhưng câu hỏi của tôi là lý do tại sao vòng lặp while thậm chí sẽ bắt đầu nếu chúng ta có tràn lúc khởi tạo? – taocp
@taocp Bạn không bị tràn khi khởi tạo. Các định dạng điểm nổi có liên tục thấp hơn * độ chính xác * khi bạn đi đến các giá trị cao hơn cho đến khi bạn đạt đến + 1. # INF. Hoạt động trên vô hạn và # NAN là hợp pháp, không được xác định. Họ có thể có kết quả bất ngờ mặc dù. Hãy xem [tiêu chuẩn IEEE-754] (https://en.wikipedia.org/wiki/IEEE_floating_point) –
@indeterminatelysequenced ah, cảm ơn rất nhiều vì điều đó. – taocp