RosettaCodeData/Task/Self-numbers/AppleScript/self-numbers.applescript

107 lines
5.0 KiB
AppleScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(*
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}