Đó là vì khi bạn in nó (ví dụ: với gói fmt
), chức năng in đã tròn thành một số lượng chữ số thập phân nhất định.
Xem ví dụ này:
const ca, cb = 0.1, 0.2
fmt.Println(ca + cb)
fmt.Printf("%.20f\n", ca+cb)
var a, b float64 = 0.1, 0.2
fmt.Println(a + b)
fmt.Printf("%.20f\n", a+b)
Output (thử nó trên Go Playground):
0.3
0.29999999999999998890
0.30000000000000004
0.30000000000000004441
Đầu tiên chúng tôi sử dụng constants bởi vì đó là khác nhau so với sử dụng các giá trị (không liên tục) loại float64
. Hằng số số đại diện cho các giá trị chính xác của độ chính xác tùy ý và không tràn.
Nhưng khi in kết quả của ca+cb
, giá trị không đổi phải được chuyển đổi thành giá trị được nhập không đổi, không đổi để có thể được chuyển đến fmt.Println()
. Giá trị này sẽ thuộc loại float64
, không thể đại diện chính xác cho 0.3
. Nhưng fmt.Println()
sẽ làm tròn nó thành ~ 16 số thập phân, sẽ là 0.3
. Nhưng khi chúng tôi tuyên bố rõ ràng chúng tôi muốn nó hiển thị với 20 chữ số, chúng tôi sẽ thấy nó không chính xác. Lưu ý rằng chỉ 0.3
mới được chuyển đổi thành float64
, vì số học không đổi 0.1+0.2
sẽ được trình biên dịch đánh giá (tại thời gian biên dịch). Tiếp theo chúng ta bắt đầu với các biến kiểu float64
, và không ngạc nhiên, đầu ra không phải là 0.3
chính xác, nhưng lần này ngay cả với làm tròn mặc định, chúng tôi nhận được kết quả khác với 0.3
. Lý do cho điều này là vì trong trường hợp đầu tiên (hằng số) là 0.3
đã được chuyển đổi, nhưng lần này cả hai 0.1
và 0.2
được chuyển đổi thành float64
, không ai trong số đó là chính xác và thêm chúng dẫn đến một số có khoảng cách lớn hơn từ 0.3
, đủ lớn để tạo "hình ảnh trực quan" với phần làm tròn mặc định của gói fmt
.
Kiểm tra tương tự/câu hỏi có liên quan + câu trả lời cho biết thêm về chủ đề:
Why do these two float64s have different values?
How does Go perform arithmetic on constants?
Golang converting float64 to int error
Does go compiler's evaluation differ for constant expression and other expression
Why does adding 0.1 multiple times remain lossless?
Golang Round to Nearest 0.05
Go: Converting float64 to int with multiplier
Hãy chắc chắn rằng Go không liên tục lần biểu thức, vì Go sử dụng chính xác thêm tại thời gian biên dịch. – user2357112
Nhờ có điều mới! – Integral