-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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: big.Int String conversion is slow #20906
Comments
Thanks for raising this as a separate issue. I'd like to point out that it's not just that Go is slower, but the way the time increases with the size of the
The increase in time with the increase in number of digits is not quite linear even with gmp, but it's close (1.5x to 2x linear). The increase with Go seems to be quadratic (number of digits increases 10x, time increases 100x). |
This doesn't happen when converting to a base that's a power of 2, which uses a different code path. Base 8 takes only 109 ms for 10e50,000,000 for example. pprof -top output:
|
@realityexists Thanks for the measurements, that's useful. The reason why it's faster (and why there's a different implementation) for a conversion base that's a power of 2 is of course that the conversion is trivial in that case: The result merely requires reading out the existing bits. Any base that's not a power of 2 requires real work. The basic conversion algorithm is quadratic so I'm not too surprised. But there's better approaches. |
@griesemer More than half the time is consumed in the divLarge calls from convertWords, which uses a divide and conquer algorithm to split the input. math/big doesn't currently have an implementation of Burnikel and Ziegler's Fast Recursive Division which would reduce those big divisions' asymptotic complexity to the multiplication time, ~n^1.6 for karatsuba. Does it make sense to open a separate performance issue to implement Fast Recursive Division that would speed up not only string output but any large divisions? |
@bmkessler Sure, that sounds good. Faster division would be beneficial in general. |
A relevant paper that avoids most of the divisions is: Cyril Bouvier, Paul Zimmermann. Division-Free Binary-to-Decimal Conversion. IEEE Trans- It contains both quadratic basecase and sub-quadratic algorithms. Each use one division to compute a floating point approximation of a/(base^k) and then only use multiplications in the splitting and digit generating loop, i.e. computing most significant digits first. They achieve a speedup of about 55% and 19% faster than GMP in the basecase and subquadratic cases respectively. Also, in the intro they mention that there were not able to find much relevant other literature on efficient multiprecision radix conversion besides the standard references: D. E. Knuth, R. P. Brent and P. Zimmermann, |
Was toying around with Go, implementing a factorial calculation with |
Il giorno 6 gennaio 2018, alle ore 22:25, Alex Ewerlöf <[email protected]> ha scritto:
Was toying around with Go, implementing a factorial calculation with math/big. Turns out computing 1,000,000! takes less time than actually stringifying the result.
This is normal, expected, and common to every reasonable implementation of bignums.
|
Well, I haven't tried them all so I don't know. But hopefully the Go implementation will be faster in the future. |
Just thought I would update that the recursive division change https://golang.org/cl/172018 improves string formatting considerably as expected. For the example program above about a 4x improvement.
|
(Forked out from #11068 which is about slow
big.Float
printing but will likely be fixed by not converting in full precision before printing).The following program:
which computes
2**5000000
and prints it, takes about 7 seconds on my machine to print the 1505151 characters-long answer.Almost all the time is spent generating the
String
representation ofn
. For comparison, the following equivalentgmp
program:which prints the same string, is ~20x faster.
The text was updated successfully, but these errors were encountered: