digits_to_number_subquadratic_algorithms.sf 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. #!/usr/bin/ruby
  2. # Subquadratic algorithms for converting a given integer into a list of digits in a given base, and viceversa.
  3. # Algorithms presented in the book:
  4. #
  5. # Modern Computer Arithmetic
  6. # - by Richard P. Brent and Paul Zimmermann
  7. #
  8. func FastIntegerInput(digits, B) {
  9. var l = digits.flip
  10. var (b, k) = (B, l.len)
  11. while (k > 1) {
  12. l = l.map_slice(2, {|lx,ly|
  13. defined(ly) ? (lx + b*ly) : (lx)
  14. })
  15. (b, k) = (b*b, (k>>1)+(k&1))
  16. }
  17. l[0]
  18. }
  19. func FastIntegerOutput(A, B) {
  20. if (A < B) {
  21. return [A]
  22. }
  23. var k = (A.ilog(B)>>1 + 1)
  24. var (Q,R) = A.divmod(B**k)
  25. var r = __FUNC__(R, B)
  26. [__FUNC__(Q, B)..., (k - r.len).of(0)..., r...]
  27. }
  28. for B in (2..100) { # run some tests
  29. var N = 1e30.irand
  30. var a = N.digits(B)
  31. var b = FastIntegerOutput(N, B)
  32. assert_eq(a.flip, b)
  33. assert_eq(FastIntegerInput(b, B), N)
  34. }
  35. say FastIntegerInput(FastIntegerOutput(5040, 10), 10) #=> 5040
  36. say FastIntegerInput(FastIntegerOutput(5040, 11), 11) #=> 5040
  37. say FastIntegerInput(FastIntegerOutput(5040, 12), 12) #=> 5040
  38. say FastIntegerInput(FastIntegerOutput(5040, 13), 13) #=> 5040