Closed trizen closed 4 years ago
Added in https://github.com/danaj/Math-Prime-Util-GMP/commit/31dabd92bcac1b0995648bccf5770652074609a4. Many thanks!
Excellent! I just pushed some code that does this in GMP. It could be further optimized in a few ways, notably not allocating memory for each invocation (Q should easily go in place, R is a little harder but at worst could be moved in place). Calling logint() each call is also not ideal -- your code doesn't do that. On the other hand, I end recursion at 32 bits, and logint should be reasonably fast below 768 bits.
I also think there is a huge amount of wasted time in back-and-forth string conversions. That's a bigger issue in general.
I need to get a profiler running to understand where the time is being spent. For now at least it is a lot faster than before.
Before:
Sum: 10658934
FastIntegerOutput took 1.382698 seconds
Sum: 10658934
MPU_GMP took 13.51419 seconds
After:
Sum: 10658934
FastIntegerOutput took 1.436776 seconds
Sum: 10658934
MPU_GMP took 0.254289 seconds
Before:
time perl fsd.pl
FastSumOfDigits((10^1)!, 100) = 153
FastSumOfDigits((10^2)!, 100) = 3663
FastSumOfDigits((10^3)!, 100) = 57420
FastSumOfDigits((10^4)!, 100) = 818136
FastSumOfDigits((10^5)!, 100) = 10658934
FastSumOfDigits((10^6)!, 100) = 131474079
real 0m16.529s
user 0m16.443s
sys 0m0.056s
After:
$ make >/dev/null && time mpu 'say vecsum(Math::Prime::Util::GMP::todigits(factorial(10**$_),100)) for 1..6'
153
3663
57420
818136
10658934
131474079
real 0m4.426s
user 0m4.299s
sys 0m0.087s
using the vecsum(todigits(...)) method previously took over 34 minutes (ouch!).
For summation it really looks like I should add another argument to sumdigits with the output base. Right now you really have to use vecsum for that, which isn't terrible in the new code, but certainly not optimal.
Let me know about any more ideas. You have the best suggestions!
Hi. I would like to suggest a divide-and-conquer subquadratic algorithm to be used in
todigits(n,b)
, presented in the book Modern Computer Arithmetic, by Richard P. Brent and Paul Zimmermann.A simple implementation in Perl, using Math::GMPz, would be:
Output:
Furthermore, if only the sum of the digits is needed, we can make the implementation even faster by adding the digits right away:
Output: