sách gpt4 ai đã đi

NSDecimalNumber trả về giá trị số nguyên 64 bit không mong muốn

In lại Tác giả: IT Prince Thời gian cập nhật: 2023-10-29 05:38:23 28 4
mua khóa gpt4 Nike

Tôi tình cờ phát hiện ra một hành vi kỳ lạ của NSDecimalNumber: đối với một số giá trị, hãy gọi giá trị nguyên,Giá trị dài,Giá trị dài dài v.v., trả về giá trị không mong muốn (giá trị). Ví dụ:

hãy để v = NSDecimalNumber(chuỗi: "9.821426272392280061")
v // đánh giá là 9.821426272392278
v.intValue // đánh giá là 9
v.integerValue // đánh giá là -8
v.longValue // đánh giá là -8
v.longLongValue // đánh giá là -8

hãy để v2 = NSDecimalNumber(chuỗi: "9.821426272392280060")
v2 // đánh giá là 9.821426272392278
v2.intValue // đánh giá là 9
v2.integerValue // đánh giá là 9
v2.longValue // đánh giá là 9
v2.longLongValue // đánh giá là 9

Bài viết này sử dụng XCode 7.3; tôi chưa thử nghiệm với các phiên bản trước đó của framework này.

Tôi đã thấy rất nhiều về Số thập phân NSD Thảo luận về hành vi làm tròn bất ngờ của và không sử dụng kế thừa Số NS Bộ khởi tạo sẽ khởi tạo nó, nhưng tôi không thấy thông tin gì về hành vi cụ thể này. Nhưng, Có một số thảo luận khá chi tiết về biểu diễn nội bộ và làm tròn có thể chứa thông tin hữu ích mà tôi đang tìm kiếm, vì vậy xin lỗi trước nếu tôi bỏ lỡ.

biên tập:Vấn đề này nằm trong phần bình luận nhưng tôi đã gửi nó tới Apple với mã số #25465729. Mở Radar:http://www.openradar.me/radar?id=5007005597040640 .

Sửa đổi 2:Apple đã đánh dấu đây là bản sao của #19812966.

1 Câu trả lời

Vì bạn đã biết rằng vấn đề này là do "quá chính xác", bạn có thể khắc phục bằng cách làm tròn số thập phân trước:

hãy để b = NSDecimalNumber(chuỗi: "9.99999999999999999999")
in(b, "->", b.int64Value)
// 9.9999999999999999999 -> -8

hãy truncateBehavior = NSDecimalNumberHandler(roundingMode: .down,
thang đo: 0,
raiseOnExactness: đúng,
raiseOnOverflow: đúng,
raiseOnUnderflow: đúng,
raiseOnDivideByZero: đúng)
hãy để c = b.rounding(accordingToBehavior: truncateBehavior)
in(c, "->", c.int64Value)
// 9 -> 9

Nếu bạn muốn sử dụng int64Giá trị(Ngay lập tức -longLongValue), tránh sử dụng các số có độ chính xác lớn hơn 62 chữ số hoặc tổng cộng nhiều hơn 18 chữ số. Lý do được giải thích như sau.


NSDecimalNumber được biểu diễn nội bộ như Cấu trúc thập phân :

định nghĩa kiểu cấu trúc {
có dấu int _exponent:8;
số nguyên không dấu _length:4;
int không dấu _isNegative:1;
int không dấu _isCompact:1;
int không dấu _reserved:18;
unsigned short _mantissa[NSDecimalMaxSize]; // NSDecimalMaxSize = 8
} NSDecimal;

Điều này có thể được thực hiện bằng cách sử dụng.giá trị thập phânLấy ví dụ

hãy để v2 = NSDecimalNumber(chuỗi: "9.821426272392280061")
hãy để d = v2.giá trị thập phân
in(d._exponent, d._mantissa, d._length)
// -18 (30717, 39329, 46888, 34892, 0, 0, 0, 0) 4

Điều này có nghĩa là 9.821426272392280061 được lưu trữ nội bộ dưới dạng 9821426272392280061 × 10-18 — Xin lưu ý 9821426272392280061 = 34892 × 655363 + 46888 × 655362 + 39329 × 65536 + 30717.

Bây giờ hãy so sánh với 9.821426272392280060:

hãy để v2 = NSDecimalNumber(chuỗi: "9.821426272392280060")
hãy để d = v2.giá trị thập phân
in(d._exponent, d._mantissa, d._length)
// -17 (62054, 3932, 17796, 3489, 0, 0, 0, 0) 4

Lưu ý rằng số mũ được giảm xuống còn -17, nghĩa là Foundation bỏ đi các số không theo sau.


Biết được cấu trúc bên trong, tôi xin tuyên bố: Lỗi này là do34892 ≥ 32768. quan sát:

hãy để a = NSDecimalNumber(số thập phân: Số thập phân(
_exponent: -18, _length: 4, _isNegative: 0, _isCompact: 1, _reserved: 0,
_mantissa: (65535, 65535, 65535, 32767, 0, 0, 0, 0)))
hãy để b = NSDecimalNumber(số thập phân: Số thập phân(
_exponent: -18, _length: 4, _isNegative: 0, _isCompact: 1, _reserved: 0,
_mantissa: (0, 0, 0, 32768, 0, 0, 0, 0)))
in(a, "->", a.int64Value)
in(b, "->", b.int64Value)
// 9.223372036854775807 -> 9
// 9.223372036854775808 -> -9

Xin lưu ý rằng 32768 × 655363 = 263 Giá trị của chỉ đủ lớn để tràn số 64 bit có dấu. Vì vậy, tôi nghi ngờ rằng lỗi này là do Foundation đặt int64Giá trị Được thực hiện như (1) Chuyển đổi mantissa trực tiếp thành Int64, sau đó (2) chia cho 10 |Mục lục|.

Trên thực tế, nếu bạn tháo rời Foundation.framework, bạn sẽ thấy rằng về cơ bản nó làint64Giá trị(Điều này không liên quan gì đến chiều rộng con trỏ của nền tảng).

nhưng tại sao int32Giá trị Không bị ảnh hưởng? Bởi vì bên trong nó chỉ được thực hiện như Int32(self. giá trị kép), do đó sẽ không có vấn đề tràn. Thật không may, double chỉ có độ chính xác 53 bit, do đó Apple không có lựa chọn nào khác ngoài việc triển khai nó mà không có phép toán dấu phẩy động. int64Giá trị(Yêu cầu độ chính xác 64 bit).

Liên quan đến iOS - NSDecimalNumber trả về giá trị số nguyên 64 bit không mong muốn, chúng tôi đã tìm thấy một câu hỏi tương tự trên Stack Overflow: https://stackoverflow.com/questions/36322336/

28 4 0
Giấy chứng nhận ICP Bắc Kinh số 000000
Hợp tác quảng cáo: 1813099741@qq.com 6ren.com