Có hai vấn đề khác nhau ở đây. Đầu tiên - như đã đề cập trong các chú thích - số dấu phẩy động nhị phân không thể đại diện cho số 8.7
chính xác. Swift sử dụng các tiêu chuẩn IEEE 754 cho đại diện số dấu chấm động đơn và kép chính xác, và nếu bạn gán
let x = 8.7
sau đó là số biểu diễn gần nhất được lưu trữ trong x
, và đó là
8.699999999999999289457264239899814128875732421875
Bạn có thể tìm thấy thêm thông tin về điều này trong số tuyệt vời Q & A Is floating point math broken?.
Vấn đề thứ hai là: Tại sao là số đôi khi in như "8,7" và đôi khi là "8,6999999999999993"?
let str = "8.7"
print(Double(str)) // Optional(8.6999999999999993)
let x = 8.7
print(x) // 8.7
Là Double("8.7")
khác với 8.7
?Có chính xác hơn mục còn lại không?
Để trả lời những câu hỏi này, chúng ta cần phải biết làm thế nào print()
chức năng hoạt động:
- Nếu cãi nhau phù hợp với
CustomStringConvertible
, chức năng in gọi bất động sản description
của nó và in kết quả đến đầu ra tiêu chuẩn.
- Nếu không, nếu đối số phù hợp với
CustomDebugStringConvertible
, , gọi hàm là debugDescription
và in kết quả cho đầu ra tiêu chuẩn.
- Nếu không, một số cơ chế khác sẽ được sử dụng. (Không phải nhập khẩu ở đây cho mục đích của chúng tôi.)
Loại Double
phù hợp với CustomStringConvertible
, do đó
let x = 8.7
print(x) // 8.7
sẽ cho kết quả tương tự như
let x = 8.7
print(x.description) // 8.7
Nhưng những gì xảy ra trong
let str = "8.7"
print(Double(str)) // Optional(8.6999999999999993)
Double(str)
là một tùy chọn, và struct Optional
không không phù hợp với CustomStringConvertible
, nhưng để CustomDebugStringConvertible
. Do đó, chức năng in gọi thuộc tính debugDescription
của Optional
, lần lượt gọi số debugDescription
của số Double
cơ bản. Do đó - ngoài việc là một tùy chọn - đầu ra số là giống như trong
let x = 8.7
print(x.debugDescription) // 8.6999999999999993
Nhưng sự khác biệt giữa description
và debugDescription
cho các giá trị dấu chấm động là gì? Từ mã nguồn Swift, bạn có thể xem cả hai cuối cùng gọi hàm swift_floatingPointToString
trong Stubs.cpp, với thông số Debug
được đặt thành false
và true
, tương ứng. này điều khiển độ chính xác của số để chuyển đổi chuỗi:
int Precision = std::numeric_limits<T>::digits10;
if (Debug) {
Precision = std::numeric_limits<T>::max_digits10;
}
Đối với ý nghĩa của những hằng số, xem http://en.cppreference.com/w/cpp/types/numeric_limits:
digits10
- số chữ số thập phân có thể được trình bày mà không cần thay đổi,
max_digits10
- số chữ số thập phân cần thiết để phân biệt tất cả các giá trị thuộc loại này.
Vì vậy, description
tạo một chuỗi có ít chữ số thập phân hơn. Đó là chuỗi có thể được chuyển đổi thành Double
và quay lại chuỗi cho số cùng một kết quả. debugDescription
tạo chuỗi có nhiều chữ số thập phân hơn để bất kỳ hai giá trị điểm động nào khác nhau sẽ tạo ra một đầu ra khác nhau.
Tóm tắt:
- Hầu hết các số thập phân không thể được đại diện chính xác như một nhị phân giá trị dấu chấm động.
- Phương thức
description
và debugDescription
của các loại điểm nổi sử dụng độ chính xác khác để chuyển đổi thành chuỗi . Kết quả là,
- in tùy chọn giá trị dấu phẩy động sử dụng độ chính xác khác cho chuyển đổi so với in giá trị không tùy chọn.
Vì vậy trong trường hợp của bạn, có thể bạn muốn unwrap các tùy chọn trước khi in nó:
let str = "8.7"
if let d = Double(str) {
print(d) // 8.7
}
Để kiểm soát tốt hơn, sử dụng NSNumberFormatter
hoặc định dạng in với định dạng %.<precision>f
.
Tùy chọn khác có thể sử dụng (NS)DecimalNumber
thay vì Double
(ví dụ: đối với số tiền), xem ví dụ: Round Issue in swift.
sử dụng in (Double (str)!) –
Nếu câu hỏi của bạn là khoảng 8,7 so với 8,69999981 thì bạn nên đọc [Toán tử dấu chấm động bị hỏng?] (Http://stackoverflow.com/questions/588004/is-floating- point-math-broken) và [Mỗi nhà khoa học máy tính nên biết gì về số học dấu chấm động] (http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html). –
"Định dạng dấu phẩy động kép chính xác là định dạng số máy tính chiếm 8 byte (64 bit) trong bộ nhớ máy tính và đại diện cho phạm vi rộng, năng động của các giá trị bằng cách sử dụng dấu phẩy động.", Do đó bạn phải chỉ định "độ chính xác" của giá trị (độ chính xác là số chữ số trong một số). –