(This task is taken from a   Project Euler   problem.)

(All numbers herein are expressed in base ten.)


27   =   128   and   7   is
the first power of   2   whose leading decimal digits are   12.

The next power of   2   whose leading decimal digits
are   12   is   80,

280   =   1208925819614629174706176.



Define        p(L,n)      to be the  nth-smallest
value of    j    such that the base ten representation
of    2j    begins with the digits of    L .

    So   p(12, 1) =  7    and
         p(12, 2) = 80



You are also given that:

         p(123, 45)   =   12710



Task

   find: 
     p(12, 1)  
     p(12, 2)  
     p(123, 45)  
     p(123, 12345)  
     p(123, 678910)  
   display the results here, on this page.


func farey_approximations(r, callback) {
 
    var (a1 = r.int, b1 = 1)
    var (a2 = a1+1,  b2 = 1)
 
    loop {
        var a3 = a1+a2
        var b3 = b1+b2
 
        if (a3 < r*b3) {
            (a1, b1) = (a3, b3)
        }
        else {
            (a2, b2) = (a3, b3)
        }
 
        callback(a3 / b3)
    }
}
 
func p(L, nth) {
 
    define ln2  = log(2)
    define ln5  = log(5)
    define ln10 = log(10)
 
    var t = L.len-1
 
    func isok(n) {
        floor(exp(ln2*(n - floor((n*ln2)/ln10) + t) + ln5*(t - floor((n*ln2)/ln10)))) == L
    }
 
    var deltas = gather {
        farey_approximations(ln2/ln10, {|r|
            take(r.de) if (r.de.len == L.len)
            break      if (r.de.len >  L.len)
        })
    }.sort.uniq
 
    var c = 0
    var k = (1..Inf -> first(isok))
 
    loop {
        return k if (++c == nth)
        k += (deltas.first {|d| isok(k+d) } \\ die "error: #{k}")
    }
}
 
var tests = [
    [12, 1],
    [12, 2],
    [123, 45],
    [123, 12345],
    [123, 678910],
 
    # extra
    [1234, 10000],
    [12345, 10000],
]
 
for a,b in (tests) {
    say "p(#{a}, #{b}) = #{p(a,b)}"
}