How to add two NSNumber objects? - objective-c

Now this must be easy, but how can sum two NSNumber? Is like:
[one floatValue] + [two floatValue]
or exist a better way?

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.

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[].

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]);

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)

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]);
}

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

Related

Large (but representable) integers get parsed as doubles by NSNumberFormatter

I've been using the following method to parse NSString's into NSNumber's:
// (a category method on NSString)
-(NSNumber*) tryParseAsNumber {
NSNumberFormatter* formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
return [formatter numberFromString:self];
}
And I had tests verifying that this was working correctly:
test(#"".tryParseAsNumber == nil);
...
test([(#NSUIntegerMax).description.tryParseAsNumber isEqual:#NSUIntegerMax]);
...
The max-value test started failing when I switched to testing on an iPhone 6, probably because NSUInteger is now 64 bits instead of 32 bits. The value returned by the formatter is now the double 1.844674407370955e+19 instead of the uint64_t 18446744073709551615.
Is there a built-in method that succeeds exactly for all int64s and unsigned int64s, or do I have to implement one myself?
+ [NSNumber numberWithLongLong:]
+ [NSNumber numberWithUnsignedLongLong:]
Have you tried these?
EDIT
I'm not at all certain what it is you'd ultimately do with your instances of NSNumber, but consider that NSDecimalNumber seems to do exactly what you want:
NSDecimalNumber *decNum = [NSDecimalNumber decimalNumberWithString:#"18446744073709551615"];
NSLog(#"%#", decNum);
which yields:
2014-09-21 15:11:25.472 Test[1138:812724] 18446744073709551615
Here's another thing to consider: NSDecimalNumber "is a" NSNumber, as it's a subclass of the latter. So it would appear that, whatever you can do with NSNumber, you can do with NSDecimalNumber.
trudyscousin's answer allowed me to figure it out.
NSDecimalNumber decimalNumberWithString: is capable of parsing with full precision, but it lets some bad inputs by (e.g. "88ffhih" gets parsed as 88). On the other hand, NSNumberFormatter numberFromString: always detects bad inputs but loses precision. They have opposite weaknesses.
So... just do both. For example, here's a method that should parse representable NSUIntegers but nothing else:
+(NSNumber*) parseAsNSUIntegerElseNil:(NSString*)decimalText {
// NSNumberFormatter.numberFromString is good at noticing bad inputs, but loses precision for large values
// NSDecimalNumber.decimalNumberWithString has perfect precision, but lets bad inputs through sometimes (e.g. "88ffhih" -> 88)
// We use both to get both accuracy and detection of bad inputs
NSNumberFormatter* formatter = [NSNumberFormatter new];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
if ([formatter numberFromString:decimalText] == nil) {
return nil;
}
NSNumber* value = [NSDecimalNumber decimalNumberWithString:decimalText];
// Discard values not representable by NSUInteger
if (![value isEqual:#(value.unsignedIntegerValue)]) {
return nil;
}
return value;
}

arc4random in NSNumber giving negative values?

I'm creating a random number and storing it in a NSNumber object like this:
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(2^32-1)];
I also tried:
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(4294967295)];
NSNumber *index = #(arc4random_uniform(4294967295));
At some point I'm also assigning the number 1 like this:
NSNumber *index = #(1);
This should give me only positive numbers.
Later on, I print out these numbers like this:
NSString *string = [NSString stringWithFormat:#"%#", index];
This gives me some negative values for the random numbers and 1 is being printed as 1. So I though maybe if I do:
NSString *string = [NSString stringWithFormat:#"%u", index.unsignedIntValue];
I'll get only positive numbers - which I do - but now 1 is suddenly being printed as some large positive number, also.
What's going on here? How can I correctly store a u_int32 (which arc4random returns) in a NSNmber and make sure that they are only positive?
Use
NSNumber *index = [NSNumber numberWithUnsignedInt:arc4random_uniform(exp2(32)-1)];
I never get any negative numbers. arc4random_uniform(x) always returns a number between 0 and x, and the stringvalue of the NSNumber generated from it is correct.
EDIT: replaced exp2(31) with exp2(32)
You said in a comment that the index is stored in a Core Data entity as an "Integer 32" attribute, and I assume that is where the problem comes from.
Core Data dynamically generates getter and setter methods for all attributes (and relationships) of managed object classes. These accessor methods are different from the "usual" #synthesized accessor methods which are backed up by an instance variable.
For an "Integer 32" attribute, Core Data uses a (signed) integer for the attribute, and when you set a value, it is just cast or truncated to int. Example:
e.index = [NSNumber numberWithUnsignedInt:0xFFFFFFF0U];
// This would give the same result:
// e.index = [NSNumber numberWithLongLong:0x1234FFFFFFF0LL];
NSNumber *val = e.index;
NSLog(#"value=%#, type=%s", val, [val objCType]);
// Output: value=-16, type=i
The output type=i shows that the value contains an int.
If you need unsigned integers in the range 0 .. 2^32-1, then you can either (as you already did) use unsignedIntValue:
unsigned x = [val unsignedIntValue];
or store the attribute as "Integer 64".
Remarks:
I am fairly sure that this is not a problem of arc4random_uniform.
In your first code example arc4random_uniform(2^32-1), you should note that ^ is exclusive-or, not exponentiation.

Adding integers which are in strings in objective-c

For example I have "$100" and "$50" in two strings, I want to add them to get an output "$150".
I know the general method(converting them into integers and adding them), but i am searching for a shorter method which does not call many functions
You can use an NSNumberFormatter to parse the string into a NSNumber, Sum them and then convert back to String :
NSString *strNum1 = "$100";
NSString *strNum2 = "$150";
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterCurrencyStyle];
NSNumber * myFirstNumber = [f numberFromString:strNum1];
NSNumber * mySecNumber = [f numberFromString:strNum2];
NSNumber *sum = [NSNumber numberWithFloat:([myFirstNumber floatValue] + [mySecNumber floatValue])];
NSString * strSum = [f stringFromNumber:sum];
float result = [[fiftyBucks substringFromIndex:1] floatValue] + [[hundredBucks substringFromIndex:1] floatValue];
or use NSScanner, but it will be little longer, but more reliably/safely:
float fifty, hundred, result;
[[NSScaner scannerWithString: fiftyBucks] scanFloat: &fifty];
[[NSScaner scannerWithString: hundredBucks] scanFloat: &hundred];
result = fifty + hundred;
I think you better store the price at CGfloat instead.
showing a string "$100" is a front-end task and calculating the sum of the prices are back end task. These two should be seperated.
If you store the price as a CGFloat, you can simply do the maths.
And when you wanna show that string, juz implement a method.
- (NSString *)priceLabel:(CGFloat) _price {
return [NSString stringWithFormat: #"$.1f", _price];
}
Besides, don't be afraid of making a Front-end Helper model when you code. I put all this kind of minor method in this model as a class method. Wherever you need reuse this method, you can simply import the model.

Sum NSArray of NSDecimalNumbers

I know you can sum an array of NSNumbers by using the #sum.self keypath, but does that also work with NSDecimalNumbers? Will the result be accurate?
EDIT: To be more specific, here is code I know that works with NSNumber.
NSNumber *sum = [numArray valueForKeyPath:#"#sum.self"];
NSDecimalNumber is a subclass of NSNumber, so it will inherit this ability.
Also, I would recommend using one of these:
NSDecimalNumber *sum = [numArray valueForKeyPath:#"#sum.floatValue"];
float sum = [[numArray valueforKeyPath:#"#sum.floatValue"] floatValue];

#"" string type literals for NSNumber

I love the shorthand handling of string literals in Objective C with the #"string" notation. Is there any way to get similar behavior with NSNumbers? I deal with numbers more and it's so tedious having [NSNumber numberWithWhatever:] calls everywhere. Even creating a macro would work, but my knowledge of how best to do that is limited.
Since nobody has mentioned this... If you need to wrap a value in an NSNumber, the NSNumber literal syntax is as follows.
int val = 13;
NSNumber *numVal = #(val);
As of Clang v3.1 you can now use Objective-C literals.
NSNumber *fortyTwo = #42; // equivalent to [NSNumber numberWithInt:42]
NSNumber *fortyTwoUnsigned = #42U; // equivalent to [NSNumber numberWithUnsignedInt:42U]
NSNumber *fortyTwoLong = #42L; // equivalent to [NSNumber numberWithLong:42L]
NSNumber *fortyTwoLongLong = #42LL; // equivalent to [NSNumber numberWithLongLong:42LL]
So, answering your specific question:
[Tyler setArms:[[[NSNumber alloc] initWithInt:1] autorelease]];
Can now be written as:
[Tyler setArms:#1];
There are also literals for arrays and dictionaries, but they are beyond the scope of this question.
To take advantage of literals in Xcode you'll need at least version 4.4 -- this comes with Apple's LLVM 4.0 compiler.
I'm using a macro like
#define N(x) [NSNumber numberWithInt: x]
wich leads to code like
[N(123) intValue];
update:
One should be aware of the CPU and memory consumption of such a macro. While the #"…" strings are static compiler generated strings of the constant string class (depends on foundation maybe NSConstantString in Cocoa?) the macros create code which is evaluated at runtime and therefore create a new object every time they are called.
Xcode 4.4 has introduced the Clang features that rjstelling mentioned for literals for NSNumber, NSArray and NSDictionary. The syntax is simple:
//Number literal
NSNumber *pi = #3.14;
//Array literal
NSArray *primes = #[ #2, #3, #5, #7, #11 ]; //No nil terminator needed
//Dictionary literal
NSDictionary *dict = #{
#"key1": #42,
#"key2": #"Another key",
#3: #"A NSNumber key"
}; //No nil terminator, stored in "key:value," format