Narcissistic decimal number: Difference between revisions

m
→‎{{header|AppleScript}}: "Natively written" solution modified to store digit collections as numbers instead of lists, incidentally finding results in order without needing a sort. Also reprefaced, and reheadered.
(→‎{{header|AppleScript}}: Minor modification to natively written version to match change to recommended sort.)
m (→‎{{header|AppleScript}}: "Natively written" solution modified to store digit collections as numbers instead of lists, incidentally finding results in order without needing a sort. Also reprefaced, and reheadered.)
Line 427:
<lang AppleScript>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407, 1634, 8208, 9474, 54748, 92727, 93084, 548834, 1741725, 4210818, 9800817, 9926315}</lang>
----
===Natively writtenIdiomatic===
This and an earlier version it replaces were written from scratch in AppleScript and return the required 25 numbers in around a quarter of a second. (The extreme slowness of the JavaScript/Haskell translation above is ''not'' due to AppleScript being "a little out of its depth here"!) Beyond the requirements of the task, this current version returns the first 41 numbers in just under 20 seconds, but then takes four-and-a-quarter minutes over the first 42 and thirty-eight-and-a-half minutes over the first 44. (All timings on a 3.4 GHz iMac.) The 43rd and 44th numbers are both displayed as 4.33828176939137E+15 in Script Editor's result pane, but appear to have the correct values when tested. The narcissistic decimal numbers beyond these are admittedly beyond the resolution of AppleScript's number classes.
AppleScript can certainly struggle when the code's an impenetrable and inefficient pidgin trying to be two other languages. However, when tested in 2020 on an apparently faster machine, the script above only takes 7.9 minutes to return 25 numbers. On the same machine, the natively written offering below finds the same 25 numbers in around 0.22 seconds. It uses the optimisation approach alluded to above. But this doesn't necessarily find numbers of the same width in numerical order, so all narcissistic numbers with the same number of digits have to be found before their order can be determined. Thus it takes about the same amount of time (12.9 seconds) to find the first 34 numbers as it does the first 41, the 34th to 41st numbers all having 11 digits. Nearly four and a quarter minutes are needed for the first 42 numbers and nearly an hour for the first 44. The highest narcissistic integer AppleScript can represent ''as'' an integer is the 31st in the table on the Discussion page. The highest that can be accurately displayed as a real is the 43rd, although the 44th seems to be accurate internally. For this reason, the 44th is effectively the highest narcissistic decimal number the script can identify. As per the task description, the first so many numbers are returned rather than the numbers whose digit counts fall within a specified range.
 
The JavaScript/Haskell translation above is coded not to return so many narcissistic numbers but to return those with up to so many digits. As such, it doesn't strictly conform to the current task description and only returns the required result because the 25th narcissistic decimal number also happens to be the last of the four which have 7 digits. A user of the code would have to know this in advance to be able to supply the relevant parameter. However, as I write, that code's demo call for 7 digits is commented out.
<lang applescript>use sorter : script "Insertion Sort" -- <https://www.rosettacode.org/wiki/Sorting_algorithms/Insertion_sort#AppleScript>
 
<lang applescript>(*
-- Return the first q narcissistic decimal numbers (or as many as can be represented by AppleScript reals).
(or as many of the q as can be represented by AppleScript number values).
*)
 
