86

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

[one floatValue] + [two floatValue]

or exist a better way?

Girish
  • 4,692
  • 4
  • 35
  • 55
mamcx
  • 15,916
  • 26
  • 101
  • 189

6 Answers6

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.

Girish
  • 4,692
  • 4
  • 35
  • 55
Louis Gerbarg
  • 43,356
  • 8
  • 80
  • 90
  • 1
    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? – Kendall Helmstetter Gelner Jan 30 '09 at 06:53
  • 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. – Louis Gerbarg Jan 30 '09 at 07:36
  • The proper method on NSNumber is 'numberWithFloat:' - perhaps this has changed since the time of answering. – Nick Nov 30 '10 at 03:29
  • You are correct, the getter is floatValue, so I habitually type it in both places, but stackoverflow does not give me a compile error. Fixed – Louis Gerbarg Dec 02 '10 at 19:38
  • If you look I answered the question over 5 years ago, way before literals were added. – Louis Gerbarg Apr 06 '14 at 16:21
  • 2
    @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. – Stephen Canon Apr 08 '14 at 10:24
  • Sure it's slow, but what can I do if using CoreData? – Fidel López Jun 12 '15 at 07:11
  • 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. – Motti Shneor Feb 20 '19 at 07:14
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[].

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Semmel
  • 1,040
  • 10
  • 14
  • Could you elaborate on what you mean by " very tedious to pair every new [] with delete[]."? – jpswain Aug 12 '11 at 01:48
  • 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. – user4951 May 29 '12 at 13:45
  • After adding two `NSDecimalNumber`s, how to convert the `NSDecimalNumber` result back to `NSNumber`? (This question is about adding of two `NSNumber`s, not adding two `NSDecimalNumber`s.) – ohho Feb 05 '13 at 09:13
  • why would you ever be using a C array when you have a vector anyways? – Jake Long May 29 '13 at 20:23
  • 1
    Why would you want to convert a NSDecimalNumber back to an NSNumber? An NSDecimalNumber *is* a NSNumber: `@interface NSDecimalNumber : NSNumber` – Steven Fisher Dec 06 '13 at 19:37
  • 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. – Austin May 14 '15 at 04:58
  • NSDecimalNumber is a subclass of NSNumber @ohho – Oritm Jul 27 '15 at 17:34
  • What do arrays have to do with either the question or your answer? – Motti Shneor Feb 20 '19 at 07:15
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]);
nemesis
  • 1,349
  • 1
  • 15
  • 30
  • What is the reason for the "@" symbol? I'm not sure I understand what it does in this context. – Mike Meyers Dec 16 '13 at 21:20
  • Ah. I see now.... it's an NSNumber literal, as described here: http://stackoverflow.com/a/11120371/35723 – Mike Meyers Dec 16 '13 at 23:05
  • Yes, @mikemeyers it's the literal that wraps primitives like `int` or `long` or it's big brother `typedef`'ed `NSInteger` into `NSNumber` *objects*. – nemesis Jan 07 '14 at 02:51
  • `integerValue` truncates `float`. How this answer can be up-voted? – ohho Apr 08 '14 at 04:07
  • @ohho this was a simple example. Why in the world would you use `integerValue` if you want to preserve the decimal part of the numbers? – nemesis Apr 08 '14 at 10:14
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)
Community
  • 1
  • 1
Dan Loewenherz
  • 10,879
  • 7
  • 50
  • 81
0

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]);
 }
Motti Shneor
  • 2,095
  • 1
  • 18
  • 24
-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
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
William Falcon
  • 9,813
  • 14
  • 67
  • 110