¿Cómo agregar dos objetos NSNumber?

79

Ahora bien, esto debe ser fácil, pero ¿cómo se pueden sumar dos NSNumber? Es como:

[one floatValue] + [two floatValue]

o existe una mejor manera?

mamcx
fuente

Respuestas:

143

Realmente no hay una mejor manera, pero realmente no debería hacer esto si puede evitarlo. NSNumberexiste como contenedor de números escalares para que pueda almacenarlos en colecciones y pasarlos polimórficamente con otros NSObjects. En realidad, no se utilizan para almacenar números en matemáticas reales. Si hace cálculos matemáticos con ellos, es mucho más lento que realizar la operación solo con los escalares, por lo que probablemente no hay métodos convenientes para ello.

Por ejemplo:

NSNumber *sum = [NSNumber numberWithFloat:([one floatValue] + [two floatValue])];

Está soplando un mínimo de 21 instrucciones en los envíos de mensajes, y sin importar la cantidad de código que necesiten los métodos para desempaquetar y volver a empaquetar los valores (probablemente unos cientos) para hacer 1 instrucción de matemáticas.

Entonces, si necesita almacenar números en dictados, use an NSNumber, si necesita pasar algo que podría ser un número o una cadena en una función, use an NSNumber, pero si solo desea hacer matemáticas con tipos escalares C.

Louis Gerbarg
fuente
1
Agregaría eso si necesita almacenar colecciones de números para los que tiene la intención de hacer muchas matemáticas, ¿quizás realmente desea una matriz de estilo C del tipo numérico adecuado?
Kendall Helmstetter Gelner
Siempre que esté haciendo muchas matemáticas, desea usar los escalares, desea usar los objetos cuando necesita polimorfismo o deben caber en contenedores existentes.
Louis Gerbarg
El método adecuado en NSNumber es 'numberWithFloat:'; quizás esto haya cambiado desde el momento de responder.
Nick
Tiene razón, el getter es floatValue, por lo que habitualmente lo escribo en ambos lugares, pero stackoverflow no me da un error de compilación. Fijo
Louis Gerbarg
2
@clopez: “Doctor, me duele cuando hago esto”. NSNumber es un tipo en caja para usar con contenedores, no para aritmética. Si está haciendo aritmética, use un tipo aritmético.
Stephen Canon
49

NSDecimalNumber (subclase de NSNumber ) tiene todas las ventajas que está buscando:

– decimalNumberByAdding:
– decimalNumberBySubtracting:
– decimalNumberByMultiplyingBy:
– decimalNumberByDividingBy:
– decimalNumberByRaisingToPower:

...

Si el rendimiento informático es de interés, conviértalo a C ++ array std :: vector o similar.

Ahora nunca más uso C-Arrays; es muy fácil fallar usando un índice o puntero incorrecto. Y muy tedioso emparejar cada nuevo [] con eliminar [].

Semmel
fuente
¿Podría explicar lo que quiere decir con "muy tedioso emparejar cada nuevo [] con eliminar []"?
jpswain
Pongámoslo de esta manera. En c, evite usar puntero en absoluto. El objetivo de objetivo-c es poner una capa encima de C de la que NUNCA tienes que preocuparte. C no es un lenguaje para usarse directamente. Es algo que primero debe "administrarse".
user4951
Después de agregar dos NSDecimalNumbers, ¿cómo convertir el NSDecimalNumberresultado a NSNumber? (Esta pregunta trata sobre la suma de dos NSNumbers, no la suma de dos NSDecimalNumbers.)
ohho
¿Por qué alguna vez usarías una matriz C cuando tienes un vector de todos modos?
Jake Long
1
¿Por qué querría convertir un NSDecimalNumber de nuevo en un NSNumber? Un NSDecimalNumber es un NSNumber:@interface NSDecimalNumber : NSNumber
Steven Fisher
12

Puedes usar

NSNumber *sum = @([first integerValue] + [second integerValue]);

Editar: como lo observó ohho , este ejemplo es para sumar dos NSNumberinstancias que contienen valores enteros. Si desea sumar dos NSNumberque contienen valores de punto flotante, debe hacer lo siguiente:

NSNumber *sum = @([first floatValue] + [second floatValue]);
justicia
fuente
¿Cuál es el motivo del símbolo "@"? No estoy seguro de entender lo que hace en este contexto.
Mike Meyers
¡Ah! Ya veo ... es un literal NSNumber, como se describe aquí: stackoverflow.com/a/11120371/35723
Mike Meyers
Sí, @mikemeyers es lo literal que envuelve primitivas como into long, o que es hermano mayor typedefed' NSIntegeren NSNumber los objetos .
némesis
integerValuetrunca float. ¿Cómo se puede mejorar esta respuesta?
ohho
@ohho este fue un ejemplo simple. ¿Por qué diablos usarías integerValuesi quieres conservar la parte decimal de los números?
némesis
6

La respuesta actual más votada conducirá a errores difíciles de diagnosticar y pérdida de precisión debido al uso de flotadores. Si está realizando operaciones numéricas en valores NSNumber, primero debe convertir a NSDecimalNumber y realizar operaciones con esos objetos.

De la documentación :

NSDecimalNumber, una subclase inmutable de NSNumber, proporciona un contenedor orientado a objetos para realizar operaciones aritméticas en base 10. Una instancia puede representar cualquier número que se pueda expresar como mantisa x 10 ^ exponente donde mantisa es un número entero decimal de hasta 38 dígitos y el exponente es un número entero de –128 a 127.

Por lo tanto, debe convertir sus instancias de NSNumber a NSDecimalNumbers [NSNumber decimalValue], realizar la aritmética que desee y luego volver a asignar un NSNumber cuando haya terminado.

En Objective-C:

NSDecimalNumber *a = [NSDecimalNumber decimalNumberWithDecimal:one.decimalValue]
NSDecimalNumber *b = [NSDecimalNumber decimalNumberWithDecimal:two.decimalValue]
NSNumber *result = [a decimalNumberByAdding:b]

En Swift 3:

let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Dan Loewenherz
fuente
0

¿Por qué no usar NSxEpression?

NSNumber *x = @(4.5), *y = @(-2);

NSExpression *ex = [NSExpression expressionWithFormat:@"(%@ + %@)", x, y];
NSNumber *result = [ex expressionValueWithObject:nil context:nil];

NSLog(@"%@",result); // will print out "2.5"

También puede crear una NSExpression que se puede reutilizar para evaluar con diferentes argumentos, como este:

NSExpression *expr = [NSExpression expressionWithFormat: @"(X+Y)"];
NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, @"X", y, @"Y", nil];
NSLog(@"%@", [expr expressionValueWithObject:parameters context:nil]);

Por ejemplo, podemos evaluar en bucle la misma expresión analizada, cada vez con un valor de "Y" diferente:

 for (float f=20; f<30; f+=2.0) {
    NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, @"X", @(f), @"Y", nil];
    NSLog(@"%@", [expr expressionValueWithObject:parameters context:nil]);
 }
Motti Shneor
fuente
-1

En Swift, puede obtener esta funcionalidad utilizando la biblioteca Bolt_Swift https://github.com/williamFalcon/Bolt_Swift .

Ejemplo:

  var num1 = NSNumber(integer: 20)
  var num2 = NSNumber(integer: 25)
  print(num1+num2) //prints 45
William Falcon
fuente