Why longLongValue returns an invalid value

I have an NSDictionary that contains a key with a value of 4937446359977427944. Am I trying to get its value as a long time and get 4937446359977427968?

NSLog(@"value1 = %@", [dict objectForKey"MyKey"]); // prints 4937446359977427944 long long lv = [dict objectForKey:@"MyKey"] longLongValue]; NSLog(@"value2 = %lld", lv); // prints 4937446359977427968 

Doing:

 NSLog(@"%lld", [@"4937446359977427944" longLongValue]); // prints 4937446359977427944 

I guess this is some kind of rounding problem, since the lower bits seem to be clearing, I just don't know how to stop this (or why this is happening).

The dictionary is created using NSJSONSerialization , and the JSON object (correctly) contains the entry "MyKey": 4937446359977427944 , and the dict object is correct.

The value held in NSDictionary is equal to NSDecimalNumber

Is something being converted to a float behind the scenes?

+3
source share
3 answers

NSDecimalValue not saved as a double , it is a 64-bit unsigned integer mantissa, an 8-bit integer with a base sign of 10, and a signed bit.

The problem is that the exact value of NSDecimalValue is only represented as ... an NSDecimalValue .

You can get an approximate value of 64EE IEE754 using the doubleValue method.

When you try to use longLongValue , you effectively get the casting result to a long int int of an approximate value of IEE754.

You may or may not consider this a mistake in the implementation of NSDecimalValue (and, ultimately, file a radar and ask Apple to use a different conversion procedure). But, strictly speaking, this is not a mistake: it is a design decision.

You should think of NSDecimalValue as a floating point decimal. In fact, it is very similar to the software implementation of what IEEE754 called a decimal floating-point number with extended precision, except that it does not meet this definition (since it does not have a metric that supports at least values ​​from -6143 to +6144 and because it does not support NAN and endlessly).

In other words, this is not an extended implementation of an integer, it is an extended (but not having NAN and infinity) implementation of a double. The fact that Apple initially provides an approximate conversion to double (implying that the conversion to long long int may or may not be accurate for any value that exceeds 53 bits of precision) is not an error.

You may or may not want to implement another transformation yourself (with a category).

Another possible point of view is to consider a problem, which is a bug in the JSon implementation that you used. But this is also very controversial: he gave you an NSDecimalValue and that, perhaps, the correct representation. Either you work with NSDecimalValue or you are responsible for any conversion.

+2
source

I am not sure if you are interested in a simple solution or just studying the details of why there is a loss of accuracy.

If you are interested in a simple answer: -[NSDecimalNumber description] displays a string with a value, and -[NSString longLongValue] converts the string to long long

 NSDecimalNumber *decimalNumber = [NSDecimalNumber decimalNumberWithString:@"4937446359977427944"]; long long longLongNumber = [[decimalNumber description] longLongValue]; NSLog(@"decimalNumber %@ -- longLongNumber %lld", decimalNumber, longLongNumber); 

exits

 2014-04-16 08:51:21.221 APP_NAME[30458:60b] decimalNumber 4937446359977427944 -- longLongNumber 4937446359977427944 

Final note

[decimalNumber descriptionWithLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US"]] can be more reliable if your application supports multiple locales.

+1
source

For everyone who is interested in a quick solution to the problem, according to the correct answer to the analog file:

 long long someNumber = 8204064638523577098; NSLog(@"some number lld: %lld", someNumber); NSNumber *snNSNumber = [NSNumber numberWithLongLong:someNumber]; NSLog(@"some number NSNumber: %@", snNSNumber); NSString *someJson = @"{\"someValue\":8204064638523577098}"; NSDictionary* dict = [NSJSONSerialization JSONObjectWithData:[someJson dataUsingEncoding:NSUTF8StringEncoding] options:0 error:nil]; NSLog(@"Dict: %@", dict); NSLog(@"Some digit out of dict: %@", [dict objectForKey:@"someValue"]); NSLog(@"Some digit out of dict as lld: %lld", [[dict objectForKey:@"someValue"] longLongValue]); long long someNumberParsed; sscanf([[[dict objectForKey:@"someValue"] stringValue] UTF8String], "%lld", &someNumberParsed); NSLog(@"Properly parsed lld: %lld", someNumberParsed); 

Results in:

2014-04-16 14: 22: 02.997 Study Guide 4 [97950: 303] some lld:
8204064638523577098

2014-04-16 14: 22: 02.998 Study Guide 4 [97950: 303] some NSNumber:
8204064638523577098

2014-04-16 14: 22: 02.998 Tutorial4 [97950: 303] Dict: {someValue = 8204064638523577098; }

2014-04-16 14: 22: 02.998 Tutorial4 [97950: 303] Some figures from the dict:
8204064638523577098

2014-04-16 14: 22: 02.999 Tutorial4 [97950: 303] Some digit from the dict as lld: 8204064638523577344

2014-04-16 14: 22: 02.999 Tutorial4 [97950: 303] Correctly disassembled:
8204064638523577098

0
source

Source: https://habr.com/ru/post/953315/


All Articles