number_to_digits_subquadratic_algorithm_2.sf 1.1 KB

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