tl;dr: How should I be dealing with numbers like 20! * 20! in Objective-C?
I’m learning Objective-C by working through Project Euler. It’s been quite fun, but one problem I’ve been running in to is working with arbitrarily large numbers. I’m still pretty green on these things, so I don’t know why something like, say, Python, handles large numbers with ease compared to Obj-C.
Take for example Problem 15:
Starting in the top left corner of a 2 x 2 grid, there are 6 routes (without backtracking) to the bottom right corner.
How many routes are there through a 20 x 20 grid?
That’s easy. Using combinatorics:
(20+20)! / 20!(20!)
-> 815915283247897734345611269596115894272000000000 / 5919012181389927685417441689600000000
-> 137846528820
In Python:
import math
print math.factorial(40) / (math.factorial(20) * math.factorial(20))
In Objective-C, though? I have’t yet found a way to force such a large numbers through. Using the 2 x 2 example works fine. I can get 9C4 = 126, as it should be. But how should I be dealing with numbers like 20!?
I’ve dallied with trying to use NSDecimalNumber, which appears to support more numerals per number, assuming you can convert it to Mantissa x Exponent and don’t mind loss of precision, but that didn’t prove to be too useful, as I couldn’t figure out how to have Obj-C create a Mantissa from a %llu and I do mind loss of precision.
The code I have so far properly generates the factorials, as it appears unsigned long long handles values so large, but chokes up on x * y, and thus getCombinatoricOf:20 and:20 returns 1.
#import "Problem15.h"
@implementation Problem15
- (unsigned long long)factorial:(NSNumber *)number {
unsigned long long temp = 1;
for (int i = [number intValue]; i > 0; i--) {
temp *= i;
}
return temp;
}
- (unsigned long long)getCombinatorcOf:(NSNumber *)x and:(NSNumber *)y {
NSNumber *n = @([x intValue] + [y intValue]);
NSNumber *n_factorial = @([self factorial:n]);
NSNumber *x_factorial = @([self factorial:x]);
NSNumber *y_factorial = @([self factorial:y]);
return ([n_factorial unsignedLongLongValue] / ([x_factorial unsignedLongLongValue] * [y_factorial unsignedLongLongValue]));
}
- (NSString *)answer {
NSNumber *x = @5;
NSNumber *y = @4;
unsigned long long answer = [self getCombinatoricOf:x and:y];
return [NSString stringWithFormat:@"\n\nProblem 15: \nHow many routes are there through a 20 x 20 grid? \n%llu", answer];
}
@end
It’s not Objective-C, but you could just use GMP just as an ordinary C library.
There are also Objective-C wrappers fo GMP, like GMPInt.