Các số dấu phẩy động 99,15 và 28,85 và 78,30 không có biểu diễn nhị phân chính xác của IEEE 754. Bạn có thể thấy điều này với một chương trình C thực hiện cùng một phép tính:
#include <stdio.h>
int
main(int ac, char **av)
{
float a = 99.15;
float b = 20.85;
float c;
printf("a = %.7f\n", a);
printf("b = %.7f\n", b);
c = a - b;
printf("c = %.7f\n", c);
return 0;
}
Tôi nhận được những câu trả lời trên bởi một máy x86 và một máy x86_64 có lẽ bởi vì cả hai đều thực hiện phép toán dấu phẩy động IEEE 754 :
a = 99.1500015 b = 20.8500004 c = 78.3000031
Đây là những gì xảy ra: số dấu phẩy động được biểu diễn bằng một bit dấu (dương hoặc âm), một số bit và số mũ. Không phải mọi số hữu tỷ (là số "dấu phẩy động" trong ngữ cảnh này) có thể được biểu diễn chính xác theo định dạng IEEE 754. Vì vậy, phần cứng càng gần càng tốt. Thật không may, trong trường hợp thử nghiệm của bạn, phần cứng không nhận được đại diện chính xác của bất kỳ 3 giá trị nào. Nó sẽ không ngay cả khi bạn sử dụng double
thay vì float
, điều đó awk
có thể làm.
Dưới đây là một lời giải thích thêm về khoảng cách của các số dấu phẩy động có biểu diễn nhị phân chính xác.
Bạn có thể có thể tìm thấy một số giá trị vượt qua bài kiểm tra của bạn và những giá trị khác không. Còn nhiều điều nữa không.
Thông thường mọi người giải quyết một vấn đề dấu phẩy động bằng cách làm một cái gì đó như thế này:
if (abs(c) <= epsilon) {
// We'll call it equal
} else {
// Not equal
}
Điều đó khó hơn rất nhiều để làm awk
. Nếu bạn đang kiếm tiền với các đơn vị tiền tệ và hai chữ số đáng kể của đơn vị phụ (đô la và xu, giả sử), bạn chỉ nên thực hiện tất cả các tính toán trong các đơn vị phụ (xu ở Hoa Kỳ). Không sử dụng dấu phẩy động để tính toán tiền tệ. Bạn sẽ chỉ thấy mình hối hận vì quyết định đó.
awk 'BEGIN{a=99.15;b=20.85;c=78.30;printf("%22.20f %22.20f %22.20f",a,b,c)}' 99.15000000000000568434 20.85000000000000142109 78.29999999999999715783
Cũng lưu ý rằng đại diện awk gấp đôi, mã c của bạn được sử dụng đơn (do đó lỗi lớn hơn). Đối với gấp đôi hơn 17 chữ số chính xác là không hợp lý.