NSDecimalNumber и большие беззнаковые длинные (64-разрядные) целые числа

Я обрабатываю большие 64-разрядные целые числа без знака из источника JSON, которые анализируются в NSDecimalNumbers, что, по-видимому, "верно представляет числа произвольной точности".

Проблема, с которой я сталкиваюсь, заключается в том, что я не могу получить правильные цифры из этого класса. Например (используя наибольшее возможное значение):

print (unsigned long long) [[NSDecimalNumber decimalNumberWithString:@"18446744073709551615"] unsignedLongLongValue]
= 0 // Incorrect
print (unsigned long long) [[NSDecimalNumber decimalNumberWithString:@"9223372036854775808"] unsignedLongLongValue]
= 9223372036854775808 // Correct
print (unsigned long long) [[NSDecimalNumber decimalNumberWithString:@"9223372036854775810"] unsignedLongLongValue]
= 9223372036854775808 // Incorrect

Похоже, что я не могу получить ничего большего, чем максимальное значащее долгое значение из NSDecimalNumber. Это не нравится значениям больше 9223372036854775808. Однако кажется, что число хранится в полной точности в NSDecimalNumber, как:

po [[NSDecimalNumber decimalNumberWithString:@"18446744073709551615"] stringValue]
= 18446744073709551615

Я заметил, что объекты NSNumber могут обрабатывать эти большие числа, а unsignedLongLongValue работает правильно. Это просто NSDecimalNumbers (который я застрял), которые не работают.

Как я могу получить правильные значения unsigned long long из NSDecimalNumbers? Или, по крайней мере, преобразовать их в объекты NSNumber, где unsignedLongLongValue действительно работает.

Ответы

Ответ 1

У меня был ответ от Apple по этой проблеме через форумы разработчиков:

Это постоянная проблема с NSDecimalNumber, где простой Аксессоры (например, [unsigned] longLongValue) проходят через doubleValue accessor - это любое значение, требующее более 53 бит точности будет неправильно округлено. Не стесняйтесь сообщать об ошибке выпустить и указать номер ошибки 8220543.

Тем не менее, если вы просто получая 64-битные номера от JSON, вы должны просто использовать NSNumber вместо NSDecimalNumber.

Поэтому я решаю это, изменяя парсер от SBJson до JSONKit, который не только намного быстрее, но и отображает числа в объекты NSNumber вместо объектов NSDecimalNumber.

Ответ 2

Если вы все еще хотите извлечь длинное длинное значение без знака из NSDecimalNumber, вы можете использовать подход, предложенный johne здесь, и сделать что-то вроде следующего:

NSDecimalNumber *testNumber = [NSDecimalNumber decimalNumberWithString:@"18446744073709551615"];
unsigned long long ullvalue = strtoull([[testNumber stringValue] UTF8String], NULL, 0);
NSLog(@"Number:%llu", ullvalue);

который дает правильный результат

Номер: 18446744073709551615

Я попытался сделать это с помощью NSScanner:

NSScanner *theScanner = [[NSScanner alloc] initWithString:[testNumber stringValue]];
unsigned long long outputValue;

[theScanner scanLongLong:(long long *)&outputValue];
[theScanner release];

но, к сожалению, он только считывает подписанные длинные длинные значения, поэтому приведенное выше дает неправильное значение 9223372036854775807.