Есть ли способ создать NSDecimal без использования NSNumber и создания автоматически выпущенных объектов? - PullRequest
17 голосов
/ 10 января 2010

Я выполняю ряд вычислений, используя NSDecimal, и создаю каждую NSDecimal структуру, используя следующую технику:

[[NSNumber numberWithFloat:kFloatConstant] decimalValue]

Я использую NSDecimal, чтобы избежать использования автоматически выпущенных NSDecimalNumber объектов (если используется подход NSDecimalNumber для точных расчетов). Однако кажется, что механизм создания NSNumber также возвращает автоматически освобожденный NSNumber, из которого извлекается десятичное значение.

Есть ли способ создать NSDecimal без использования NSNumber и создания автоматически выпущенных объектов?

Ответы [ 2 ]

27 голосов
/ 10 января 2010

К сожалению, Apple не предоставляет каких-либо простых способов помещения значений в структуру NSDecimal. Само определение структуры можно найти в заголовке NSDecimal.h:

typedef struct {
    signed   int _exponent:8;
    unsigned int _length:4;     // length == 0 && isNegative -> NaN
    unsigned int _isNegative:1;
    unsigned int _isCompact:1;
    unsigned int _reserved:18;
    unsigned short _mantissa[NSDecimalMaxSize];
} NSDecimal;

но я не знаю, буду ли я пытаться перепроектировать, как структуры содержат значения. Подчеркивания на полях в структуре указывают, что они являются частными и могут быть изменены. Я не представляю, что в низкоуровневых функциях NSDecimal происходит много изменений, но я буду нервничать по поводу того, что что-то сломается в какой-то момент.

Учитывая, что инициализация NSDecimal из числа с плавающей запятой лучше всего делать описанным вами способом. Однако следует помнить, что всякий раз, когда вы используете значение с плавающей запятой, вы теряете точность, достигнутую с помощью NSDecimal, и будете подвергаться ошибкам с плавающей запятой.

Я всегда работаю только с NSDecimals в своих высокоточных вычислениях и беру и экспортирую NSStrings для обмена этими значениями с внешним миром. Чтобы создать NSDecimal на основе NSString, вы можете использовать подход, который мы используем в Core Plot framework :

NSDecimal CPDecimalFromString(NSString *stringRepresentation)
{
    NSDecimal result;
    NSScanner *theScanner = [[NSScanner alloc] initWithString:stringRepresentation];
    [theScanner scanDecimal:&result];
    [theScanner release];

    return result;
}

Использование NSScanner вместо NSDecimalNumber -initWithString:locale: примерно на 90% быстрее в моих тестах.

2 голосов
/ 14 июня 2013

Чтобы ответить на «без автоматически выпущенных объектов» , просто:

NSDecimalNumber *intermediateNumber = [[NSDecimalNumber alloc] initWithFloat:kFloatConstant];
NSDecimal decimal = [intermediateNumber decimalValue];
[intermediateNumber release];
...