I've spent considerable time today trying to calculate the Fibonacci nth term when n is a very large number. I decided to use Objective-C which in hindsight may not have been the best decision, considering how long it has taken. I researched and decided to use Binet's formula which seems to work for other people using other programming languages.
double phi = (sqrt(5) + 1) / 2.0;
long long j = (long long) round(pow(phi, number) / sqrt(5));
Is the gist of a fibonacci(number) function in C. I tried converting this to Objective-C using NSDecimalNumber, my method looks like this:
NSDecimalNumber* squareRootOfFive = [NSDecimalNumber decimalNumberWithString: [[NSNumber numberWithDouble:sqrt(5)] stringValue]];
NSDecimalNumber* phi = [[squareRootOfFive decimalNumberByAdding:[NSDecimalNumber one]] decimalNumberByDividingBy:[NSDecimalNumber decimalNumberWithString:@"2"]];
return [[[phi decimalNumberByRaisingToPower: number] decimalNumberByDividingBy:squareRootOfFive] decimalNumberByRoundingAccordingToBehavior: [NSDecimalNumberHandler decimalNumberHandlerWithRoundingMode: NSRoundPlain scale:2 raiseOnExactness:NO raiseOnOverflow:YES raiseOnUnderflow:NO raiseOnDivideByZero:NO ]];
Wonderfully readable I know. This code works for the first X Fibonacci number with X being greater than 700 but less than 800. I eventually get this error/output:
2013-02-01 17:27:19.977 Euler25[14907:303] Fibonacci number 792 has 166 digits
2013-02-01 17:27:19.989 Euler25[14907:303] *** Terminating app due to uncaught exception 'NSDecimalNumberOverflowException', reason: 'NSDecimalNumber overflow exception'
*** First throw call stack:
0 CoreFoundation 0x00007fff8c3b10a6 __exceptionPreprocess + 198
1 libobjc.A.dylib 0x00007fff880443f0 objc_exception_throw + 43
2 CoreFoundation 0x00007fff8c3b0e7c +[NSException raise:format:] + 204
3 Foundation 0x00007fff8c88bc3d -[NSDecimalNumberHandler exceptionDuringOperation:error:leftOperand:rightOperand:] + 193
4 Foundation 0x00007fff8c88ad46 _checkErrorAndRound + 60
5 Foundation 0x00007fff8c88b1e2 -[NSDecimalNumber decimalNumberByRaisingToPower:withBehavior:] + 156
6 Euler25 0x0000000100001bb2 +[Euler25 fibonacci:] + 402
7 Euler25 0x0000000100001978 main + 184
8 libdyld.dylib 0x00007fff8a5147e1 start + 0
9 ??? 0x0000000000000001 0x0 + 1
Which I can't get to format pretty. I was using this code to solve Project euler [Problem 25]( [1]: http://projecteuler.net/ [2]: https://projecteuler.net/problem=25), how does one work with large number in Objective-C if not with NSDecimalNumber, I'm not sure how to proceed further with this problem, perhaps there is some math trick I should be using?
Thanks in advance.
You have run into the maximum value that a
NSDecimalNumber
can hold. There is a function which can tell you exactly what it is. Try:It will give you:
Which happens to be 166 digits.
Objective-C/C does not support numbers larger than that, so you will need to use an Arbitrary Precision Math library. Here is another SO question which discusses some options.
EDIT:
Also, as Metabble mentions below, the maximum number of digits in the mantissa is 38 digits. This means that any calculation which results in a value larger than 38 digits will be truncated and stored with a mantissa keeping track of the number of remaining digits. When you access the results, every digit after the 38th one will be 0, which results in an incorrect value.