tldr; Nếu bạn cần độ chính xác cao hơn Double
, không sử dụng Double
.
Câu trả lời nằm trong thời điểm khi kết quả bị ép buộc thành một Double
từ một số Variant
. Một số Double
là số dấu phẩy động IEEE 754, và tính năng đảo ngược đặc điểm kỹ thuật của IEEE được đảm bảo với 15 chữ số có nghĩa. giá trị của mình tán tỉnh với giới hạn đó:
0.5 * (152 * .784637)/(133 * .784637) * 70 = 39.99999999999997 (16 sig. digits)
VBA sẽ tròn bất cứ điều gì vượt quá 15 chữ số có nghĩa khi nó được ép buộc thành một đôi:
Debug.Print CDbl("39.99999999999997") '<--Prints 40
Trong thực tế, bạn có thể xem hành vi này trong VBE. Nhập hoặc sao chép đoạn mã sau:
Dim x As Double
x = 39.99999999999997
Các VBE "tự động sửa chữa" các giá trị văn chương bằng cách đúc nó vào một Double
, mang đến cho bạn:
Dim x As Double
x = 40#
OK, vì vậy bây giờ bạn có lẽ yêu cầu những gì đã làm với sự khác biệt giữa 2 biểu thức. VBA đánh giá các biểu thức toán học bằng cách sử dụng loại biến "thứ tự cao nhất" mà nó có thể.
Trong giây Sub
của bạn, nơi bạn có tất cả các biến khai báo là Double
ở phía bên tay phải, các hoạt động được đánh giá theo trình tự cao Double
thì kết quả được ngầm cast vào một Variant
trước khi được thông qua như là thông số cho Int()
.
Trong Sub
đầu tiên của bạn, nơi bạn có Variant
tờ khai, các diễn viên tiềm ẩn để Variant
không được thực hiện trước khi đi qua để Int
- thứ tự cao nhất trong biểu thức toán học là Variant
, vì vậy không diễn viên tiềm ẩn được thực hiện trước khi đi qua kết quả là Int()
- số Variant
vẫn chứa float IEEE 754 thô.
mỗi sự documentation của Int
:
Cả Int và Fix loại bỏ các phần phân đoạn của số lượng và trả lại kết quả giá trị số nguyên.
Không làm tròn được thực hiện. Mã trên cùng gọi Int(39.99999999999997)
. Mã dưới cùng gọi Int(40)
. Câu trả lời "" phụ thuộc vào mức độ của lỗi dấu chấm động mà bạn muốn làm tròn. Nếu 15 công trình, thì 40 là câu trả lời "đúng". Nếu bạn muốn xếp bất kỳ thứ gì lên tới 16 hoặc nhiều chữ số có nghĩa, thì 39 là câu trả lời "đúng". Giải pháp là sử dụng Round
và chỉ định mức độ chính xác mà bạn đang tìm kiếm một cách rõ ràng. Ví dụ, nếu bạn quan tâm đến đủ 15 chữ số:
Int(Round((0.5 * attack/defense * 70), 15))
Hãy nhớ rằng độ chính xác cao nhất mà bạn sử dụng bất cứ nơi nào trong các yếu tố đầu là 6 chữ số, vì vậy đó sẽ là một tròn logic cắt-off:
Int(Round((0.5 * attack/defense * 70), 6))
thay đổi thứ tự của '0,5' và' 70', và bạn sẽ nhận được 39 một trong hai cách: 'Int (70 * attack/defense * 0.5)'. – ThunderFrame