Self-describing numbers: Difference between revisions
(→{{header|AppleScript}}: Added a draft 'selfDescribes' predicate in Applescript) |
(→{{header|AppleScript}}: Updated predicate.) |
||
Line 128: | Line 128: | ||
on selfDescribes(x) |
on selfDescribes(x) |
||
set s to str(x) |
set s to str(x) |
||
set descripn to |λ|(my groupBy(my eq, my sort(characters of s))) of my described({¬ |
set descripn to my str(|λ|(my groupBy(my eq, my sort(characters of s))) of my described({¬ |
||
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}) |
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"})) |
||
1 = (offset of |
1 = (offset of descripn in s) and ¬ |
||
0 = ((items ((length of descripn) + 1) thru -1 of s) as string as integer) |
|||
end selfDescribes |
end selfDescribes |
||
Line 168: | Line 169: | ||
-------------------- GENERIC FUNCTIONS -------------------- |
-------------------- GENERIC FUNCTIONS -------------------- |
||
-- True if every value in the list is true. |
|||
-- and :: [Bool] -> Bool |
|||
on |and|(xs) |
|||
repeat with x in xs |
|||
if not (contents of x) then return false |
|||
end repeat |
|||
return true |
|||
end |and| |
|||
-- eq (==) :: Eq a => a -> a -> Bool |
-- eq (==) :: Eq a => a -> a -> Bool |
Revision as of 12:18, 30 April 2020
You are encouraged to solve this task according to the task description, using any language you may know.
There are several so-called "self-describing" or "self-descriptive" integers.
An integer is said to be "self-describing" if it has the property that, when digit positions are labeled 0 to N-1, the digit in each position is equal to the number of times that that digit appears in the number.
For example, 2020 is a four-digit self describing number:
- position 0 has value 2 and there are two 0s in the number;
- position 1 has value 0 and there are no 1s in the number;
- position 2 has value 2 and there are two 2s;
- position 3 has value 0 and there are zero 3s.
Self-describing numbers < 100.000.000 are: 1210, 2020, 21200, 3211000, 42101000.
- Task Description
- Write a function/routine/method/... that will check whether a given positive integer is self-describing.
- As an optional stretch goal - generate and display the set of self-describing numbers.
- Related tasks
- Fours is the number of letters in the ...
- Look-and-say sequence
- Number names
- Self-referential sequence
- Spelling of ordinal numbers
Ada
<lang Ada>with Ada.Text_IO; use Ada.Text_IO; procedure SelfDesc is
subtype Desc_Int is Long_Integer range 0 .. 10**10-1;
function isDesc (innum : Desc_Int) return Boolean is subtype S_Int is Natural range 0 .. 10; type S_Int_Arr is array (0 .. 9) of S_Int; ref, cnt : S_Int_Arr := (others => 0); n, digit : S_Int := 0; num : Desc_Int := innum; begin loop digit := S_Int (num mod 10); ref (9 - n) := digit; cnt (digit) := cnt (digit) + 1; num := num / 10; exit when num = 0; n := n + 1; end loop; return ref (9 - n .. 9) = cnt (0 .. n); end isDesc;
begin
for i in Desc_Int range 1 .. 100_000_000 loop if isDesc (i) then Put_Line (Desc_Int'Image (i)); end if; end loop;
end SelfDesc;</lang>
- Output:
1210 2020 21200 3211000 42101000
ALGOL 68
<lang algol68>BEGIN
# return TRUE if number is self describing, FALSE otherwise # OP SELFDESCRIBING = ( INT number )BOOL: BEGIN
[10]INT counts := ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ); INT n := number; INT digits := 0;
# count the occurances of each digit # WHILE n /= 0 DO digits +:= 1; counts[ ( n MOD 10 ) + 1 ] +:= 1; n OVERAB 10 OD;
# construct the number that the counts would describe, # # if the number was self describing #
INT described number := 0; FOR i TO digits DO described number *:= 10; described number +:= counts[ i ] OD;
# if the described number is the input number, # # it is self describing # ( number = described number ) END; # SELFDESCRIBING #
main: (
FOR i TO 100 000 000 DO IF SELFDESCRIBING i THEN print( ( i, " is self describing", newline ) ) FI OD
)
END</lang>
- Output:
+1210 is self describing +2020 is self describing +21200 is self describing +3211000 is self describing +42101000 is self describing
AppleScript
<lang applescript>use AppleScript version "2.4" use framework "Foundation" use scripting additions
-- selfDescribes :: Int -> Bool
on selfDescribes(x)
set s to str(x) set descripn to my str(|λ|(my groupBy(my eq, my sort(characters of s))) of my described({¬ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"})) 1 = (offset of descripn in s) and ¬ 0 = ((items ((length of descripn) + 1) thru -1 of s) as string as integer)
end selfDescribes
-- described :: [Char] -> Char -> [Char]
on described(digits)
script on |λ|(groups) if 0 < length of digits and 0 < length of groups then set grp to item 1 of groups set go to described(rest of digits) if item 1 of digits = item 1 of (item 1 of grp) then {item 1 of my str(length of grp)} & |λ|(rest of groups) of go else {"0"} & |λ|(groups) of go end if else {} end if end |λ| end script
end described
TEST ---------------------------
on run
script test on |λ|(n) str(n) & " -> " & str(selfDescribes(n)) end |λ| end script unlines(map(test, ¬ {1210, 1211, 2020, 2022, 21200, 21203, 3211000, 3211004}))
end run
GENERIC FUNCTIONS --------------------
-- True if every value in the list is true. -- and :: [Bool] -> Bool on |and|(xs)
repeat with x in xs if not (contents of x) then return false end repeat return true
end |and|
-- eq (==) :: Eq a => a -> a -> Bool
on eq(a, b)
a = b
end eq
-- foldl :: (a -> b -> a) -> a -> [b] -> a
on foldl(f, startValue, xs)
tell mReturn(f) set v to startValue set lng to length of xs repeat with i from 1 to lng set v to |λ|(v, item i of xs, i, xs) end repeat return v end tell
end foldl
-- Typical usage: groupBy(on(eq, f), xs)
-- groupBy :: (a -> a -> Bool) -> [a] -> a
on groupBy(f, xs)
set mf to mReturn(f) script enGroup on |λ|(a, x) if length of (active of a) > 0 then set h to item 1 of active of a else set h to missing value end if if h is not missing value and mf's |λ|(h, x) then {active:(active of a) & {x}, sofar:sofar of a} else {active:{x}, sofar:(sofar of a) & {active of a}} end if end |λ| end script if length of xs > 0 then set dct to foldl(enGroup, {active:{item 1 of xs}, sofar:{}}, rest of xs) if length of (active of dct) > 0 then sofar of dct & {active of dct} else sofar of dct end if else {} end if
end groupBy
-- map :: (a -> b) -> [a] -> [b]
on map(f, xs)
-- The list obtained by applying f -- to each element of xs. tell mReturn(f) set lng to length of xs set lst to {} repeat with i from 1 to lng set end of lst to |λ|(item i of xs, i, xs) end repeat return lst end tell
end map
-- mReturn :: First-class m => (a -> b) -> m (a -> b)
on mReturn(f)
-- 2nd class handler function lifted into 1st class script wrapper. if script is class of f then f else script property |λ| : f end script end if
end mReturn
-- sort :: Ord a => [a] -> [a]
on sort(xs)
((current application's NSArray's arrayWithArray:xs)'s ¬ sortedArrayUsingSelector:"compare:") as list
end sort
-- str :: a -> String
on str(x)
x as string
end str
-- unlines :: [String] -> String
on unlines(xs)
-- A single string formed by the intercalation -- of a list of strings with the newline character. set {dlm, my text item delimiters} to ¬ {my text item delimiters, linefeed} set s to xs as text set my text item delimiters to dlm s
end unlines</lang>
- Output:
1210 -> true 1211 -> false 2020 -> true 2022 -> false 21200 -> true 21203 -> false 3211000 -> true 3211004 -> false
AutoHotkey
Uses CountSubString: Count occurrences of a substring#AutoHotkey <lang AutoHotkey>; The following directives and commands speed up execution:
- NoEnv
SetBatchlines -1 ListLines Off Process, Priority,, high
MsgBox % 2020 ": " IsSelfDescribing(2020) "`n" 1337 ": " IsSelfDescribing(1337) "`n" 1210 ": " IsSelfDescribing(1210) Loop 100000000
If IsSelfDescribing(A_Index) list .= A_Index "`n"
MsgBox % "Self-describing numbers < 100000000 :`n" . list
CountSubstring(fullstring, substring){
StringReplace, junk, fullstring, %substring%, , UseErrorLevel return errorlevel
}
IsSelfDescribing(number){
Loop Parse, number If Not CountSubString(number, A_Index-1) = A_LoopField return false return true
}</lang> Output:
--------------------------- Self.ahk --------------------------- Self-describing numbers < 100000000 : 1210 2020 21200 3211000 42101000 --------------------------- OK ---------------------------
AWK
<lang AWK># syntax: GAWK -f SELF-DESCRIBING_NUMBERS.AWK BEGIN {
for (n=1; n<=100000000; n++) { if (is_self_describing(n)) { print(n) } } exit(0)
} function is_self_describing(n, i) {
for (i=1; i<=length(n); i++) { if (substr(n,i,1) != gsub(i-1,"&",n)) { return(0) } } return(1)
}</lang>
output:
1210 2020 21200 3211000 42101000
BASIC
<lang qbasic>Dim x, r, b, c, n, m As Integer Dim a, d As String Dim v(10), w(10) As Integer Cls For x = 1 To 5000000
a$ = ltrim$(Str$(x)) b = Len(a$) For c = 1 To b d$ = Mid$(a$, c, 1) v(Val(d$)) = v(Val(d$)) + 1 w(c - 1) = Val(d$) Next c r = 0 For n = 0 To 10 If v(n) = w(n) Then r = r + 1 v(n) = 0 w(n) = 0 Next n If r = 11 Then Print x; " Yes,is autodescriptive number"
Next x Print Print "End" sleep end</lang>
BBC BASIC
<lang bbcbasic> FOR N = 1 TO 5E7
IF FNselfdescribing(N) PRINT N NEXT END DEF FNselfdescribing(N%) LOCAL D%(), I%, L%, O% DIM D%(9) O% = N% L% = LOG(N%) WHILE N% I% = N% MOD 10 D%(I%) += 10^(L%-I%) N% DIV=10 ENDWHILE = O% = SUM(D%())</lang>
Output:
1210 2020 21200 3211000 42101000
Befunge
Although we simply list the conforming numbers - nothing more.
Be aware, though, that even with a fast interpreter, it's going to be a very long time before you see the full set of results.
<lang befunge>>1+9:0>\#06#:p#-:#1_$v ?v6:%+55:\+1\<<<\0:::<
- >g1+\6p55+/:#^_001p\v
^_@#!`<<v\+g6g10*+55\< >:*:*:*^>>:01g1+:01p`| ^_\#\:#+.#5\#5,#$:<-$<</lang>
- Output:
1210 2020 21200 3211000 42101000
C
Using integers instead of strings. <lang c>#include <stdio.h>
inline int self_desc(unsigned long long xx) { register unsigned int d, x; unsigned char cnt[10] = {0}, dig[10] = {0};
for (d = 0; xx > ~0U; xx /= 10) cnt[ dig[d++] = xx % 10 ]++;
for (x = xx; x; x /= 10) cnt[ dig[d++] = x % 10 ]++;
while(d-- && dig[x++] == cnt[d]);
return d == -1; }
int main() { int i; for (i = 1; i < 100000000; i++) /* don't handle 0 */ if (self_desc(i)) printf("%d\n", i);
return 0; }</lang>output<lang>1210 2020 21200 3211000 42101000</lang>
Backtracking version
Backtracks on each digit from right to left, takes advantage of constraints "sum of digit values = number of digits" and "sum of (digit index * digit value) = number of digits". It is using as argument the list of allowed digits (example 012345789 to run the program in standard base 10). <lang c>#include <stdio.h>
- include <stdlib.h>
- include <string.h>
- define BASE_MIN 2
- define BASE_MAX 94
void selfdesc(unsigned long);
const char *ref = "!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; char *digs; unsigned long *nums, *inds, inds_sum, inds_val, base;
int main(int argc, char *argv[]) { int used[BASE_MAX]; unsigned long digs_n, i; if (argc != 2) { fprintf(stderr, "Usage is %s <digits>\n", argv[0]); return EXIT_FAILURE; } digs = argv[1]; digs_n = strlen(digs); if (digs_n < BASE_MIN || digs_n > BASE_MAX) { fprintf(stderr, "Invalid number of digits\n"); return EXIT_FAILURE; } for (i = 0; i < BASE_MAX; i++) { used[i] = 0; } for (i = 0; i < digs_n && strchr(ref, digs[i]) && !used[digs[i]-*ref]; i++) { used[digs[i]-*ref] = 1; } if (i < digs_n) { fprintf(stderr, "Invalid digits\n"); return EXIT_FAILURE; } nums = calloc(digs_n, sizeof(unsigned long)); if (!nums) { fprintf(stderr, "Could not allocate memory for nums\n"); return EXIT_FAILURE; } inds = malloc(sizeof(unsigned long)*digs_n); if (!inds) { fprintf(stderr, "Could not allocate memory for inds\n"); free(nums); return EXIT_FAILURE; } inds_sum = 0; inds_val = 0; for (base = BASE_MIN; base <= digs_n; base++) { selfdesc(base); } free(inds); free(nums); return EXIT_SUCCESS; }
void selfdesc(unsigned long i) { unsigned long diff_sum, upper_min, j, lower, upper, k; if (i) { diff_sum = base-inds_sum; upper_min = inds_sum ? diff_sum:base-1; j = i-1; if (j) { lower = 0; upper = (base-inds_val)/j; } else { lower = diff_sum; upper = diff_sum; } if (upper < upper_min) { upper_min = upper; } for (inds[j] = lower; inds[j] <= upper_min; inds[j]++) { nums[inds[j]]++; inds_sum += inds[j]; inds_val += inds[j]*j; for (k = base-1; k > j && nums[k] <= inds[k] && inds[k]-nums[k] <= i; k--); if (k == j) { selfdesc(i-1); } inds_val -= inds[j]*j; inds_sum -= inds[j]; nums[inds[j]]--; } } else { for (j = 0; j < base; j++) { putchar(digs[inds[j]]); } puts(""); } }</lang>
Output for base 36 <lang>$ time ./selfdesc.exe 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ 1210 2020 21200 3211000 42101000 521001000 6210001000 72100001000 821000001000 9210000001000 A2100000001000 B21000000001000 C210000000001000 D2100000000001000 E21000000000001000 F210000000000001000 G2100000000000001000 H21000000000000001000 I210000000000000001000 J2100000000000000001000 K21000000000000000001000 L210000000000000000001000 M2100000000000000000001000 N21000000000000000000001000 O210000000000000000000001000 P2100000000000000000000001000 Q21000000000000000000000001000 R210000000000000000000000001000 S2100000000000000000000000001000 T21000000000000000000000000001000 U210000000000000000000000000001000 V2100000000000000000000000000001000 W21000000000000000000000000000001000
real 0m0.094s user 0m0.046s sys 0m0.030s</lang>
C++
<lang cpp>
- include <iostream>
//-------------------------------------------------------------------------------------------------- typedef unsigned long long bigint;
//-------------------------------------------------------------------------------------------------- using namespace std;
//-------------------------------------------------------------------------------------------------- class sdn { public:
bool check( bigint n ) {
int cc = digitsCount( n ); return compare( n, cc );
} void displayAll( bigint s ) {
for( bigint y = 1; y < s; y++ ) if( check( y ) ) cout << y << " is a Self-Describing Number." << endl;
}
private:
bool compare( bigint n, int cc ) {
bigint a; while( cc ) { cc--; a = n % 10; if( dig[cc] != a ) return false; n -= a; n /= 10; } return true;
} int digitsCount( bigint n ) {
int cc = 0; bigint a; memset( dig, 0, sizeof( dig ) ); while( n ) { a = n % 10; dig[a]++; cc++ ; n -= a; n /= 10; } return cc;
} int dig[10];
}; //-------------------------------------------------------------------------------------------------- int main( int argc, char* argv[] ) {
sdn s; s. displayAll( 1000000000000 ); cout << endl << endl; system( "pause" ); bigint n; while( true ) {
system( "cls" ); cout << "Enter a positive whole number ( 0 to QUIT ): "; cin >> n; if( !n ) return 0; if( s.check( n ) ) cout << n << " is"; else cout << n << " is NOT"; cout << " a Self-Describing Number!" << endl << endl; system( "pause" );
} return 0;
} </lang>
- Output:
1210 is a Self-Describing Number. 2020 is a Self-Describing Number. 21200 is a Self-Describing Number. 3211000 is a Self-Describing Number. 42101000 is a Self-Describing Number. 521001000 is a Self-Describing Number. [...]
Alternate version
Uses C++11. Build with
g++ -std=c++11 sdn.cpp
<lang cpp>#include <algorithm>
- include <array>
- include <iostream>
bool is_self_describing(unsigned long long int n) noexcept {
if (n == 0) { return false; } std::array<char, 10> digits = {0}, counts = {0}; std::size_t i = digits.size();
do { counts[digits[--i] = n % 10]++; } while ((n /= 10) > 0 && i < digits.size());
return n == 0 && std::equal(begin(digits) + i, end(digits), begin(counts));
}
int main() {
for (unsigned long long int i = 0; i < 10000000000; ++i) { if (is_self_describing(i)) { std::cout << i << "\n"; } }
}</lang> Output:
1210 2020 21200 3211000 42101000 521001000 6210001000
Common Lisp
Not terribly speedy brute force. I played around with "counting" the digits directly into a number by adding in appropriate powers of 10 for each digit I see but trailing zeroes kind of gum up the works. I still think it's possible and probably much faster because it wouldn't have to allocate an array and then turn around and "interpret" it back out but I didn't really pursue it. <lang lisp>(defun to-ascii (str) (mapcar #'char-code (coerce str 'list)))
(defun to-digits (n)
(mapcar #'(lambda(v) (- v 48)) (to-ascii (princ-to-string n))))
(defun count-digits (n)
(do ((counts (make-array '(10) :initial-contents '(0 0 0 0 0 0 0 0 0 0))) (curlist (to-digits n) (cdr curlist))) ((null curlist) counts) (setf (aref counts (car curlist)) (+ 1 (aref counts (car curlist)))))))
(defun self-described-p (n)
(if (not (numberp n)) nil (do ((counts (count-digits n)) (ipos 0 (+ 1 ipos)) (digits (to-digits n) (cdr digits))) ((null digits) t) (if (not (eql (car digits) (aref counts ipos))) (return nil)))))</lang>
Output: <lang>(loop for i from 1 to 4000000 do (if (self-described-p i) (print i)))
1210 2020 21200 3211000 NIL</lang>
Crystal
<lang ruby>def self_describing?(n)
digits = n.to_s.chars.map(&.to_i) # 12345 => [1, 2, 3, 4, 5] digits.each_with_index.all? { |digit, idx| digits.count(idx) == digit }
end
t = Time.monotonic 600_000_000.times { |n| (puts "#{n} in #{(Time.monotonic - t).total_seconds} secs";
t = Time.monotonic) if self_describing?(n) }</lang> System: I5-2410m, 2.9 GHz, Linux Kernel 5.5.17, Crystal 0.34 Compil: $ crystal build selfdescribing.cr --release Run as: $ time ./selfdescribing
- Output:
1210 in 0.000405621 secs 2020 in 0.000260327 secs 21200 in 0.005639628 secs 3211000 in 0.799380182 secs 42101000 in 9.825958853 secs 521001000 in 127.339214639 secs ./selfdescribing 171.69s user 7.81s system 112% cpu 2:38.96 total
<lang ruby>def selfDesc(n)
ns = n.to_s nc = ns.size count = Array.new(nc, 0) sum = 0 while n > 0 d = n % 10 return false if d >= nc # can't have a digit >= number of digits sum += d return false if sum > nc count[d] += 1 n //= 10 end # to be self-describing sum of digits must equal number of digits return false if sum != nc return ns == count.join() # there must always be at least one zero
end
start = Time.monotonic print("The self-describing numbers are:") i = 10i64 # self-describing number must end in 0 pw = 10i64 # power of 10 fd = 1i64 # first digit sd = 1i64 # second digit dg = 2i64 # number of digits mx = 11i64 # maximum for current batch lim = 9_100_000_001i64 # sum of digits can't be more than 10 while i < lim
if selfDesc(i) secs = (Time.monotonic - start).total_seconds print("\n#{i} in #{secs} secs") end i += 10 if i > mx fd += 1 sd -= 1 if sd >= 0 i = pw * fd else pw *= 10 dg += 1 i = pw fd = 1 sd = dg - 1 end mx = i + sd * pw // 10 end
end osecs = (Time.monotonic - start).total_seconds print("\nTook #{osecs} secs overall")</lang>
System: I5-2410m, 2.9 GHz, Linux Kernel 5.5.17, Crystal 0.34 Run as: $ crystal selfdescribing.cr --release
- Output:
The self-describing numbers are: 1210 in 2.8282e-5 secs 2020 in 5.823e-5 secs 21200 in 0.000171366 secs 3211000 in 0.025022473 secs 42101000 in 0.279668575 secs 521001000 in 3.864771331 secs 6210001000 in 52.883335718 secs Took 63.117831317 secs overall
D
Functional Version
<lang d>import std.stdio, std.algorithm, std.range, std.conv, std.string;
bool isSelfDescribing(in long n) pure nothrow @safe {
auto nu = n.text.representation.map!q{ a - '0' }; return nu.length.iota.map!(a => nu.count(a)).equal(nu);
}
void main() {
4_000_000.iota.filter!isSelfDescribing.writeln;
}</lang>
- Output:
[1210, 2020, 21200, 3211000]
A Faster Version
<lang d>bool isSelfDescribing2(ulong n) nothrow @nogc {
if (n <= 0) return false;
__gshared static uint[10] digits, d; digits[] = 0; d[] = 0; int i;
if (n < uint.max) { uint nu = cast(uint)n; for (i = 0; nu > 0 && i < digits.length; nu /= 10, i++) { d[i] = nu % 10; digits[d[i]]++; } if (nu > 0) return false; } else { for (i = 0; n > 0 && i < digits.length; n /= 10, i++) { d[i] = n % 10; digits[d[i]]++; } if (n > 0) return false; }
foreach (immutable k; 0 .. i) if (d[k] != digits[i - k - 1]) return false; return true;
}
void main() {
import std.stdio;
foreach (immutable x; [1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000]) assert(x.isSelfDescribing2);
foreach (immutable i; 0 .. 4_000_000) if (i.isSelfDescribing2) i.writeln;
}</lang>
- Output:
1210 2020 21200 3211000
(About 0.29 seconds run time for 4 million tests.)
Output with foreach(i;0..600_000_000):
1210 2020 21200 3211000 42101000 521001000
Elixir
<lang elixir>defmodule Self_describing do
def number(n) do digits = Integer.digits(n) Enum.map(0..length(digits)-1, fn s -> length(Enum.filter(digits, fn c -> c==s end)) end) == digits end
end
m = 3300000 Enum.filter(0..m, fn n -> Self_describing.number(n) end)</lang>
- Output:
[1210, 2020, 21200, 3211000]
Erlang
<lang erlang>
sdn(N) -> lists:map(fun(S)->length(lists:filter(fun(C)->C-$0==S end,N))+$0 end,lists:seq(0,length(N)-1))==N. gen(M) -> lists:filter(fun(N)->sdn(integer_to_list(N)) end,lists:seq(0,M)).
</lang>
Factor
<lang factor>USING: kernel math.parser prettyprint sequences ; IN: rosetta-code.self-describing-numbers
- digits ( n -- seq ) number>string string>digits ;
- digit-count ( seq n -- m ) [ = ] curry count ;
- self-describing-number? ( n -- ? )
digits dup [ digit-count = ] with map-index [ t = ] all? ;
100,000,000 <iota> [ self-describing-number? ] filter .</lang>
- Output:
V{ 1210 2020 21200 3211000 42101000 }
Forth
<lang forth>\ where unavailable.
- third ( A b c -- A b c A ) >r over r> swap ;
- (.) ( u -- c-addr u ) 0 <# #s #> ;
\ COUNT is a standard word with a very different meaning, so this \ would typically be beheaded, or given another name, or otherwise \ given a short lifespan, so to speak.
- count ( c-addr1 u1 c -- c-addr1 u1 c+1 u )
0 2over bounds do over i c@ = if 1+ then loop swap 1+ swap ;
- self-descriptive? ( u -- f )
(.) [char] 0 third third bounds ?do count i c@ [char] 0 - <> if drop 2drop false unloop exit then loop drop 2drop true ;</lang>
FreeBASIC
<lang freebasic>' FB 1.05.0 Win64
Function selfDescribing (n As UInteger) As Boolean
If n = 0 Then Return False Dim ns As String = Str(n) Dim count(0 To 9) As Integer all elements zero by default While n > 0 count(n Mod 10) += 1 n \= 10 Wend For i As Integer = 0 To Len(ns) - 1 If ns[i] - 48 <> count(i) Then Return False numerals have ascii values from 48 to 57 Next Return True
End Function
Print "The self-describing numbers less than 100 million are:" For i As Integer = 0 To 99999999
If selfDescribing(i) Then Print i; " ";
Next Print Print "Press any key to quit" Sleep</lang>
- Output:
The self-describing numbers less than 100 million are: 1210 2020 21200 3211000 42101000
Go
Original
<lang go>package main
import (
"fmt" "strconv" "strings"
)
// task 1 requirement func sdn(n int64) bool {
if n >= 1e10 { return false } s := strconv.FormatInt(n, 10) for d, p := range s { if int(p)-'0' != strings.Count(s, strconv.Itoa(d)) { return false } } return true
}
// task 2 code (takes a while to run) func main() {
for n := int64(0); n < 1e10; n++ { if sdn(n) { fmt.Println(n) } }
}</lang> Output produced by above program:
1210 2020 21200 3211000 42101000 521001000 6210001000
Optimized
Uses the optimized loop from the Wren entry - 12 times faster than before. <lang go>package main
import (
"fmt" "strconv" "strings" "time"
)
func selfDesc(n uint64) bool {
if n >= 1e10 { return false } s := strconv.FormatUint(n, 10) for d, p := range s { if int(p)-'0' != strings.Count(s, strconv.Itoa(d)) { return false } } return true
}
func main() {
start := time.Now() fmt.Println("The self-describing numbers are:") i := uint64(10) // self-describing number must end in 0 pw := uint64(10) // power of 10 fd := uint64(1) // first digit sd := uint64(1) // second digit dg := uint64(2) // number of digits mx := uint64(11) // maximum for current batch lim := uint64(9_100_000_001) // sum of digits can't be more than 10 for i < lim { if selfDesc(i) { secs := time.Since(start).Seconds() fmt.Printf("%d (in %.1f secs)\n", i, secs) } i += 10 if i > mx { fd++ sd-- if sd >= 0 { i = fd * pw } else { pw *= 10 dg++ i = pw fd = 1 sd = dg - 1 } mx = i + sd*pw/10 } } osecs := time.Since(start).Seconds() fmt.Printf("\nTook %.1f secs overall\n", osecs)
}</lang>
- Output:
Timings are for an Intel Core i7-8565U machine running Go 1.14.2 on Ubuntu 18.04.
The self-describing numbers are: 1210 (in 0.0 secs) 2020 (in 0.0 secs) 21200 (in 0.0 secs) 3211000 (in 0.0 secs) 42101000 (in 0.2 secs) 521001000 (in 2.5 secs) 6210001000 (in 29.9 secs) Took 43.0 secs overall
Haskell
<lang Haskell>import Data.Char
count :: Int -> [Int] -> Int count x = length . filter (x ==)
isSelfDescribing :: Integer -> Bool isSelfDescribing n = nu == f
where nu = digitToInt <$> show n f = (`count` nu) <$> [0 .. length nu - 1]
main :: IO () main = do
print $ isSelfDescribing <$> [1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000] print $ filter isSelfDescribing [0 .. 4000000]</lang>
Output:
[True,True,True,True,True,True,True] [1210,2020,21200,3211000]
Here are functions for generating all the self-describing numbers of a certain length. We capitalize on the fact (from Wikipedia) that a self-describing number of length n is a base-n number (i.e. all digits are 0..n-1). <lang haskell>import Data.Char (intToDigit) import Control.Monad (replicateM, forM_)
count :: Int -> [Int] -> Int count x = length . filter (x ==)
-- all the combinations of n digits of base n -- a base-n number are represented as a list of ints, one per digit allBaseNNumsOfLength :: Int -> Int allBaseNNumsOfLength = replicateM <*> (enumFromTo 0 . subtract 1)
isSelfDescribing :: [Int] -> Bool isSelfDescribing num = all (\(i, x) -> x == count i num) $ zip [0 ..] num
-- translate it back into an integer in base-10 decimalize :: [Int] -> Int decimalize = read . map intToDigit
main :: IO () main =
(print . concat) $ map decimalize . filter isSelfDescribing . allBaseNNumsOfLength <$> [1 .. 8]</lang>
- Output:
[1210,2020,21200,3211000,42101000]
Icon and Unicon
The following program contains the procedure is_self_describing
to test if a number is a self-describing number, and the procedure self_describing_numbers
to generate them.
<lang Icon> procedure count (test_item, str)
result := 0 every item := !str do if test_item == item then result +:= 1 return result
end
procedure is_self_describing (n)
ns := string (n) # convert to a string every i := 1 to *ns do { if count (string(i-1), ns) ~= ns[i] then fail } return 1 # success
end
- generator for creating self_describing_numbers
procedure self_describing_numbers ()
n := 1 repeat { if is_self_describing(n) then suspend n n +:= 1 }
end
procedure main ()
# write the first 4 self-describing numbers every write (self_describing_numbers ()\4)
end </lang> A slightly more concise solution can be derived from the above by taking more advantage of Icon's (and Unicon's) automatic goal-directed evaluation: <lang unicon> procedure is_self_describing (n)
ns := string (n) # convert to a string every i := 1 to *ns do { if count (string(i-1), ns) ~= ns[i] then fail } return n # on success, return the self-described number
end
procedure self_describing_numbers ()
suspend is_self_describing(seq())
end</lang>
J
Solution:<lang j> digits =: 10&#.^:_1
counts =: _1 + [: #/.~ i.@:# , ] selfdesc =: = counts&.digits"0 NB. Note use of "under"</lang>
Example:<lang j> selfdesc 2020 1210 21200 3211000 43101000 42101000 1 1 1 1 0 1</lang> Extra credit:<lang j> I.@:selfdesc i. 1e6 1210 2020 21200</lang> Discussion: The use of &. here is a great example of its surprisingly broad applicability, and the elegance it can produce.
The use of "0 is less satisfying, expressing an essentially scalar solution, and that such an approach runs against the grain of J becomes quite evident when executing the extra credit sentence.
It would not be difficult to rephrase the verb in a way that would take advantage of J's array mastery, but it would cost us of some of the simplicity and elegance of the existing solution. More gratifying would be some kind of closed-form, algebraic formula that could identify the SDNs directly, without test-and-filter.
That said, note that this is an incomplete implementation of the extra-credit problem -- and, hypothetically speaking, numbers longer than 9 digits could be valid results in the extra-credit problem (we just have to be sure that digit positions which are not occupied by digits we can represent have 0 for their count). This might allow us to treat numbers up to just under 19 digits as self describing numbers. This is a slightly larger range of numbers than we get for positive integers from signed 64 bit representation. So a proper solution to this problem on currently available hardware (one that finds the complete result in some useful span of time) probably should use a non-brute-force solution.
Java
<lang java>public class SelfDescribingNumbers{
public static boolean isSelfDescribing(int a){ String s = Integer.toString(a); for(int i = 0; i < s.length(); i++){ String s0 = s.charAt(i) + ""; int b = Integer.parseInt(s0); // number of times i-th digit must occur for it to be a self describing number int count = 0; for(int j = 0; j < s.length(); j++){ int temp = Integer.parseInt(s.charAt(j) + ""); if(temp == i){ count++; } if (count > b) return false; } if(count != b) return false; } return true; }
public static void main(String[] args){ for(int i = 0; i < 100000000; i++){ if(isSelfDescribing(i)){ System.out.println(i); } } }
}</lang>
JavaScript
<lang javascript>function is_self_describing(n) {
var digits = Number(n).toString().split("").map(function(elem) {return Number(elem)}); var len = digits.length; var count = digits.map(function(x){return 0});
digits.forEach(function(digit, idx, ary) { if (digit >= count.length) return false count[digit] ++; });
return digits.equals(count);
}
Array.prototype.equals = function(other) {
if (this === other) return true; // same object if (this.length != other.length) return false; for (idx in this) if (this[idx] !== other[idx]) return false; return true;
}
for (var i=1; i<=3300000; i++)
if (is_self_describing(i)) print(i);</lang>
outputs
1210 2020 21200 3211000
jq
<lang jq># If your jq includes all/2 then comment out the following definition,
- which is slightly less efficient:
def all(generator; condition):
reduce generator as $i (true; if . then $i | condition else . end);</lang>
<lang jq>def selfie:
def count(value): reduce .[] as $i (0; if $i == value then . + 1 else . end); def digits: tostring | explode | map(. - 48);
digits | if add != length then false else . as $digits | all ( range(0; length); . as $i | $digits | (.[$i] == count($i)) ) end;</lang>
The task: <lang jq>range(0; 100000001) | select(selfie)</lang>
- Output:
<lang sh>$ jq -n -f Self-describing_numbers.jq 1210 2020 21200 3211000 42101000</lang>
Julia
<lang julia>function selfie(x::Integer) ds = reverse(digits(x)) if sum(ds) != length(ds) return false end for (i, d) in enumerate(ds) if d != sum(ds .== i - 1) return false end end return true end
@show selfie(2020) @show selfie(2021)
selfies(x) = for i in 1:x selfie(i) && println(i) end @time selfies(4000000)</lang>
- Output:
1210 2020 21200 3211000 1.398922 seconds (8.01 M allocations: 1.049 GiB, 6.91% gc time)
K
<lang k> sdn: {n~+/'n=/:!#n:0$'$x}'
sdn 1210 2020 2121 21200 3211000 42101000
1 1 0 1 1 1
&sdn@!:1e6
1210 2020 21200</lang>
Kotlin
<lang scala>// version 1.0.6
fun selfDescribing(n: Int): Boolean {
if (n <= 0) return false val ns = n.toString() val count = IntArray(10) var nn = n while (nn > 0) { count[nn % 10] += 1 nn /= 10 } for (i in 0 until ns.length) if( ns[i] - '0' != count[i]) return false return true
}
fun main(args: Array<String>) {
println("The self-describing numbers less than 100 million are:") for (i in 0..99999999) if (selfDescribing(i)) print("$i ") println()
}</lang>
- Output:
The self-describing numbers less than 100 million are: 1210 2020 21200 3211000 42101000
Liberty BASIC
<lang lb>'adapted from BASIC solution FOR x = 1 TO 5000000
a$ = TRIM$(STR$(x)) b = LEN(a$) FOR c = 1 TO b d$ = MID$(a$, c, 1) v(VAL(d$)) = v(VAL(d$)) + 1 w(c - 1) = VAL(d$) NEXT c r = 0 FOR n = 0 TO 10 IF v(n) = w(n) THEN r = r + 1 v(n) = 0 w(n) = 0 NEXT n IF r = 11 THEN PRINT x; " is a self-describing number"
NEXT x PRINT PRINT "End"</lang>
LiveCode
<lang LiveCode>function selfDescNumber n
local tSelfD, tLen put len(n) into tLen repeat with x = 0 to (tLen - 1) put n into nCopy replace x with empty in nCopy put char (x + 1) of n = (tLen - len(nCopy)) into tSelfD if not tSelfD then exit repeat end repeat return tSelfD
end selfDescNumber</lang> To list the self-describing numbers to 10 million<lang LiveCode>on mouseUp
repeat with n = 0 to 10000000 if selfDescNumber(n) then put n into selfNum[n] end if end repeat combine selfNum using comma put selfNum
end mouseUp</lang> Output<lang LiveCode>1210,2020,21200,3211000</lang>
Logo
<lang logo>TO XX BT MAKE "AA (ARRAY 10 0) MAKE "BB (ARRAY 10 0) FOR [Z 0 9][SETITEM :Z :AA "0 SETITEM :Z :BB "0 ]
FOR [A 1 50000][ MAKE "B COUNT :A MAKE "Y 0 MAKE "X 0 MAKE "R 0 MAKE "J 0 MAKE "K 0
FOR [C 1 :B][MAKE "D ITEM :C :A SETITEM :C - 1 :AA :D MAKE "X ITEM :D :BB MAKE "Y :X + 1 SETITEM :D :BB :Y MAKE "R 0] FOR [Z 0 9][MAKE "J ITEM :Z :AA MAKE "K ITEM :Z :BB IF :J = :K [MAKE "R :R + 1]]
IF :R = 10 [PR :A] FOR [Z 0 9][SETITEM :Z :AA "0 SETITEM :Z :BB "0 ]] PR [END] END</lang>
Lua
<lang lua>function Is_self_describing( n )
local s = tostring( n )
local t = {} for i = 0, 9 do t[i] = 0 end
for i = 1, s:len() do
local idx = tonumber( s:sub(i,i) )
t[idx] = t[idx] + 1 end
for i = 1, s:len() do if t[i-1] ~= tonumber( s:sub(i,i) ) then return false end end
return true
end
for i = 1, 999999999 do
print( Is_self_describing( i ) )
end</lang>
Mathematica
<lang Mathematica>isSelfDescribing[n_Integer] := (RotateRight[DigitCount[n]] == PadRight[IntegerDigits[n], 10])</lang>
Select[Range[10^10 - 1], isSelfDescribing] -> {1210,2020,21200,3211000,42101000,521001000,6210001000}
MATLAB / Octave
<lang Matlab>function z = isSelfDescribing(n)
s = int2str(n)-'0'; % convert to vector of digits y = hist(s,0:9); z = all(y(1:length(s))==s);
end;</lang>
Test function:
<lang Matlab>for k = 1:1e10,
if isSelfDescribing(k), printf('%i\n',k); end
end; </lang>
Output:
1210 2020 21200 ...
MiniScript
<lang MiniScript>numbers = [12, 1210, 1300, 2020, 21200, 5]
occurrences = function(test, values)
count = 0 for i in values if i.val == test then count = count + 1 end for return count
end function
for number in numbers
check = "" + number digits = check.values describing = true for digit in digits.indexes if digits[digit].val != occurrences(digit, digits) then describing = false end if end for if describing then print number + " is self describing" else print number + " is not self describing" end if
end for </lang>
- Output:
12 is not self describing 1210 is self describing 1300 is not self describing 2020 is self describing 21200 is self describing 5 is not self describing
Modula-2
<lang modula2> MODULE SelfDescribingNumber;
FROM WholeStr IMPORT
CardToStr;
FROM STextIO IMPORT
WriteString, WriteLn;
FROM SWholeIO IMPORT
WriteCard;
PROCEDURE Check(Number: CARDINAL): BOOLEAN; VAR
I, D: CARDINAL; A: ARRAY [0 .. 9] OF CHAR; Count, W: ARRAY [0 .. 9] OF CARDINAL; Result: BOOLEAN;
BEGIN
CardToStr(Number, A); FOR I := 0 TO 9 DO Count[I] := 0; W[I] := 0; END; FOR I := 0 TO LENGTH(A) - 1 DO D := ORD(A[I]) - ORD("0"); INC(Count[D]); W[I] := D; END; Result := TRUE; I := 0; WHILE Result AND (I <= 9) DO Result := (Count[I] = W[I]); INC(I); END; RETURN Result;
END Check;
VAR
X: CARDINAL;
BEGIN
WriteString("Autodescriptive numbers from 1 to 100000000:"); WriteLn; FOR X := 1 TO 100000000 DO IF Check(X) THEN WriteString(" "); WriteCard(X, 1); WriteLn; END; END; WriteString("Job done."); WriteLn;
END SelfDescribingNumber. </lang>
- Output:
Autodescriptive numbers from 1 to 100000000: 1210 2020 21200 3211000 42101000 Job done.
Nim
<lang nim>import strutils
proc count(s, sub): int =
var i = 0 while true: i = s.find(sub, i) if i < 0: break inc i inc result
proc isSelfDescribing(n): bool =
let s = $n for i, ch in s: if s.count($i) != parseInt("" & ch): return false return true
for x in 0 .. 4_000_000:
if isSelfDescribing(x): echo x</lang>
Output:
1210 2020 21200 321100
ooRexx
<lang ooRexx> -- REXX program to check if a number (base 10) is self-describing. parse arg x y . if x== then exit if y== then y=x -- 10 digits is the maximum size number that works here, so cap it numeric digits 10 y=min(y, 9999999999)
loop number = x to y
loop i = 1 to number~length digit = number~subchar(i) -- return on first failure if digit \= number~countstr(i - 1) then iterate number end say number "is a self describing number"
end </lang> output when using the input of: 0 999999999
1210 is a self-describing number. 2020 is a self-describing number. 21200 is a self-describing number. 3211000 is a self-describing number. 42101000 is a self-describing number. 521001000 is a self-describing number. 6210001000 is a self-describing number.
PARI/GP
This is a finite set... <lang parigp>S=[1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000]; isself(n)=vecsearch(S,n)</lang>
Pascal
<lang pascal>Program SelfDescribingNumber;
uses
SysUtils;
function check(number: longint): boolean;
var i, d: integer; a: string; count, w : array [0..9] of integer;
begin a := intToStr(number); for i := 0 to 9 do begin count[i] := 0; w[i] := 0; end; for i := 1 to length(a) do begin d := ord(a[i]) - ord('0'); inc(count[d]); w[i - 1] := d; end; check := true; i := 0; while check and (i <= 9) do begin check := count[i] = w[i]; inc(i); end; end;
var
x: longint;
begin
writeln ('Autodescriptive numbers from 1 to 100000000:'); for x := 1 to 100000000 do if check(x) then writeln (' ', x); writeln('Job done.');
end.</lang> Output:
:> ./SelfDescribingNumber Autodescriptive numbers from 1 to 100000000: 1210 2020 21200 3211000 42101000 Job done.
Perl
The idea is to make two arrays: the first one contains the digits at their positions and the second one contains the digits counts.
The number is self-descriptive If the arrays are equal. <lang perl>sub is_selfdesc { local $_ = shift; my @b = (0) x length; $b[$_]++ for my @a = split //; return "@a" eq "@b"; }
- check all numbers from 0 to 100k plus two 'big' ones
for (0 .. 100000, 3211000, 42101000) { print "$_\n" if is_selfdesc($_); }</lang> Output:
1210 2020 21200 3211000 42101000
Phix
<lang Phix>function self_desc(integer i) sequence digits = repeat(0,10), counts = repeat(0,10) integer n = 0, digit
while 1 do digit := mod(i,10) digits[10-n] := digit counts[digit+1] += 1 i = floor(i/10) if i=0 then exit end if n += 1 end while return digits[10-n..10] = counts[1..n+1]
end function
atom t0 = time() for i=10 to 100_000_000 by 10 do
if self_desc(i) then ?i end if
end for printf(1,"done (%3.2fs)",time()-t0)</lang>
- Output:
1210 2020 21200 3211000 42101000 done (21.78s)
generator
Not quite as fast as I hoped it would be, although a bazillion times faster than the above and a good five times faster than Python, the following self(20) completes in just over half a second whereas self(24) takes nearly 9s, and it continues getting exponentially slower after that. Curiously, it is the early stages (same output) that slow down, whereas the latter ones always complete fairly quickly. <lang Phix>procedure impl(sequence d, c, integer m)
if m>=0 then integer l = length(d) if l and d == c[1..l] then string ds = "" for i=1 to l do integer ch = d[i]+'0' if ch>'9' then ch += 'a'-'9'-1 end if ds &= ch end for printf(1,"%s\n",ds) end if sequence dd = d&0 for i=c[l+1] to m do dd[$] = i if i>l or c[i+1]!=dd[i+1] then c[i+1] += 1 impl(dd,c,m-i) c[i+1] -= 1 end if end for end if
end procedure
procedure self(integer n)
impl({}, repeat(0,n+1), n)
end procedure self(20)</lang>
- Output:
1210 2020 21200 3211000 42101000 521001000 6210001000 72100001000 821000001000 9210000001000 a2100000001000 b21000000001000 c210000000001000 d2100000000001000 e21000000000001000 f210000000000001000 g2100000000000001000
even faster
Finishes in less than a tenth of a second
<lang Phix>constant string aleph = tagset('9','0')&tagset('z','a')&tagset('Z','A')
procedure gen(integer n)
for ones=0 to min(2,n-3) do sequence digits = repeat(0,n), counts = repeat(0,n) digits[1] := n-2-ones if digits[1]<>2 then digits[digits[1]+1] := 1 digits[2] := 2 digits[3] := 1 else digits[2] := (ones<>0) digits[3] := 2 end if for i=1 to n do counts[digits[i]+1] += 1 end for if counts=digits then string s = "" for i=1 to n do integer di = digits[i] s &= aleph[di+1] end for printf(1,"%s\n",s) end if end for
end procedure
for n=1 to length(aleph)+3 do
gen(n)
end for</lang>
- Output:
as above plus
h21000000000000001000 i210000000000000001000 ... z21000000000000000000000000000000001000 A210000000000000000000000000000000001000 ... Z2100000000000000000000000000000000000000000000000000000000001000
PHP
Works with: PHP 5.
<lang PHP><?php
function is_describing($number) {
foreach (str_split((int) $number) as $place => $value) { if (substr_count($number, $place) != $value) { return false; } } return true;
}
for ($i = 0; $i <= 50000000; $i += 10) {
if (is_describing($i)) { echo $i . PHP_EOL; }
}
?></lang>
Output:
1210 2020 21200 3211000 42101000
PicoLisp
<lang PicoLisp>(de selfDescribing (N)
(fully '((D I) (= D (cnt = N (circ I)))) (setq N (mapcar format (chop N))) (range 0 (length N)) ) )</lang>
Output:
: (filter selfDescribing (range 1 4000000)) -> (1210 2020 21200 3211000)
PowerShell
According to the Wiki definition, the sum of the products of the index and the digit contained at the index should equal the number of digits in the number: <lang PowerShell> function Test-SelfDescribing ([int]$Number) {
[int[]]$digits = $Number.ToString().ToCharArray() | ForEach-Object {[Char]::GetNumericValue($_)} [int]$sum = 0
for ($i = 0; $i -lt $digits.Count; $i++) { $sum += $i * $digits[$i] }
$sum -eq $digits.Count
} </lang> <lang PowerShell> Test-SelfDescribing -Number 2020 </lang>
- Output:
True
It takes a very long while to test 100,000,000 numbers, and since they are already known just test a few: <lang PowerShell> 11,2020,21200,321100 | ForEach-Object {
[PSCustomObject]@{ Number = $_ IsSelfDescribing = Test-SelfDescribing -Number $_ }
} | Format-Table -AutoSize </lang>
- Output:
Number IsSelfDescribing ------ ---------------- 11 False 2020 True 21200 True 321100 False
Prolog
Works with SWI-Prolog and library clpfd written by Markus Triska. <lang Prolog>:- use_module(library(clpfd)).
self_describling :- forall(between(1, 10, I), (findall(N, self_describling(I,N), L), format('Len ~w, Numbers ~w~n', [I, L]))).
% search of the self_describling numbers of a given len self_describling(Len, N) :- length(L, Len), Len1 is Len - 1, L = [H|T],
% the first figure is greater than 0 H in 1..Len1,
% there is a least to figures so the number of these figures % is at most Len - 2 Len2 is Len - 2, T ins 0..Len2,
% the sum of the figures is equal to the len of the number sum(L, #=, Len),
% There is at least one figure corresponding to the number of zeros H1 #= H+1, element(H1, L, V), V #> 0,
% create the list label(L),
% test the list msort(L, LNS), packList(LNS,LNP), numlist(0, Len1, NumList), verif(LNP,NumList, L),
% list is OK, create the number maplist(atom_number, LA, L), number_chars(N, LA).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% testing a number (not use in this program)
self_describling(N) :-
number_chars(N, L),
maplist(atom_number, L, LN),
msort(LN, LNS),
packList(LNS,LNP), !,
length(L, Len),
Len1 is Len - 1,
numlist(0, Len1, NumList),
verif(LNP,NumList, LN).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% verif(PackList, Order_of_Numeral, Numeral_of_the_nuber_to_test)
% Packlist is of the form [[Number_of_Numeral, Order_of_Numeral]|_]
% Test succeed when
% All lists are empty verif([], [], []).
% Packlist is empty and all lasting numerals are 0 verif([], [_N|S], [0|T]) :- verif([], S, T).
% Number of numerals N is V verif([[V, N]|R], [N|S], [V|T]) :- verif(R, S, T).
% Number of numerals N is 0 verif([[V, N1]|R], [N|S], [0|T]) :- N #< N1, verif([[V,N1]|R], S, T).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % ?- packList([a,a,a,b,c,c,c,d,d,e], L). % L = [[3,a],[1,b],[3,c],[2,d],[1,e]] . % ?- packList(R, [[3,a],[1,b],[3,c],[2,d],[1,e]]). % R = [a,a,a,b,c,c,c,d,d,e] . % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% packList([],[]).
packList([X],1,X) :- !.
packList([X|Rest],[XRun|Packed]):-
run(X,Rest, XRun,RRest), packList(RRest,Packed).
run(Var,[],[1, Var],[]).
run(Var,[Var|LRest],[N1, Var],RRest):-
N #> 0, N1 #= N + 1, run(Var,LRest,[N, Var],RRest).
run(Var,[Other|RRest], [1, Var],[Other|RRest]):-
dif(Var,Other).</lang>
Output
?- self_describling. Len 1, Numbers [] Len 2, Numbers [] Len 3, Numbers [] Len 4, Numbers [1210,2020] Len 5, Numbers [21200] Len 6, Numbers [] Len 7, Numbers [3211000] Len 8, Numbers [42101000] Len 9, Numbers [521001000] Len 10, Numbers [6210001000] true.
PureBasic
<lang PureBasic>Procedure isSelfDescribing(x.q)
;returns 1 if number is self-describing, otherwise it returns 0 Protected digitCount, digit, i, digitSum Dim digitTally(10) Dim digitprediction(10) If x <= 0 ProcedureReturn 0 ;number must be positive and non-zero EndIf While x > 0 And i < 10 digit = x % 10 digitSum + digit If digitSum > 10 ProcedureReturn 0 ;sum of digits' values exceeds maximum possible EndIf digitprediction(i) = digit digitTally(digit) + 1 x / 10 i + 1 Wend digitCount = i - 1 If digitSum < digitCount Or x > 0 ProcedureReturn 0 ;sum of digits' values is too small or number has more than 10 digits EndIf For i = 0 To digitCount If digitTally(i) <> digitprediction(digitCount - i) ProcedureReturn 0 ;number is not self-describing EndIf Next ProcedureReturn 1 ;number is self-describing
EndProcedure
Procedure displayAll()
Protected i, j, t PrintN("Starting search for all self-describing numbers..." + #CRLF$) For j = 0 To 9 PrintN(#CRLF$ + "Searching possibilites " + Str(j * 1000000000) + " -> " + Str((j + 1) * 1000000000 - 1)+ "...") t = ElapsedMilliseconds() For i = 0 To 999999999 If isSelfDescribing(j * 1000000000 + i) PrintN(Str(j * 1000000000 + i)) EndIf Next PrintN("Time to search this range of possibilities: " + Str((ElapsedMilliseconds() - t) / 1000) + "s.") Next PrintN(#CRLF$ + "Search complete.")
EndProcedure
If OpenConsole()
DataSection Data.q 1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000, 3214314 EndDataSection Define i, x.q For i = 1 To 8 Read.q x Print(Str(x) + " is ") If Not isSelfDescribing(x) Print("not ") EndIf PrintN("selfdescribing.") Next PrintN(#CRLF$) displayAll() Print(#CRLF$ + #CRLF$ + "Press ENTER to exit"): Input() CloseConsole()
EndIf</lang> Sample output:
1210 is selfdescribing. 2020 is selfdescribing. 21200 is selfdescribing. 3211000 is selfdescribing. 42101000 is selfdescribing. 521001000 is selfdescribing. 6210001000 is selfdescribing. 3214314 is not selfdescribing. Starting search for all self-describing numbers... Searching possibilites 0 -> 999999999... 1210 2020 21200 3211000 42101000 521001000 Time to search this range of possibilities: 615s. Searching possibilites 1000000000 -> 1999999999... Time to search this range of possibilities: 614s. Searching possibilites 2000000000 -> 2999999999... Time to search this range of possibilities: 628s. Searching possibilites 3000000000 -> 3999999999... Time to search this range of possibilities: 631s. Searching possibilites 4000000000 -> 4999999999... Time to search this range of possibilities: 630s. Searching possibilites 5000000000 -> 5999999999... Time to search this range of possibilities: 628s. Searching possibilites 6000000000 -> 6999999999... 6210001000 Time to search this range of possibilities: 629s. Searching possibilites 7000000000 -> 7999999999... Time to search this range of possibilities: 631s. Searching possibilites 8000000000 -> 8999999999... Time to search this range of possibilities: 629s. Searching possibilites 9000000000 -> 9999999999... Time to search this range of possibilities: 629s. Search complete.
Python
<lang python>>>> def isSelfDescribing(n): s = str(n) return all(s.count(str(i)) == int(ch) for i, ch in enumerate(s))
>>> [x for x in range(4000000) if isSelfDescribing(x)] [1210, 2020, 21200, 3211000] >>> [(x, isSelfDescribing(x)) for x in (1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000)] [(1210, True), (2020, True), (21200, True), (3211000, True), (42101000, True), (521001000, True), (6210001000, True)]</lang>
Generator
From here. <lang python>def impl(d, c, m):
if m < 0: return if d == c[:len(d)]: print d for i in range(c[len(d)],m+1): dd = d+[i] if i<len(dd) and c[i]==dd[i]: continue impl(dd,c[:i]+[c[i]+1]+c[i+1:],m-i)
def self(n): impl([], [0]*(n+1), n)
self(10)</lang> Output:
[] [1, 2, 1, 0] [2, 0, 2, 0] [2, 1, 2, 0, 0] [3, 2, 1, 1, 0, 0, 0] [4, 2, 1, 0, 1, 0, 0, 0] [5, 2, 1, 0, 0, 1, 0, 0, 0] [6, 2, 1, 0, 0, 0, 1, 0, 0, 0]
Racket
<lang Racket>#lang racket (define (get-digits number (lst null))
(if (zero? number) lst (get-digits (quotient number 10) (cons (remainder number 10) lst))))
(define (self-describing? number)
(if (= number 0) #f (let ((digits (get-digits number))) (for/fold ((bool #t)) ((i (in-range (length digits)))) (and bool (= (count (lambda (x) (= x i)) digits) (list-ref digits i)))))))</lang>
Sadly, the implementation is too slow for the optional task, taking somewhere around 3 minutes to check all numbers below 100.000.000
Raku
(formerly Perl 6) <lang perl6>my @values = <1210 2020 21200 3211000 42101000 521001000 6210001000 27 115508>;
for @values -> $test {
say "$test is {sdn($test) ?? !! 'NOT ' }a self describing number.";
}
sub sdn($n) {
my $s = $n.Str; my $chars = $s.chars; my @a = +«$s.comb; my @b; for @a -> $i { return False if $i >= $chars; ++@b[$i]; } @b[$_] //= 0 for ^$chars; @a eqv @b;
}
.say if .&sdn for ^9999999;</lang> Output:
1210 is a self describing number. 2020 is a self describing number. 21200 is a self describing number. 3211000 is a self describing number. 42101000 is a self describing number. 521001000 is a self describing number. 6210001000 is a self describing number. 27 is NOT a self describing number. 115508 is NOT a self describing number. 1210 2020 21200 3211000
Red
<lang Red>Red []
- -------------------------------------
count-dig: func ["count occurence of digit in number"
- -------------------------------------
s [string!] "number as string" sdig [char!] "search number as char"
][ cnt: #"0" ;; counter as char for performance optimization
while [s: find/tail s sdig][cnt: cnt + 1] return cnt ]
- -------------------------------------
isSDN?: func ["test if number is self describing number"
s [string!] "number to test as string " ][
- -------------------------------------
ind: #"0" ;; use digit as char for performance optimization
foreach ele s [
if ele <> count-dig s ind [return false] ind: ind + 1
] return true ]
repeat i 4000000 [ if isSDN? to-string i [print i] ] </lang> output
1210 2020 21200 3211000 >>
REXX
Also see: OEIS A46043 and OEIS A138480.
digit by digit test
<lang rexx>/*REXX program determines if a number (in base 10) is a self─describing, */ /*────────────────────────────────────────────────────── self─descriptive, */ /*────────────────────────────────────────────────────── autobiographical, or a */ /*────────────────────────────────────────────────────── curious number. */ parse arg x y . /*obtain optional arguments from the CL*/ if x== | x=="," then exit /*Not specified? Then get out of Dodge*/ if y== | y=="," then y=x /* " " Then use the X value.*/ w=length(y) /*use Y's width for aligned output. */ numeric digits max(9, w) /*ensure we can handle larger numbers. */ if x==y then do /*handle the case of a single number. */
noYes=test_SDN(y) /*is it or ain't it? */ say y word("is isn't", noYes+1) 'a self-describing number.' exit end
do n=x to y if test_SDN(n) then iterate /*if not self─describing, try again. */ say right(n,w) 'is a self-describing number.' /*is it? */ end /*n*/
exit /*stick a fork in it, we're all done. */ /*──────────────────────────────────────────────────────────────────────────────────────*/ test_SDN: procedure; parse arg ?; L=length(?) /*obtain the argument and its length.*/
do j=L to 1 by -1 /*parsing backwards is slightly faster.*/ if substr(?,j,1)\==L-length(space(translate(?,,j-1),0)) then return 1 end /*j*/ return 0 /*faster if used inverted truth table. */</lang>
╔══════════════════════════════════════════════════════════════════╗ ║ The method used above is to TRANSLATE the digit being queried to ║ ║ blanks, then use the SPACE BIF function to remove all blanks, ║ ║ and then compare the new number's length to the original length. ║ ║ ║ ║ The difference in length is the number of digits translated. ║ ╚══════════════════════════════════════════════════════════════════╝
output when using the input of: 0 9999999999
1210 is a self-describing number. 2020 is a self-describing number. 21200 is a self-describing number. 3211000 is a self-describing number. 42101000 is a self-describing number. 521001000 is a self-describing number. 6210001000 is a self-describing number.
faster method
(Uses table lookup.) <lang rexx>/*REXX program determines if a number (in base 10) is a self-describing number.*/ parse arg x y . /*obtain optional arguments from the CL*/ if x== | x=="," then exit /*Not specified? Then get out of Dodge*/ if y== | y=="," then y=x /*Not specified? Then use the X value.*/ w=length(y) /*use Y's width for aligned output. */ numeric digits max(9, w) /*handle the possibility of larger #'s.*/ $= '1210 2020 21200 3211000 42101000 521001000 6210001000' /*the list of numbers.*/
/*test for a single integer. */
if x==y then do /*handle the case of a single number. */
say word("isn't is", wordpos(x, $) + 1) 'a self-describing number.' exit end /* [↓] test for a range of integers.*/ do n=x to y; parse var n -1 _ /*obtain the last decimal digit of N. */ if _\==0 then iterate if wordpos(n, $)==0 then iterate say right(n,w) 'is a self-describing number.' end /*n*/ /*stick a fork in it, we're all done. */</lang>
output is the same as the 1st REXX example.
fastest method
(Uses a table look-up.)
(Results are instantaneous.) <lang rexx>/*REXX program determines if a number (in base 10) is a self-describing number.*/ parse arg x y . /*obtain optional arguments from the CL*/ if x== | x=="," then exit /*Not specified? Then get out of Dodge*/ if y== | y=="," then y=x /*Not specified? Then use the X value.*/ w=length(y) /*use Y's width for aligned output. */ numeric digits max(9, w) /*handle the possibility of larger #'s.*/ $= '1210 2020 21200 3211000 42101000 521001000 6210001000' /*the list of numbers.*/
/*test for a single integer. */
if x==y then do /*handle the case of a single number. */
say word("isn't is", wordpos(x, $) + 1) 'a self-describing number.' exit end /* [↓] test for a range of integers.*/ do n=1 for words($); _=word($, n) /*look for integers that are in range. */ if _<x | _>y then iterate /*if not self-describing, try again. */ say right(_, w) 'is a self-describing number.' end /*n*/ /*stick a fork in it, we're all done. */</lang>
output is the same as the 1st REXX example.
Ring
<lang ring>
- Project : Self-describing numbers
for num = 1 to 45000000
res = 0 for n=1 to len(string(num)) temp = string(num) pos = number(temp[n]) cnt = count(temp,string(n-1)) if cnt = pos res = res + 1 ok next if res = len(string(num)) see num + nl ok
next
func count(cString,dString)
sum = 0 while substr(cString,dString) > 0 sum = sum + 1 cString = substr(cString,substr(cString,dString)+len(string(sum))) end return sum
</lang> Output:
1210 2020 21200 3211000 42101000
Ruby
<lang ruby>def self_describing?(n)
digits = n.digits.reverse digits.each_with_index.all?{|digit, idx| digits.count(idx) == digit}
end
3_300_000.times {|n| puts n if self_describing?(n)}</lang> outputs
1210 2020 21200 3211000
<lang ruby>def selfDesc(n)
ns = n.to_s nc = ns.size count = Array.new(nc, 0) sum = 0 while n > 0 d = n % 10 return false if d >= nc # can't have a digit >= number of digits sum += d return false if sum > nc count[d] += 1 n /= 10 end # to be self-describing sum of digits must equal number of digits return false if sum != nc return ns == count.join() # there must always be at least one zero
end
start = Time.now print("The self-describing numbers are:") i = 10 # self-describing number must end in 0 pw = 10 # power of 10 fd = 1 # first digit sd = 1 # second digit dg = 2 # number of digits mx = 11 # maximum for current batch lim = 9_100_000_001 # sum of digits can't be more than 10 while i < lim
if selfDesc(i) secs = (Time.now - start) #.total_seconds print("\n#{i} in #{secs} secs") end i += 10 if i > mx fd += 1 sd -= 1 if sd >= 0 i = pw * fd else pw *= 10 dg += 1 i = pw fd = 1 sd = dg - 1 end mx = i + sd * pw / 10 end
end osecs = (Time.now - start) print("\nTook #{osecs} secs overall")</lang>
System: I5-2410m, 2.9 GHz, Linux Kernel 5.5.17, Ruby 2.7.1 Run as: $ ruby selfdescribing.rb
- Output:
The self-describing numbers are: 1210 in 9.5517e-05 secs 2020 in 0.000175127 secs 21200 in 0.001102871 secs 3211000 in 0.129514701 secs 42101000 in 1.98685897 secs 521001000 in 29.109239987 secs 6210001000 in 409.844891982 secs Took 489.148319843 secs overall
System: I5-2410m, 2.9 GHz, Linux Kernel 5.5.17, JRuby 9.2.11.1 Run as: $ ruby selfdescribing.rb
- Output:
The self-describing numbers are: 1210 in 0.028907000000000002 secs 2020 in 0.044975999999999995 secs 21200 in 0.081773 secs 3211000 in 0.6109169999999999 secs 42101000 in 1.7770949999999999 secs 521001000 in 18.245994 secs 6210001000 in 250.319289 secs Took 298.839834 secs overall
System: I5-2410m, 2.9 GHz, Linux Kernel 5.5.17, TruffleRuby 20.0.0 Run as: $ ruby selfdescribing.rb
- Output:
The self-describing numbers are: 1210 in 0.01 secs 2020 in 0.012 secs 21200 in 0.029 secs 3211000 in 1.056 secs 42101000 in 1.793 secs 521001000 in 7.223 secs 6210001000 in 191.416 secs Took 240.244 secs overall
Run BASIC
<lang Runbasic>for i = 0 to 50000000 step 10
a$ = str$(i) for c = 1 TO len(a$) d = val(mid$(a$, c, 1)) j(d) = j(d) + 1 k(c-1) = d next c r = 0 for n = 0 to 10 r = r + (j(n) = k(n)) j(n) = 0 k(n) = 0 next n if r = 11 then print i
next i print "== End ==" end</lang>
Rust
<lang rust> fn is_self_desc(xx: u64) -> bool {
let s: String = xx.to_string(); let mut count_vec = vec![0; 10]; for c in s.chars() { count_vec[c.to_digit(10).unwrap() as usize] += 1; } for (i, c) in s.chars().enumerate() { if count_vec[i] != c.to_digit(10).unwrap() as usize { return false; } } return true;
}
fn main() {
for i in 1..100000000 { if is_self_desc(i) { println!("{}", i) } }
} </lang>
Scala
Functional Programming
<lang Scala>object SelfDescribingNumbers extends App {
def isSelfDescribing(a: Int): Boolean = { val s = Integer.toString(a)
(0 until s.length).forall(i => s.count(_.toString.toInt == i) == s(i).toString.toInt) }
println("Curious numbers n = x0 x1 x2...x9 such that xi is the number of digits equal to i in n.")
for (i <- 0 to 42101000 by 10 if isSelfDescribing(i)) println(i)
println("Successfully completed without errors.")
}</lang>
See it running in your browser by Scastie (JVM).
Seed7
<lang seed>$ include "seed7_05.s7i";
const func boolean: selfDescr (in string: stri) is func
result var boolean: check is TRUE; local var integer: idx is 0; var array integer: count is [0 .. 9] times 0; begin for idx range 1 to length(stri) do incr(count[ord(stri[idx]) - ord('0')]); end for; idx := 1; while check and idx <= length(stri) do check := count[pred(idx)] = ord(stri[idx]) - ord('0'); incr(idx); end while; end func;
const proc: gen (in integer: n) is func
local var array integer : digits is 0 times 0; var string: stri is ""; var integer: numberOfOneDigits is 0; var integer: idx is 0; begin while numberOfOneDigits <= 2 and numberOfOneDigits < n - 2 do digits := n times 0; digits[1] := n - 2 - numberOfOneDigits; if digits[1] <> 2 then digits[digits[1] + 1] := 1; digits[2] := 2; digits[3] := 1; else digits[2] := ord(numberOfOneDigits <> 0); digits[3] := 2; end if; stri := ""; for idx range 1 to n do stri &:= chr(ord(digits[idx]) + ord('0')); end for; if selfDescr(stri) then writeln(stri); end if; incr(numberOfOneDigits); end while; end func;
const proc: main is func
local const array integer: nums is [] (1210, 1337, 2020, 21200, 3211000, 42101000); var integer: number is 0; begin for number range nums do write(number <& " is "); if not selfDescr(str(number)) then write("not "); end if; writeln("self describing"); end for; writeln; writeln("All autobiograph numbers:"); for number range 1 to 10 do gen(number); end for; end func;</lang>
Output:
1210 is self describing 1337 is not self describing 2020 is self describing 21200 is self describing 3211000 is self describing 42101000 is self describing All autobiograph numbers: 2020 1210 21200 3211000 42101000 521001000 6210001000
Sidef
<lang ruby>func sdn(Number n) {
var b = [0]*n.len var a = n.digits.flip a.each { |i| b[i] := 0 ++ } a == b
}
var values = [1210, 2020, 21200, 3211000, 42101000, 521001000, 6210001000, 27, 115508]
values.each { |test|
say "#{test} is #{sdn(test) ? : 'NOT ' }a self describing number."
}
say "\nSelf-descriptive numbers less than 1e5 (in base 10):" ^1e5 -> each { |i| say i if sdn(i) }</lang>
- Output:
1210 is a self describing number. 2020 is a self describing number. 21200 is a self describing number. 3211000 is a self describing number. 42101000 is a self describing number. 521001000 is a self describing number. 6210001000 is a self describing number. 27 is NOT a self describing number. 115508 is NOT a self describing number. Self-descriptive numbers less than 1e5 (in base 10): 1210 2020 21200
Extra credit: this will generate all the self-describing numbers in bases 7 to 36: <lang ruby>for b in (7 .. 36) {
var n = ((b-4) * b**(b-1) + 2*(b**(b-2)) + b**(b-3) + b**3 -> base(b)) say "base #{'%2d' % b}: #{n}"
}</lang>
- Output:
base 7: 3211000 base 8: 42101000 base 9: 521001000 base 10: 6210001000 base 11: 72100001000 base 12: 821000001000 base 13: 9210000001000 base 14: a2100000001000 base 15: b21000000001000 base 16: c210000000001000 base 17: d2100000000001000 base 18: e21000000000001000 base 19: f210000000000001000 base 20: g2100000000000001000 base 21: h21000000000000001000 base 22: i210000000000000001000 base 23: j2100000000000000001000 base 24: k21000000000000000001000 base 25: l210000000000000000001000 base 26: m2100000000000000000001000 base 27: n21000000000000000000001000 base 28: o210000000000000000000001000 base 29: p2100000000000000000000001000 base 30: q21000000000000000000000001000 base 31: r210000000000000000000000001000 base 32: s2100000000000000000000000001000 base 33: t21000000000000000000000000001000 base 34: u210000000000000000000000000001000 base 35: v2100000000000000000000000000001000 base 36: w21000000000000000000000000000001000
Swift
<lang swift>import Foundation
extension BinaryInteger {
@inlinable public var isSelfDescribing: Bool { let stringChars = String(self).map({ String($0) }) let counts = stringChars.reduce(into: [Int: Int](), {res, char in res[Int(char), default: 0] += 1})
for (i, n) in stringChars.enumerated() where counts[i, default: 0] != Int(n) { return false }
return true }
}
print("Self-describing numbers less than 100,000,000:")
DispatchQueue.concurrentPerform(iterations: 100_000_000) {i in
defer { if i == 100_000_000 - 1 { exit(0) } }
guard i.isSelfDescribing else { return }
print(i)
}
dispatchMain()</lang>
- Output:
Self-describing numbers less than 100,000,000: 1210 2020 21200 3211000 42101000
Tcl
<lang tcl>package require Tcl 8.5 proc isSelfDescribing num {
set digits [split $num ""] set len [llength $digits] set count [lrepeat $len 0] foreach d $digits {
if {$d >= $len} {return false} lset count $d [expr {[lindex $count $d] + 1}]
} foreach d $digits c $count {if {$c != $d} {return false}} return true
}
for {set i 0} {$i < 100000000} {incr i} {
if {[isSelfDescribing $i]} {puts $i}
}</lang>
UNIX Shell
Seeking self-describing numbers up to 100,000,000 is very time consuming, so we'll just verify a few numbers. <lang bash>selfdescribing() {
local n=$1 local count=() local i for ((i=0; i<${#n}; i++)); do ((count[${n:i:1}]++)) done for ((i=0; i<${#n}; i++)); do (( ${n:i:1} == ${count[i]:-0} )) || return 1 done return 0
}
for n in 0 1 10 11 1210 2020 21200 3211000 42101000; do
if selfdescribing $n; then printf "%d\t%s\n" $n yes else printf "%d\t%s\n" $n no fi
done</lang>
- Output:
0 no 1 no 10 no 11 no 1210 yes 2020 yes 21200 yes 3211000 yes 42101000 yes
VBScript
Takes a very, very long time to check 100M numbers that I have to terminate the script. But the function works. <lang vb> Function IsSelfDescribing(n) IsSelfDescribing = False Set digit = CreateObject("Scripting.Dictionary") For i = 1 To Len(n) k = Mid(n,i,1) If digit.Exists(k) Then digit.Item(k) = digit.Item(k) + 1 Else digit.Add k,1 End If Next c = 0 For j = 0 To Len(n)-1 l = Mid(n,j+1,1) If digit.Exists(CStr(j)) Then If digit.Item(CStr(j)) = CInt(l) Then c = c + 1 End If ElseIf l = 0 Then c = c + 1 Else Exit For End If Next If c = Len(n) Then IsSelfDescribing = True End If End Function
'testing start_time = Now s = "" For m = 1 To 100000000 If IsSelfDescribing(m) Then WScript.StdOut.WriteLine m End If Next end_time = Now WScript.StdOut.WriteLine "Elapse Time: " & DateDiff("s",start_time,end_time) & " seconds" </lang>
Wren
Heavily optimized to complete the search in a reasonable time for a scripting language. <lang ecmascript>var selfDesc = Fn.new { |n|
var ns = "%(n)" var nc = ns.count var count = List.filled(nc, 0) var sum = 0 while (n > 0) { var d = n % 10 if (d >= nc) return false // can't have a digit >= number of digits sum = sum + d if (sum > nc) return false count[d] = count[d] + 1 n = (n/10).floor } // to be self-describing sum of digits must equal number of digits if (sum != nc) return false return ns == count.join() // there must always be at least one zero
}
var start = System.clock System.print("The self-describing numbers are:") var i = 10 // self-describing number must end in 0 var pw = 10 // power of 10 var fd = 1 // first digit var sd = 1 // second digit var dg = 2 // number of digits var mx = 11 // maximum for current batch var lim = 9.1 * 1e9 + 1 // sum of digits can't be more than 10 while (i < lim) {
if (selfDesc.call(i)) { var secs = ((System.clock - start) * 10).round / 10 System.print("%(i) (in %(secs) secs)") } i = i + 10 if (i > mx) { fd = fd + 1 sd = sd - 1 if (sd >= 0) { i = fd * pw } else { pw = pw * 10 dg = dg + 1 i = pw fd = 1 sd = dg - 1 } mx = i + sd*pw/10 }
} var osecs = ((System.clock - start) * 10).round / 10 System.print("\nTook %(osecs) secs overall")</lang>
- Output:
Timings are for an Intel Core i7-8565U machine running Wren 0.2.0 on Ubuntu 18.04.
The self-describing numbers are: 1210 (in 0 secs) 2020 (in 0 secs) 21200 (in 0 secs) 3211000 (in 0.3 secs) 42101000 (in 4.8 secs) 521001000 (in 72.9 secs) 6210001000 (in 1162.5 secs) Took 1392.1 secs overall
XPL0
<lang XPL0>code ChOut=8, IntOut=11;
func SelfDesc(N); \Returns 'true' if N is self-describing int N; int Len, \length = number of digits in N
I, D;
char Digit(10), Count(10);
proc Num2Str(N); \Convert integer N to string in Digit int N; int R; [N:= N/10; R:= rem(0); if N then Num2Str(N); Digit(Len):= R; Len:= Len+1; ];
[Len:= 0; Num2Str(N); for I:= 0 to Len-1 do Count(I):= 0; for I:= 0 to Len-1 do
[D:= Digit(I); if D >= Len then return false; Count(D):= Count(D)+1; ];
for I:= 0 to Len-1 do
if Count(I) # Digit(I) then return false;
return true; ]; \SelfDesc
int N;
for N:= 0 to 100_000_000-1 do
if SelfDesc(N) then [IntOut(0, N); ChOut(0, ^ )]</lang>
Output:
1210 2020 21200 3211000 42101000
Yabasic
<lang Yabasic>FOR N = 1 TO 5E7
IF FNselfdescribing(N) PRINT N
NEXT
sub FNselfdescribing(N)
LOCAL D(9), I, L, O
O = N L = INT(LOG(N, 10)) WHILE(N) I = MOD(N, 10) D(I) = D(I) + 10^(L-I) N = INT(N / 10) WEND L = 0 FOR I = 0 TO 8 : L = L + D(I) : NEXT RETURN O = L
END SUB</lang>
zkl
<lang zkl>fcn isSelfDescribing(n){
if (n.bitAnd(1)) return(False); // Wikipedia: last digit must be zero nu:= n.toString(); ns:=["0".."9"].pump(String,nu.inCommon,"len"); //"12233".inCommon("2")-->"22" (nu+"0000000000")[0,10] == ns; //"2020","2020000000"
}</lang> Since testing a humongous number of numbers is slow, chunk the task into a bunch of threads. Even so, it pegged my 8 way Ivy Bridge Linux box for quite some time (eg the Python & AWK solutions crush this one). <lang zkl>//[1..0x4_000_000].filter(isSelfDescribing).println(); const N=0d500_000; [1..0d100_000_000, N] // chunk and thread, 200 in this case
.apply(fcn(n){ n.filter(N,isSelfDescribing) }.future) .filter().apply("noop").println();</lang>
A future is a thread returning a [delayed] result, future.filter/future.noop will block until the future coughs up the result. Since the results are really sparse for the bigger numbers, filter out the empty results.
- Output:
L(L(1210,2020,21200),L(3211000),L(42101000))
- Clarified and Needing Review
- Programming Tasks
- Solutions by Programming Task
- Ada
- ALGOL 68
- AppleScript
- AutoHotkey
- AWK
- BASIC
- BBC BASIC
- Befunge
- C
- C++
- Common Lisp
- Crystal
- D
- Elixir
- Erlang
- Factor
- Forth
- FreeBASIC
- Go
- Haskell
- Icon
- Unicon
- J
- Java
- JavaScript
- Jq
- Julia
- K
- Kotlin
- Liberty BASIC
- LiveCode
- Logo
- Lua
- Mathematica
- MATLAB
- Octave
- MiniScript
- Modula-2
- Nim
- OoRexx
- PARI/GP
- Pascal
- Perl
- Phix
- PHP
- PicoLisp
- PowerShell
- Prolog
- PureBasic
- Python
- Racket
- Raku
- Red
- REXX
- Ring
- Ruby
- Run BASIC
- Rust
- Scala
- Seed7
- Sidef
- Swift
- Tcl
- UNIX Shell
- VBScript
- Wren
- XPL0
- Yabasic
- Zkl