Như những người khác đã nói, đây chỉ là một vấn đề cơ bản mà bạn nhận được khi làm dấu chấm động số học đến bất kỳ cơ sở nào. Nó chỉ xảy ra rằng base-2 là một trong những phổ biến nhất trong máy tính (vì nó thừa nhận thực hiện phần cứng hiệu quả).
Khắc phục tốt nhất, nếu có thể, là chuyển sang sử dụng một số loại biểu diễn thương của số cho vòng lặp của bạn, làm cho giá trị dấu phẩy động được bắt nguồn từ đó. OK, điều đó nghe quá mức! Đối với trường hợp cụ thể của bạn, tôi sẽ viết như sau:
int dTimes10 = 20;
double d;
while(dTimes10 != 0) {
dTimes10 -= 2;
d = dTimes10/10.0;
}
Ở đây, chúng tôi thực sự làm việc với phân số [20/10, 18/10, 16/10, ..., 2/10, 0/10] trong đó phép lặp được thực hiện với các số nguyên (ví dụ, dễ dàng để có được chính xác) trong tử số với một mẫu số cố định, trước khi chuyển đổi sang dấu phẩy động. Nếu bạn có thể viết lại thực để làm việc như thế này, bạn sẽ có thành công lớn (và chúng thực sự không đắt hơn nhiều so với những gì bạn đang làm trước đó, đó là một sự cân bằng tuyệt vời để có được tính chính xác).
Nếu bạn không thể thực hiện việc này, bạn cần sử dụng so sánh trong-epsilon như so sánh của bạn. Khoảng, thay thế d != target
bằng abs(d - target) < ε
, trong đó lựa chọn ε (epsilon) đôi khi có thể khó xử. Về cơ bản, giá trị đúng của ε phụ thuộc vào một loạt các yếu tố, nhưng nó có thể được chọn tốt nhất là 0.001 cho phép lặp lại ví dụ cho thang tỷ lệ của giá trị bước (nghĩa là, nó bằng nửa phần trăm của độ lớn của bước, vì vậy bất kỳ thứ gì bên trong đó sẽ là lỗi thay vì thông tin).
Nguồn
2010-07-28 09:51:50
Không bao giờ sử dụng '==' với giá trị thả nổi. Có thể sử dụng một cái gì đó như 'f> epsilon'. – pascal
[Đã một vài ngày, tôi cho rằng chúng tôi đã hết hạn.] (Http://docs.sun.com/source/806-3568/ncg_goldberg.html) – GManNickG
Trong Java, tôi nghĩ rằng có công cụ sửa đổi "Strictfp" cho những tình huống như vậy –