-- Return the first q narcissistic decimal numbers (or as many as can be represented by AppleScript reals).
on narcissisticDecimalNumbers(q)
script o
property output : {}
-- "DSN" is a convenience term for a number used to store the digits it contains.
property previousDigitLists : {{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}}
property newDigitListspreviousDSNs : missing value
property newDSNs : missing value
end script
if (q > 89) then set q to 89 -- Number of narcissistic decimal integers known to exist.
set maxM to 16 -- Maximum number of decimal digits (other than trailing zeros) in numbers that AppleScript can handlenumbers.
-- Begin with single-digit values, which are narcissticnarcissistic by definition.
repeat with i from 0 to 9
if (i ≥ q) then return o's output
set end of o's output to i
end repeat
set m to m1 +-- 1Digits/number.
set o's newDSNs to rest of o's output -- Initial DSNs. (1-9.)
-- Main loop, per increase in digits/number:
-- Find the remaining narcissistic integers, starting with 2-digit ones, if any.
-- ThisTests process tests groupscollections of digits rather than the several individual numbers that can be writtensuccessive withinteger them.values,
set-- emptyListbut happens to {}turn --up Singlethe instancenarcissistic ofnumbers anin emptynumerical listorder.
repeat until (m = maxM) -- or until returning from the handler with q results.
set mv to missing value -- Single instance of missing value.
set qm to counterm + 1
set counter to 10 -- Number of narcissistic integers obtained so far.
set m to 2 --set Newo's integerpreviousDSNs widthto ino's digits.newDSNs
set o's newDSNs to {}
-- Results with the same number of digits aren't necessarily obtained in order, so the counter's only checked when m's increased.
repeat with thisDSN in o's previousDSNs
repeat while ((counter < q) and (m ≤ maxM))
-- Derive a list of m-digit- listsBase fromnumber thefor digitfurther listsDSNs forto thebe derived from previousthis mone.
copy emptyList set baseDSN to o'sthisDSN * newDigitLists10
-- GetExtract eachthis previousone's listdigits, and calculatesubtotalling the sum of its integers raised to their current-mth powers.
repeat with i from 1 to (count o's previousDigitLists)
set counterbaseDigits to counter + 1{}
-- Get each previous list and calculate the sum of its integers raised to their mth powers.
set oldListsubtotal to item i of o's previousDigitLists0
setrepeat precalculationuntil to(thisDSN = 0)
repeat with set thisDigit into thisDSN mod oldList10
set precalculationend toof precalculationbaseDigits +to thisDigit ^ m
set subtotal to subtotal + thisDigit ^ m
set tempthisDSN to tempthisDSN div 10
end repeat
-- Derive and test new listsdigit collections having an additional digit integer each., only adding values
-- up to and including the old DSN's LSD to ensure every collection at this level is unique.
repeat with addedDigit from (end of oldList) to 9
repeat with additionalDigit from --0 Createto each(beginning newof list and store a copy.baseDigits)
set newListend of o's newDSNs to oldListbaseDSN &+ addedDigitadditionalDigit
copyset newListthisCollection to endbaseDigits of& o's newDigitListsadditionalDigit
-- AddComplete the additionalsum-of-powers digit'scalculation mthfor powerthis to the result from the other digitscollection.
set nsumResult to precalculationsubtotal + addedDigitadditionalDigit ^ m
-- Compare the result's decimal digits with those in the collection list.,
set-- tempeliminating tomatches nfrom the list one-for-one.
set temp to elsesumResult
repeat until (temp = 0)
set thisDigit to temp mod 10
if (thisDigit is not in newListthisCollection) then exit repeat
repeat with -- Where a digit matches onecollectionDigit in the list, replace the one in the list with 'missing value'.thisCollection
repeatif with(collectionDigit's listDigitcontents in= newListthisDigit) then
ifset (listDigitcollectionDigit's contents =to thisDigit)missing thenvalue
exit set listDigit's contents to mvrepeat
end exit repeatif
end ifrepeat
set temp to temp enddiv repeat10
set temp to temp div 10
else
-- Where not, abandon the checks.
exit repeat
end if
end repeat
-- If all the list's integersnumber values have been matched and replaced, the number'ssum-of-powers result is narcissistic.
if (newList(count thisCollection's integersnumbers) = emptyList0) then
tryset end of o's output to sumResult div 1
-- If set end of oit's outputthe qth tofind, nreturn asthe integerlot.
onif error((count o's output) = q) then return o's output
set end of o's output to n -- Too large to be an AS integer. Keep as real.
end try
set counter to counter + 1
end if
end repeat
end repeat
-- Prepare to go round again with an increased number of digits.
set m to m + 1
set o's previousDigitLists to o's newDigitLists
end repeat
-- SortIf we're here, the collectedrepeat reached numbersmaxM.
set end ofreturn o's output to& {"Remaining numbers beyond AppleScript's realnumber precision"}
tell sorter to sort(o's output, 1, -1)
-- If q wasn't reached, it's because the limit of precision of AppleScript reals was.
if (counter < q) then
set end of o's output to "Remaining numbers beyond AppleScript's real precision"
set q to counter + 1
end if
return items 1 thru q of o's output
end narcissisticDecimalNumbers
 
--Test codeDemo:
return narcissisticDecimalNumbers(25)</lang>
 
{{output}}
557

edits