2009-01-17 17 views
43

Estoy construyendo una aplicación que necesita realizar cálculos sobre dinero.¿Cómo se usa NSDecimalNumber?

Me pregunto cómo usar correctamente NSDecimalNumber, especialmente cómo inicializarlo desde enteros, floats & ¿dobles?

Me pareció fácil de usar el método -decimalNumberWithString:. Los métodos -initWith... se desaniman por lo que sólo la izquierda los que tienen mantisa, pero nunca en uno de los 7 idiomas que he usado antes qué necesitaba que así que no sé lo que puso en su lugar ...

Respuesta

80

interés NO uso NSNumber+numberWith... métodos para crear objetos NSDecimalNumber. Se declara que devuelven objetos NSNumber y no se garantiza que funcionen como instancias NSDecimalNumber.

Esto se explica en este thread por Bill Bumgarner, un desarrollador de Apple. Le recomiendo que presente un error en contra de este comportamiento, haciendo referencia al error rdar: // 6487304.

Como alternativa estos son todos los métodos apropiados de usar para crear un NSDecimalNumber:

+ (NSDecimalNumber *)decimalNumberWithMantissa:(unsigned long long)mantissa 
        exponent:(short)exponent isNegative:(BOOL)flag; 
+ (NSDecimalNumber *)decimalNumberWithDecimal:(NSDecimal)dcm; 
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue; 
+ (NSDecimalNumber *)decimalNumberWithString:(NSString *)numberValue locale:(id)locale; 

+ (NSDecimalNumber *)zero; 
+ (NSDecimalNumber *)one; 
+ (NSDecimalNumber *)minimumDecimalNumber; 
+ (NSDecimalNumber *)maximumDecimalNumber; 
+ (NSDecimalNumber *)notANumber; 

Si simplemente desea una NSDecimalNumber de un float o int constante intentar algo como esto:

NSDecimalNumber *dn = [NSDecimalNumber decimalNumberWithDecimal: 
          [[NSNumber numberWithFloat:2.75f] decimalValue]; 
+4

Además, como se dice @orj a continuación, también es correcto usar '-initWithFloat:', '-initWithDouble:' y otros métodos. Se declara que estos devuelven 'id', y acabo de verificar que efectivamente devuelven' NSDecimalNumber' en Snow Leopard. –

+2

+1 por mencionar el valor 'decimalValue' de' NSNumber'. Eché de menos totalmente ese en los documentos. –

+0

Tal vez alguien debería cambiar el título a "Cómo hacer algo simple increíblemente complicado". Gracias de todos modos por arreglar las cosas. – turingtested

6

En cuanto al diseño, debe intentar evitar la conversión de NSDecimalNumber o NSDecimals hacia y desde int, float y valores dobles por las mismas razones por las que se recomienda utilizar NSDecimalNumbers: lo ss de precisión y problemas de representación de punto flotante binario. Lo sé, a veces es inevitable (tomando datos de un control deslizante, haciendo cálculos trigonométricos, etc.), pero debes tratar de tomar la información de los usuarios como NSStrings y luego usar initWithString: locale: o decimalNumberWithString: locale: para generar NSDecimalNumbers. Haga todas sus operaciones matemáticas con NSDecimalNumbers y devuelva su representación a los usuarios o guárdelos en SQLite (o donde sea) como su descripción de cadena utilizando descriptionWithLocale :.

Si usted tiene a la entrada de un int, float, o doble, que podría hacer algo como lo siguiente:

int myInt = 3; 
NSDecimalNumber *newDecimal = [NSDecimalNumber decimalNumberWithString:[NSString stringWithFormat:@"%d", myInt]]; 

o podría seguir la sugerencia de Ashley para asegurarse de que estás a salvo en la construcción decimal .

30

La forma correcta es en realidad para hacer esto:

NSDecimalNumber *floatDecimal = [[[NSDecimalNumber alloc] initWithFloat:42.13f] autorelease]; 
NSDecimalNumber *doubleDecimal = [[[NSDecimalNumber alloc] initWithDouble:53.1234] autorelease]; 
NSDecimalNumber *intDecimal = [[[NSDecimalNumber alloc] initWithInt:53] autorelease]; 

NSLog(@"floatDecimal floatValue=%6.3f", [floatDecimal floatValue]); 
NSLog(@"doubleDecimal doubleValue=%6.3f", [doubleDecimal doubleValue]); 
NSLog(@"intDecimal intValue=%d", [intDecimal intValue]); 

Ver más información here.