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

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

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

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

Who can help me?

Answered by DTS Engineer in 758940022

You can avoid confusion about the decimal separator by calling init(string:locale:), passing in a fixed locale. For example:

let enGB = Locale(identifier: "en_GB")
let d = NSDecimalNumber(string: "2175613.28", locale: enGB)

Having said that, there’s definitely something weird going on here. First, let’s deal with the Swift side of this. The Swift intValue property returns a Swift Integer, which is the size of a pointer. This means that it doesn’t call the -[NSNumber intValue] method, because that always returns a CInt, aka an Int32. Rather, it calls the -integerValue method.

Some poking around in the debugger reveals that -integerValue is implemented in the superclass, NSNumber, and it just calls -longValue and returns that. -longValue is implemented in NSDecimalNumber.

So, to investigate further I switched to Objective-C:

@import Foundation;

int main(int argc, char **argv) {
    NSLocale * enGB = [NSLocale localeWithLocaleIdentifier:@"en_GB"];
    NSDecimalNumber * d = [[NSDecimalNumber alloc] initWithString:@"2175613.285964774433431797660" locale:enGB];
    NSLog(@"%@", d);                // 2175613.285964774
    NSLog(@"%f", d.doubleValue);    // 2175613.285965
    NSLog(@"%d", d.intValue);       // 2175613
    NSLog(@"%zd", d.integerValue);  // 0
    NSLog(@"%ld", d.longValue);     // 0
    return EXIT_SUCCESS;
}

This makes it clear that the Swift intValue is failing because -[NSDecimalNumber longValue] is failing. And I’ve no idea why that is. I stepped through the assembly in the debugger and it’s doing a bunch of stuff that looks kinda like the stuff you’d expect it to do, but I don’t know enough about how this type works to offer an informed opinion as to why it’s failing.

Regardless, I think it’s bugworthy. The fact that -intValue works but -longValue fails can’t be anything other than a bug, and I encourage you to file it as such. Please post your bug number, just for the record.

The workaround seems pretty straightforward: Use the int32Value property. Or use doubleValue property and truncate the fractional part.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I tested in playground

let intval = NSDecimalNumber(string:"2175613,285964774433431797660").intValue
let intval2 = NSDecimalNumber(string:"2175613").intValue
let intval3 = NSDecimalNumber(string:"2175613.285964774433431797660").int32Value```

I got

0
2175613
2175613

I changed to (dot decimal vs comma)

let intval = NSDecimalNumber(string:"2175613.285964774433431797660").intValue

And got

2175613

So that may be a problem with locale ?

Nota: but when I changed back to comma, it worked, so not sure of the explanation.

**Apple M1 Mac OS Ventura 13.0 Xcode Version 14.1 (14B47b)

locale is "en_US"

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

Accepted Answer

You can avoid confusion about the decimal separator by calling init(string:locale:), passing in a fixed locale. For example:

let enGB = Locale(identifier: "en_GB")
let d = NSDecimalNumber(string: "2175613.28", locale: enGB)

Having said that, there’s definitely something weird going on here. First, let’s deal with the Swift side of this. The Swift intValue property returns a Swift Integer, which is the size of a pointer. This means that it doesn’t call the -[NSNumber intValue] method, because that always returns a CInt, aka an Int32. Rather, it calls the -integerValue method.

Some poking around in the debugger reveals that -integerValue is implemented in the superclass, NSNumber, and it just calls -longValue and returns that. -longValue is implemented in NSDecimalNumber.

So, to investigate further I switched to Objective-C:

@import Foundation;

int main(int argc, char **argv) {
    NSLocale * enGB = [NSLocale localeWithLocaleIdentifier:@"en_GB"];
    NSDecimalNumber * d = [[NSDecimalNumber alloc] initWithString:@"2175613.285964774433431797660" locale:enGB];
    NSLog(@"%@", d);                // 2175613.285964774
    NSLog(@"%f", d.doubleValue);    // 2175613.285965
    NSLog(@"%d", d.intValue);       // 2175613
    NSLog(@"%zd", d.integerValue);  // 0
    NSLog(@"%ld", d.longValue);     // 0
    return EXIT_SUCCESS;
}

This makes it clear that the Swift intValue is failing because -[NSDecimalNumber longValue] is failing. And I’ve no idea why that is. I stepped through the assembly in the debugger and it’s doing a bunch of stuff that looks kinda like the stuff you’d expect it to do, but I don’t know enough about how this type works to offer an informed opinion as to why it’s failing.

Regardless, I think it’s bugworthy. The fact that -intValue works but -longValue fails can’t be anything other than a bug, and I encourage you to file it as such. Please post your bug number, just for the record.

The workaround seems pretty straightforward: Use the int32Value property. Or use doubleValue property and truncate the fractional part.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

FB12643940

FB12643940 (NSDecimalNumber(string:"2175613.285964774433431797660").int64Value = 0 is wrong , int32Value is OK. )

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