के बाद से आप पहले से ही समस्या पता है "बहुत उच्च परिशुद्धता" की वजह से है, तो आपको पहले दशमलव संख्या गोलाई से यह वैकल्पिक हल कर सकते हैं:
let b = NSDecimalNumber(string: "9.999999999999999999")
print(b, "->", b.int64Value)
// 9.999999999999999999 -> -8
let truncateBehavior = NSDecimalNumberHandler(roundingMode: .down,
scale: 0,
raiseOnExactness: true,
raiseOnOverflow: true,
raiseOnUnderflow: true,
raiseOnDivideByZero: true)
let c = b.rounding(accordingToBehavior: truncateBehavior)
print(c, "->", c.int64Value)
// 9 -> 9
आप उपयोग करना int64Value
(यानी -longLongValue
) का उपयोग कर से बचने चाहते हैं सटीक 62 बिट से अधिक संख्या वाले नंबर, यानि 18 से अधिक अंकों को पूरी तरह से टालने से बचें। नीचे बताए गए कारण।
NSDecimalNumber आंतरिक रूप से एक Decimal structure के रूप में प्रस्तुत किया जाता है:
typedef struct {
signed int _exponent:8;
unsigned int _length:4;
unsigned int _isNegative:1;
unsigned int _isCompact:1;
unsigned int _reserved:18;
unsigned short _mantissa[NSDecimalMaxSize]; // NSDecimalMaxSize = 8
} NSDecimal;
यह .decimalValue
का उपयोग कर प्राप्त किया जा सकता उदा
let v2 = NSDecimalNumber(string: "9.821426272392280061")
let d = v2.decimalValue
print(d._exponent, d._mantissa, d._length)
// -18 (30717, 39329, 46888, 34892, 0, 0, 0, 0) 4
इसका मतलब यह है 9.821426272392280061 आंतरिक रूप 9821426272392280061 × 10 -18 संग्रहीत किया जाता है - ध्यान दें कि 9821426272392280061 = 34,892 × 65536 + × 65536 + × 65536 + ।
अब 9 के साथ तुलना करें।821426272392280060:
let v2 = NSDecimalNumber(string: "9.821426272392280060")
let d = v2.decimalValue
print(d._exponent, d._mantissa, d._length)
// -17 (62054, 3932, 17796, 3489, 0, 0, 0, 0) 4
ध्यान दें कि प्रतिपादक -17 के लिए कम हो जाता है, जिसका अर्थ है अनुगामी शून्य फाउंडेशन द्वारा छोड़ा गया है।
आंतरिक संरचना को जानने का, मैं अब एक दावा कर: बग क्योंकि 34,892 ≥ 32768 है। का निरीक्षण करें:
let a = NSDecimalNumber(decimal: Decimal(
_exponent: -18, _length: 4, _isNegative: 0, _isCompact: 1, _reserved: 0,
_mantissa: (65535, 65535, 65535, 32767, 0, 0, 0, 0)))
let b = NSDecimalNumber(decimal: Decimal(
_exponent: -18, _length: 4, _isNegative: 0, _isCompact: 1, _reserved: 0,
_mantissa: (0, 0, 0, 32768, 0, 0, 0, 0)))
print(a, "->", a.int64Value)
print(b, "->", b.int64Value)
// 9.223372036854775807 -> 9
// 9.223372036854775808 -> -9
ध्यान दें कि 32768 × 65536 = 2 सिर्फ एक पर हस्ताक्षर किए 64-बिट संख्या से ऊपर जाने का पर्याप्त मूल्य है। इसलिए, मुझे संदेह है कि बग फाउंडेशन के कारण int64Value
को लागू करने के कारण है (1) मंटिसा को सीधे Int64
में परिवर्तित करें, और फिर (2) 10 द्वारा विभाजित करें | एक्सपोनेंट |।
वास्तव में, यदि आप फाउंडेशन.फ्रेमवर्क को अलग करते हैं, तो आप पाएंगे कि यह मूल रूप से int64Value
लागू किया गया है (यह प्लेटफ़ॉर्म की सूचक चौड़ाई से स्वतंत्र है)।
लेकिन int32Value
क्यों प्रभावित नहीं है? क्योंकि आंतरिक रूप से इसे अभी Int32(self.doubleValue)
के रूप में कार्यान्वित किया गया है, इसलिए कोई ओवरफ़्लो समस्या नहीं होगी। दुर्भाग्य से एक डबल में केवल 53 बिट सटीक हैं, इसलिए ऐप्पल के पास int64Value
(परिशुद्धता के 64 बिट्स की आवश्यकता होती है) को फ्लोटिंग-पॉइंट अंकगणित के बिना लागू करने के अलावा कोई विकल्प नहीं है।
यदि यह प्रासंगिक है, तो इन मानों का हेक्स प्रतिनिधित्व '0xFFFFFFF8' और' 0x9' है। या बाइनरी में, '1111 1111 1111 1111 1111 1111 1111 1000' और '1001'। – nhgrif
धन्यवाद @nhgrif; मैंने इसे प्रतिबिंबित करने के लिए शीर्षक/शरीर को अद्यतन किया है। –
[संदर्भ] (एनएसएनंबर' के लिए https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSNumber_Class/) में एक चेतावनी शामिल है: "क्योंकि संख्यात्मक प्रकारों में अलग-अलग स्टोरेज क्षमताएं होती हैं , एक प्रकार के मान के साथ प्रारंभ करने और किसी अन्य प्रकार के मान तक पहुंचने का प्रयास करने से एक गलत परिणाम उत्पन्न हो सकता है " –