Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Very big ID in JSON, how to obtain it without losing precision

I have IDs in JSON file and some of them are really big but they fit inside bounds of unsigned long long int.

"id":9223372036854775807,

How to get this large number from JSON using objectForKey:idKey of NSDictionary? Can I use NSDecimalNumber? Some of this IDs fit into regular integer.

like image 601
Prettygeek Avatar asked Dec 02 '25 14:12

Prettygeek


1 Answers

Tricky. Apple's JSON code converts integers above 10^18 to NSDecimalNumber, and smaller integers to plain NSNumber containing a 64 bit integer value. Now you might have hoped that unsignedLongLongValue would give you a 64 bit value, but it doesn't for NSDecimalNumber: The NSDecimalNumber first gets converted to double, and the result to unsigned long long, so you lose precision.

Here's something that you can add as an extension to NSNumber. It's a bit tricky, because if you get a value very close to 2^64, converting it to double might get rounded to 2^64, which cannot be converted to 64 bit. So we need to divide by 10 first to make sure the result isn't too big.

- (uint64_t)unsigned64bitValue
{
    if ([self isKindOfClass:[NSDecimalNumber class]])
    {
        NSDecimalNumber* asDecimal = (NSDecimalNumber *) self;
        uint64_t tmp = (uint64_t) (asDecimal.doubleValue / 10.0);

        NSDecimalNumber* tmp1 = [[NSDecimalNumber alloc] initWithUnsignedLongLong:tmp];
        NSDecimalNumber* tmp2 = [tmp1 decimalNumberByMultiplyingByPowerOf10: 1];
        NSDecimalNumber* remainder = [asDecimal decimalNumberBySubtracting:tmp2];

        return (tmp * 10) + remainder.unsignedLongLongValue;
    }
    else
    {
        return self.unsignedLongLongValue;
    }
}
like image 134
gnasher729 Avatar answered Dec 04 '25 07:12

gnasher729



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!