-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
math/big: large fibonacci calculation is faster in GMP #30943
Comments
Here is the fibonacci implementation:
Using math/big n=3*10^7:
Using https://github.com/ncw/gmp at n=3*10^7 (same code):
Using https://github.com/ncw/gmp at n=10^9 (same code):
|
gmp uses CGo. And according to their site https://gmplib.org/
It is expected that highly optimized C code will be faster than Go. |
divLarge is slow. |
The code doesn't use Without The time complexity of The pprof result of
|
Though I am not yet a Go developer, I am tempted to chime in, since I have implemented this in Python3. This is not how I would find the nth Fibonacci Number. Instead use the direct formula using the Golden Ration (Phi) to achieve results in O(1) time! I am uploading the code to a Public repository soon, will share link once done. Thx |
I believe the correct term to Google would be Binet's Formula... and here it is.. F(n) = round( Phi^n / √5 ) This is yet another reason to know good math and not just code! Regards |
While the fibonacci implementation is not the focus of this thread, it is clear that you have some fundamental misunderstandings about floating point as well as big integer arithmetic. Floating point numbers are only o(1) multiplication because they have finite precision. Big Integers, on the other hand, have arbitrary precision. In particular, the size we are referring to in this thread are in the millions of digits. |
@Borthralla Thanks for the insight! I do have a misunderstanding about the difference between floats and Big Integers. I will read this up in a day or two. On a side note, this is yet another reason for me to be on this forum, thanks @Borthralla. AND Exponentiation does take O(n) you are right yet again! However, also note that there may be a great benefit in writing this in a single line of code as well, esp for (smaller) integer numbers. |
@crvv Thanks for the explanation. Are there plans to support faster operations for extremely large integers in math/big similar to gmp? Is gmp's method prohibitively complex? |
Do you know offhand whether gmp uses karatsuba or a different algorithm for this? |
Definitely not. gmp stops using karatsuba pretty early:
Source: https://gmplib.org/manual/Multiplication-Algorithms.html#Multiplication-Algorithms |
The thresholds are calibrated by a calibration procedure, but for reference |
@josharian GMP uses schoolbook -> Toom-Cook -> Schönhage-Strassen for multiplication, depending on the input size. |
Does math/big include an implementation of Schönhage-Strassen? |
No, it uses karatsuba for large numbers. |
For faster asymptotic multiplication, @remyoudompheng has https://github.com/remyoudompheng/bigfft which is much faster than Also, for printing large integers @crvv noted above see #20906 |
Most observations have already been made here. To summarize:
One should probably start with the Tooms. |
Good new, guys! They found an nlog(n) multiplication algorithm, we should just use that! |
Change https://golang.org/cl/172018 mentions this issue: |
I can think of a O(log(log(n))) best case time complexity algorithm for computing exponents, which means Binet's formula might be doable for fibonacci(n). Sorry to bring this up again |
The current division algorithm produces one word of result at a time, using 2-word division to compute the top word and mulAddVWW to compute the remainder. The top word may need to be adjusted by 1 or 2 units. The recursive version, based on Burnikel, Ziegler, "Fast Recursive Division", uses the same principles, but in a multi-word setting, so that multiplication benefits from the Karatsuba algorithm (and possibly later improvements). benchmark old ns/op new ns/op delta BenchmarkDiv/20/10-4 38.2 38.3 +0.26% BenchmarkDiv/40/20-4 38.7 38.5 -0.52% BenchmarkDiv/100/50-4 62.5 62.6 +0.16% BenchmarkDiv/200/100-4 238 259 +8.82% BenchmarkDiv/400/200-4 311 338 +8.68% BenchmarkDiv/1000/500-4 604 649 +7.45% BenchmarkDiv/2000/1000-4 1214 1278 +5.27% BenchmarkDiv/20000/10000-4 38279 36510 -4.62% BenchmarkDiv/200000/100000-4 3022057 1359615 -55.01% BenchmarkDiv/2000000/1000000-4 310827664 54012939 -82.62% BenchmarkDiv/20000000/10000000-4 33272829421 1965401359 -94.09% BenchmarkString/10/Base10-4 158 156 -1.27% BenchmarkString/100/Base10-4 797 792 -0.63% BenchmarkString/1000/Base10-4 3677 3814 +3.73% BenchmarkString/10000/Base10-4 16633 17116 +2.90% BenchmarkString/100000/Base10-4 5779029 1793808 -68.96% BenchmarkString/1000000/Base10-4 889840820 85524031 -90.39% BenchmarkString/10000000/Base10-4 134338236860 4935657026 -96.33% Fixes #21960 Updates #30943 Change-Id: I134c6f81a47870c688ca95b6081eb9211def15a2 Reviewed-on: https://go-review.googlesource.com/c/go/+/172018 Reviewed-by: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
Change https://golang.org/cl/266201 mentions this issue: |
What version of Go are you using (
go version
)?Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (
go env
)?go env
OutputWhat did you do?
I wrote a Fibonacci calculator in Go using the math/big library. It was ~instant in run time up until n=10^7, after which it was extremely slow. I then used https://github.com/ncw/gmp to replace math/big with a gmp wrapper. No code was changed.
What did you expect to see?
A small performance benefit, maybe 2x or 3x.
What did you see instead?
With the same set of code, gmp quickly calculates n=10^8 in 5 seconds, while the normal math/big library takes more than 5 minutes. Gmp is even able to calculate n=10^9 after 1 minute.
The text was updated successfully, but these errors were encountered: