Brilliant numbers are a subset of semiprime numbers. Specifically, they are numbers that are the product of exactly two prime numbers that both have the same number of digits when expressed in base 10.

Brilliant numbers are useful in cryptography and when testing prime factoring algorithms.



E.G.
 3 × 3 (9) is a brilliant number. 
 2 × 7 (14) is a brilliant number.
 113 × 691 (78083) is a brilliant number.
 2 × 31 (62) is semiprime, but is not a brilliant number (different number of digits in the two factors).


Task
 Find and display the first 100 brilliant numbers.
 For the orders of magnitude 1 through 6, find and show the first brilliant number greater than or equal to the order of magnitude, and, its position in the series (or the count of brilliant numbers up to that point).


Stretch
 Continue for larger orders of magnitude.


See also
 Numbers Aplenty - Brilliant numbers
 OEIS:A078972 - Brilliant numbers: semiprimes whose prime factors have the same number of decimal digits


--
-- demo\rosetta\BrilliantNumbers.exw
-- =================================
--
with javascript_semantics
requires("1.0.2") -- (for in)
atom t0 = time()

function get_primes_by_digits(integer limit)
    sequence primes = get_primes_le(power(10,limit)),
             primes_by_digits = {}
    integer p = 10
    while length(primes) do
        integer pi = abs(binary_search(p,primes))-1
        primes_by_digits &= {primes[1..pi]}
        primes = primes[pi+1..$]
        p*= 10
    end while
    return primes_by_digits
end function
sequence primes_by_digits = get_primes_by_digits(8)
 
procedure first100()
    sequence brilliant_numbers = {}
    for primes in primes_by_digits do
        for i=1 to length(primes) do
--see talk page
--          for j=i to length(primes) do 
            for j=1 to i do 
                brilliant_numbers &= primes[i]*primes[j]
            end for
        end for
        if length(brilliant_numbers)>=100 then exit end if
    end for
    brilliant_numbers = sort(brilliant_numbers)[1..100]
    sequence j100 = join_by(brilliant_numbers,1,10," ","\n","%,5d")
    printf(1,"First 100 brilliant numbers:\n%s\n\n",{j100})
end procedure
first100()

atom pwr = 10, count = 0
for p=1 to 2*length(primes_by_digits)-1 do
    sequence primes = primes_by_digits[floor(p/2)+1]
    atom pos = count+1,
         min_product = 0
    for i=1 to length(primes) do
        integer p1 = primes[i],
                j = abs(binary_search(floor((pwr+p1-1)/p1),primes,i))
        if j<=length(primes) then -- (always is, I think)
            integer p2 = primes[j]
            atom prod = p1*p2
            if min_product=0 or prod<min_product then
                min_product = prod
            end if          
            pos += j-i
            if p1>=p2 then exit end if
        end if
    end for
    printf(1,"First brilliant number >= 10^%d is %,d at position %,d\n", {p, min_product, pos})
    pwr *= 10;
    if odd(p) then
        integer size = length(primes)
        count += size * (size + 1) / 2;
    end if
end for
?elapsed(time()-t0)
{} = wait_key()
