107 lines
5.0 KiB
AppleScript
107 lines
5.0 KiB
AppleScript
(*
|
||
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.
|
||
*)
|
||
on selfNumbers(indexRange)
|
||
set indexRange to indexRange as list
|
||
-- Script object with subhandlers and associated properties.
|
||
script |subscript|
|
||
property startIndex : beginning of indexRange
|
||
property endIndex : end of indexRange
|
||
property counter : 0
|
||
property currentSelf : -1
|
||
property output : {}
|
||
|
||
-- Advance to the next self number in the sequence, append it to the output if required, indicate if finished.
|
||
on doneAfterAdding(interval)
|
||
set currentSelf to currentSelf + interval
|
||
set counter to counter + 1
|
||
if (counter < startIndex) then return false
|
||
set end of my output to currentSelf
|
||
return (counter = endIndex)
|
||
end doneAfterAdding
|
||
|
||
-- If necessary, fast forward to the last self number before the lowest-order block containing the first number required.
|
||
on fastForward()
|
||
if (counter ≥ startIndex) then return
|
||
-- The highest-order blocks whose ends this script 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!
|
||
set indexDiff to 9.777777778E+9
|
||
set numericDiff to 1.00000000001E+11
|
||
repeat until ((indexDiff < 98) or (counter = startIndex))
|
||
set test to counter + indexDiff
|
||
if (test < startIndex) then
|
||
set counter to test
|
||
set currentSelf to (currentSelf + numericDiff)
|
||
else
|
||
set indexDiff to (indexDiff + 2) div 10
|
||
set numericDiff to numericDiff div 10 + 1
|
||
end if
|
||
end repeat
|
||
end fastForward
|
||
|
||
-- Work out a shorter run length based on the most significant digit change about to happen.
|
||
on getShorterRunLength()
|
||
set shorterRunLength to 9
|
||
set temp to (|subscript|'s currentSelf) div 1000
|
||
repeat while (temp mod 10 is 9)
|
||
set shorterRunLength to shorterRunLength - 1
|
||
set temp to temp div 10
|
||
end repeat
|
||
return shorterRunLength
|
||
end getShorterRunLength
|
||
end script
|
||
|
||
-- Main process. Start with the single-digit odd numbers and first run.
|
||
repeat 5 times
|
||
if (|subscript|'s doneAfterAdding(2)) then return |subscript|'s output
|
||
end repeat
|
||
repeat 9 times
|
||
if (|subscript|'s doneAfterAdding(11)) then return |subscript|'s output
|
||
end repeat
|
||
-- Fast forward if the start index hasn't yet been reached.
|
||
tell |subscript| to fastForward()
|
||
|
||
-- Sequencing loop, per lowest-order block.
|
||
repeat
|
||
-- Eight ten-number runs, each at a numeric interval of 2 from the end of the previous one.
|
||
repeat 8 times
|
||
if (|subscript|'s doneAfterAdding(2)) then return |subscript|'s output
|
||
repeat 9 times
|
||
if (|subscript|'s doneAfterAdding(11)) then return |subscript|'s output
|
||
end repeat
|
||
end repeat
|
||
-- Two shorter runs, the second at an interval inversely related to their length.
|
||
set shorterRunLength to |subscript|'s getShorterRunLength()
|
||
repeat with interval in {2, 2 + (10 - shorterRunLength) * 13}
|
||
if (|subscript|'s doneAfterAdding(interval)) then return |subscript|'s output
|
||
repeat (shorterRunLength - 1) times
|
||
if (|subscript|'s doneAfterAdding(11)) then return |subscript|'s output
|
||
end repeat
|
||
end repeat
|
||
end repeat
|
||
end selfNumbers
|
||
|
||
-- Demo calls:
|
||
-- First to fiftieth self numbers.
|
||
selfNumbers({1, 50})
|
||
--> {1, 3, 5, 7, 9, 20, 31, 42, 53, 64, 75, 86, 97, 108, 110, 121, 132, 143, 154, 165, 176, 187, 198, 209, 211, 222, 233, 244, 255, 266, 277, 288, 299, 310, 312, 323, 334, 345, 356, 367, 378, 389, 400, 411, 413, 424, 435, 446, 457, 468}
|
||
|
||
-- One hundred millionth:
|
||
selfNumbers(100000000)
|
||
--> {1.022727208E+9}
|
||
|
||
-- 97,777,777,792nd:
|
||
selfNumbers(9.7777777792E+10)
|
||
--> {9.99999999997E+11}
|