686 Powers of Two -- v2.sf 1.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. #!/usr/bin/ruby
  2. # Daniel "Trizen" Șuteu
  3. # Date: 03 February 2020
  4. # https://github.com/trizen
  5. # https://projecteuler.net/problem=686
  6. # Runtime: 2 minutes, 10 seconds.
  7. # General solution, computing the set of differences between consecutive exponents using Farey approximations of `log_10(2)`.
  8. func farey_approximations(r, callback) {
  9. var (a1 = r.int, b1 = 1)
  10. var (a2 = a1+1, b2 = 1)
  11. loop {
  12. var a3 = a1+a2
  13. var b3 = b1+b2
  14. if (a3 < r*b3) {
  15. (a1, b1) = (a3, b3)
  16. }
  17. else {
  18. (a2, b2) = (a3, b3)
  19. }
  20. callback(a3 / b3)
  21. }
  22. }
  23. func p(L, nth) {
  24. define ln2 = log(2)
  25. define ln5 = log(5)
  26. define ln10 = log(10)
  27. var t = L.len-1
  28. func isok(n) {
  29. floor(exp(ln2*(n - floor((n*ln2)/ln10) + t) + ln5*(t - floor((n*ln2)/ln10)))) == L
  30. }
  31. var deltas = gather {
  32. farey_approximations(ln2/ln10, {|r|
  33. take(r.de) if (r.de.len == L.len)
  34. break if (r.de.len > L.len)
  35. })
  36. }.sort.uniq
  37. var c = 0
  38. var k = (1..Inf -> first_by(isok))
  39. loop {
  40. return k if (++c == nth)
  41. k += (deltas.first_by {|d| isok(k+d) } \\ die "error: #{k}")
  42. }
  43. }
  44. assert_eq(p(12, 1), 7)
  45. assert_eq(p(12, 2), 80)
  46. assert_eq(p(123, 45), 12710)
  47. say p(123, 678910)