How to add two NSNumber objects?
Asked Answered
A

6

86

Now this must be easy, but how can sum two NSNumber? Is like:

[one floatValue] + [two floatValue]

or exist a better way?

Aladdin answered 29/1, 2009 at 23:54 Comment(0)
Y
149

There is not really a better way, but you really should not be doing this if you can avoid it. NSNumber exists as a wrapper to scalar numbers so you can store them in collections and pass them polymorphically with other NSObjects. They are not really used to store numbers in actual math. If you do math on them it is much slower than performing the operation on just the scalars, which is probably why there are no convenience methods for it.

For example:

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

Is blowing at a minimum 21 instructions on message dispatches, and however much code the methods take to unbox the and rebox the values (probably a few hundred) to do 1 instruction worth of math.

So if you need to store numbers in dicts use an NSNumber, if you need to pass something that might be a number or string into a function use an NSNumber, but if you just want to do math stick with scalar C types.

Yelp answered 30/1, 2009 at 0:2 Comment(8)
I'd add that if you need to store collections of numbers for which you intend to do a lot of math - perhaps you really want a C style array of the proper numeric type?Docent
Whenever you are doing a lot of math you want to use the scalars, you want to use the objects when you need polymorphism or they need to fit in existing containers.Yelp
The proper method on NSNumber is 'numberWithFloat:' - perhaps this has changed since the time of answering.Boland
You are correct, the getter is floatValue, so I habitually type it in both places, but stackoverflow does not give me a compile error. FixedYelp
If you look I answered the question over 5 years ago, way before literals were added.Yelp
@clopez: “Doctor, it hurts when I do this.” NSNumber is a boxed type for using with containers, not for arithmetic. If you’re doing arithmetic, use an arithmetic type.Salesperson
Sure it's slow, but what can I do if using CoreData?Carlist
This is first and foremost - a lie - about NSNumbers. There are several mechanics to allow direct manipulation and calculations on NSNumbers. the first two that come to mind are NSDecimalNumber (subclass of NSNumber) that supports calculations, and NSExpression which evaluates arbitrarily complex expressions where arguments can be NSNumber objects.Restore
H
50

NSDecimalNumber (subclass of NSNumber) has all the goodies you are looking for:

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

...

If computing performance is of interest, then convert to C++ array std::vector or like.

Now I never use C-Arrays anymore; it is too easy to crash using a wrong index or pointer. And very tedious to pair every new [] with delete[].

Halvaard answered 23/6, 2011 at 19:48 Comment(8)
Could you elaborate on what you mean by " very tedious to pair every new [] with delete[]."?Chide
Let's put it this way. In c, avoid using pointer at all. The whole point of objective-c is putting a layer on top of C you NEVER have to worry about. C is not a language to be used directly. It's something that need to be "managed" first.Onitaonlooker
After adding two NSDecimalNumbers, how to convert the NSDecimalNumber result back to NSNumber? (This question is about adding of two NSNumbers, not adding two NSDecimalNumbers.)Poleaxe
why would you ever be using a C array when you have a vector anyways?Hauptmann
Why would you want to convert a NSDecimalNumber back to an NSNumber? An NSDecimalNumber is a NSNumber: @interface NSDecimalNumber : NSNumberDavilman
I can't believe this comment has 38 upvotes. Either expand on why C++ std::vector is better or leave it out. Currently it seems biased.Caine
NSDecimalNumber is a subclass of NSNumber @PoleaxeSeely
What do arrays have to do with either the question or your answer?Restore
P
12

You can use

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

Edit: As observed by ohho, this example is for adding up two NSNumber instances that hold integer values. If you want to add up two NSNumber's that hold floating-point values, you should do the following:

NSNumber *sum = @([first floatValue] + [second floatValue]);
Pick answered 14/11, 2013 at 14:15 Comment(5)
What is the reason for the "@" symbol? I'm not sure I understand what it does in this context.Automat
Ah. I see now.... it's an NSNumber literal, as described here: https://mcmap.net/q/243584/-nsnumber-literalsAutomat
Yes, @mikemeyers it's the literal that wraps primitives like int or long or it's big brother typedef'ed NSInteger into NSNumber objects.Pick
integerValue truncates float. How this answer can be up-voted?Poleaxe
@Poleaxe this was a simple example. Why in the world would you use integerValue if you want to preserve the decimal part of the numbers?Pick
C
9

The current top-voted answer is going to lead to hard-to-diagnose bugs and loss of precision due to the use of floats. If you're doing number operations on NSNumber values, you should convert to NSDecimalNumber first and perform operations with those objects instead.

From the documentation:

NSDecimalNumber, an immutable subclass of NSNumber, provides an object-oriented wrapper for doing base-10 arithmetic. An instance can represent any number that can be expressed as mantissa x 10^exponent where mantissa is a decimal integer up to 38 digits long, and exponent is an integer from –128 through 127.

Therefore, you should convert your NSNumber instances to NSDecimalNumbers by way of [NSNumber decimalValue], perform whatever arithmetic you want to, then assign back to an NSNumber when you're done.

In Objective-C:

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

In Swift 3:

let a = NSDecimalNumber(decimal: one.decimalValue)
let b = NSDecimalNumber(decimal: two.decimalValue)
let result: NSNumber = a.adding(b)
Clemence answered 17/1, 2017 at 16:22 Comment(0)
R
1

Why not use 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"

You can also build an NSExpression that can be reused to evaluate with different arguments, like this:

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

For instance, we can loop evaluating the same parsed expression, each time with a different "Y" value:

 for (float f=20; f<30; f+=2.0) {
    NSDictionary *parameters = [NSDictionary dictionaryWithObjectsAndKeys:x, @"X", @(f), @"Y", nil];
    NSLog(@"%@", [expr expressionValueWithObject:parameters context:nil]);
 }
Restore answered 20/2, 2019 at 8:6 Comment(0)
E
-2

In Swift you can get this functionality by using the Bolt_Swift library https://github.com/williamFalcon/Bolt_Swift.

Example:

  var num1 = NSNumber(integer: 20)
  var num2 = NSNumber(integer: 25)
  print(num1+num2) //prints 45
Echinoderm answered 17/5, 2015 at 13:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.