Để trả lời trực tiếp câu hỏi, đây là phiên bản của tôi bằng cách đặt tên từ hàm R :
import math
def signif(x, digits=6):
if x == 0 or not math.isfinite(x):
return x
digits -= math.ceil(math.log10(abs(x)))
return round(x, digits)
Lý do chính của tôi để đăng câu trả lời này là các ý kiến phàn nàn rằng "0,075" làm tròn thành 0,07 thay vì 0,08. Điều này là do, được chỉ ra bởi "Novice C", với sự kết hợp của số học dấu phẩy động có cả độ chính xác hữu hạn và biểu diễn cơ số 2 . Số gần nhất với 0,075 thực sự có thể được biểu diễn nhỏ hơn một chút, do đó làm tròn xuất hiện khác với những gì bạn có thể mong đợi một cách ngây thơ.
Cũng lưu ý rằng điều này áp dụng cho bất kỳ việc sử dụng số học dấu phẩy động không thập phân nào, ví dụ cả C và Java đều có cùng một vấn đề.
Để hiển thị chi tiết hơn, chúng tôi yêu cầu Python định dạng số theo định dạng "hex":
0.075.hex()
cung cấp cho chúng tôi : 0x1.3333333333333p-4
. Lý do để làm điều này là biểu diễn thập phân bình thường thường liên quan đến làm tròn và do đó không phải là cách máy tính thực sự "nhìn thấy" số. Nếu bạn chưa quen với định dạng này, một vài tài liệu tham khảo hữu ích là tài liệu Python và tiêu chuẩn C .
Để cho thấy những con số này hoạt động như thế nào một chút, chúng ta có thể quay lại điểm xuất phát của mình bằng cách thực hiện:
0x13333333333333 / 16**13 * 2**-4
Nên in ra 0.075
. 16**13
là bởi vì có 13 chữ số thập lục phân sau dấu thập phân và 2**-4
là bởi vì số mũ hex là cơ số 2.
Bây giờ chúng tôi có một số ý tưởng về cách nổi được thể hiện, chúng tôi có thể sử dụng decimal
mô-đun để cung cấp cho chúng tôi chính xác hơn, cho chúng tôi thấy những gì đang xảy ra:
from decimal import Decimal
Decimal(0x13333333333333) / 16**13 / 2**4
đưa ra: 0.07499999999999999722444243844
và hy vọng giải thích lý do tại sao round(0.075, 2)
đánh giá0.07