A number n is a self number if there is no number g such that g + the sum of g's digits = n. So 18 is not a self number because 9+9=18, 43 is not a self number because 35+5+3=43.


The task is:

 Display the first 50 self numbers;
 I believe that the 100000000th self number is 1022727208. You should either confirm or dispute my conjecture.

224036583-1 is a Mersenne prime, claimed to also be a self number. Extra credit to anyone proving it.


See also
 
OEIS: A003052 - Self numbers or Colombian numbers
Wikipedia: Self numbers
--
--  Base-10 self numbers by index (single or range).
--  Follows an observed sequence pattern whereby, after the initial single-digit odd numbers, self numbers are
--  grouped in runs whose members occur at numeric intervals of 11. Runs after the first one come in blocks of
--  ten: eight runs of ten numbers followed by two shorter runs. The numeric interval between runs is usually 2,
--  but that between shorter runs, and their length, depend on the highest-order digit change occurring in them.
--  This connection with significant digit change means every ten blocks form a higher-order block, every ten
--  of these a higher-order-still block, and so on.
--
--  The code below appears to be good up to the last self number before 10^12 — ie. 999,999,999,997, which is
--  returned as the 97,777,777,792nd such number. After this, instead of zero-length shorter runs, the actual
--  pattern apparently starts again with a single run of 10, like the one at the beginning.
--
integer startIndex, endIndex, counter
atom currentSelf
sequence output
 
function doneAfterAdding(integer interval, n)
-- Advance to the next self number in the sequence, append it to the output if required, indicate if finished.
    for i=1 to n do
        currentSelf += interval
        counter += 1
        if counter >= startIndex then
            output &= currentSelf
        end if
        if counter = endIndex then return true end if
    end for
    return false
end function
 
function selfNumbers(sequence indexRange)
    startIndex = indexRange[1]
    endIndex = indexRange[$]
    counter = 0
    currentSelf = -1
    output = {}
 
    -- Main process. Start with the single-digit odd numbers and first run.
    if doneAfterAdding(2,5) then return output end if
    if doneAfterAdding(11,9) then return output end if
 
    -- If necessary, fast forward to last self number before the lowest-order block containing first number rqd.
    if counter<startIndex then
        -- The highest-order blocks whose ends this handles correctly contain 9,777,777,778 self numbers.
        -- The difference between equivalently positioned numbers in these blocks is 100,000,000,001.
        -- The figures for successively lower-order blocks have successively fewer 7s and 0s!
        atom indexDiff = 9777777778,
             numericDiff = 100000000001
        while indexDiff>=98 and counter!=startIndex do
            if counter+indexDiff < startIndex then
                counter += indexDiff
                currentSelf += numericDiff
            else
                indexDiff = (indexDiff+2)/10    -- (..78->80->8)
                numericDiff = (numericDiff+9)/10 -- (..01->10->1)
            end if
        end while
    end if 
 
    -- Sequencing loop, per lowest-order block.
    while true do
        -- Eight ten-number runs, each at a numeric interval of 2 from the end of the previous one.
        for i=1 to 8 do
            if doneAfterAdding(2,1) then return output end if
            if doneAfterAdding(11,9) then return output end if
        end for
        -- Two shorter runs, the second at an interval inversely related to their length.
        integer shorterRunLength = 8,
                temp = floor(currentSelf/1000)
        -- Work out a shorter run length based on the most significant digit change about to happen.
        while remainder(temp,10)=9 do
            shorterRunLength -= 1
            temp = floor(temp/10)
        end while
 
        integer interval = 2
        for i=1 to 2 do
            if doneAfterAdding(interval,1) then return output end if
            if doneAfterAdding(11,shorterRunLength) then return output end if
            interval += (9-shorterRunLength)*13
        end for
    end while
end function
 
atom t0 = time()
printf(1,"The first 50 self numbers are:\n")
pp(selfNumbers({1, 50}),{pp_IntFmt,"%3d",pp_IntCh,false})
for p=8 to 9 do
    integer n = power(10,p)
    printf(1,"The %,dth safe number is %,d\n",{n,selfNumbers({n})[1]})
end for
printf(1,"completed in %s\n",elapsed(time()-t0))
