Why NSDecimalNumber(string:"2175613.285964774433431797660").intValue = 0 , who can help me

88 Views Asked by At

enter image description here

Why NSDecimalNumber(string:"2175613.285964774433431797660").intValue = 0

NSDecimalNumber(string:"2175613.285964774433431797660").int32Value = 2175613

NSDecimalNumber(string:"2175613.285964774433431797660").int64Value = 0

Who can help me?

Apple M1 Mac OS Ventura 13.0 Xcode 14.1

let a = NSDecimalNumber(string: "2175613.285964774433431797660188672").intValue
// a == 0 is true 

This problem caused our users' wallet balances to clear directly to zero.

2

There are 2 best solutions below

1
Leo Dabus On

Looks like whenever the decimal significand overflows 64-bit Integer the result is unpredictable regardless of the decimal exponent value. One option to solve your issue is to round your decimal number before converting it to integer. You can overcome this issue as follow:


extension Decimal {
    func rounded(_ roundingMode: NSDecimalNumber.RoundingMode = .plain) -> Decimal {
        var result = Decimal()
        var number = self
        NSDecimalRound(&result, &number, 0, roundingMode)
        return result
    }

    var whole: Decimal { rounded(sign == .minus ? .up : .down) }
    var fraction: Decimal { self - whole }
}

extension Decimal {
    var number: NSDecimalNumber { self as NSDecimalNumber }

    var int: Int? {
        let whole = self.whole
        guard whole > Decimal(Int.min) && whole <= Decimal(Int.max) else { return nil }
        return whole.number.intValue
    }

    var int32: Int32? {
        let whole = self.whole
        guard whole > Decimal(Int32.min) && whole <= Decimal(Int32.max) else { return nil }
        return whole.number.int32Value
    }

    var int64: Int64? {
        let whole = self.whole
        guard whole > Decimal(Int64.min) && whole <= Decimal(Int64.max) else { return nil }
        return whole.number.int64Value
    }
}


let decimal1 = Decimal(string: "9223372036854775807")!
decimal1.int    // 9,223,372,036,854,775,807
decimal1.int32  // nil overflows Int32.max
decimal1.int64  // 9,223,372,036,854,775,807

let decimal2 = Decimal(string: "9223372036854775808")! // overflows Int.max
decimal2.significand        //  9,223,372,036,854,775,808 overflows Int.max
decimal2.number.intValue    // -9,223,372,036,854,775,808 undefined behavior
decimal2.number.int64Value  // -9,223,372,036,854,775,808 undefined behavior
decimal2.int    // nil
decimal2.int32  // nil
decimal2.int64  // nil

let decimal3 = Decimal(string: "2175613.9223372036854775807")! // overflows Int.max
String(describing: decimal3.significand).count // 26
decimal3.exponent           // -19
decimal3.significand        //  21,756,139,223,372,036,854,775,807 overflows Int.max
decimal3.number.intValue    // 0 undefined behavior
decimal3.number.int64Value  // 0 undefined behavior
decimal3.int    // 2,175,613
decimal3.int32  // 2,175,613
decimal3.int64  // 2,175,613
0
hida-cui On

Visit https://developer.apple.com/forums/thread/733740 ,This is Apple Foundation Bug.