Four is magic
You are encouraged to solve this task according to the task description, using any language you may know.
 Task
Write a subroutine, function, whatever it may be called in your language, that takes an integer number and returns an English text sequence starting with the English cardinal representation of that integer, the word 'is' and then the English cardinal representation of the count of characters that made up the first word, followed by a comma.
Continue the sequence by using the previous count word as the first word of the next phrase, append 'is' and the cardinal count of the letters in that word.
Continue until you reach four. Since four has four characters, finish by adding the words 'four is magic' and a period. All integers will eventually wind up at four.
For instance, suppose your are given the integer 3. Convert 3 to Three, add is , then the cardinal character count of three, or five, with a comma to separate if from the next phrase. Continue the sequence five is four, (five has four letters), and finally, four is magic.
Three is five, five is four, four is magic.
For reference, here are outputs for 0 through 9.
Zero is four, four is magic. One is three, three is five, five is four, four is magic. Two is three, three is five, five is four, four is magic. Three is five, five is four, four is magic. Four is magic. Five is four, four is magic. Six is three, three is five, five is four, four is magic. Seven is five, five is four, four is magic. Eight is five, five is four, four is magic. Nine is four, four is magic.
 Some task guidelines

 You may assume the input will only contain integer numbers.
 Cardinal numbers between 20 and 100 may use either hyphens or spaces as word separators but they must use a word separator. (23 is twenty three or twentythree not twentythree.)
 Cardinal number conversions should follow the English short scale. (billion is 1e9, trillion is 1e12, etc.)
 Cardinal numbers should not include commas. (20140 is twenty thousand one hundred forty not twenty thousand, one hundred forty.)
 When converted to a string, 100 should be one hundred, not a hundred or hundred, 1000 should be one thousand, not a thousand or thousand.
 When converted to a string, there should be no and in the cardinal string. 130 should be one hundred thirty not one hundred and thirty.
 When counting characters, count all of the characters in the cardinal number including spaces and hyphens. One hundred fiftyone should be 21 not 18.
 The output should follow the format "N is K, K is M, M is ... four is magic." (unless the input is 4, in which case the output should simply be "four is magic.")
 The output can either be the return value from the function, or be displayed from within the function.
 You are encouraged, though not mandated to use proper sentence capitalization.
 You may optionally support negative numbers. 7 is negative seven.
 Show the output here for a small representative sample of values, at least 5 but no more than 25. You are free to choose which which numbers to use for output demonstration.
You can choose to use a library, (module, external routine, whatever) to do the cardinal conversions as long as the code is easily and freely available to the public.
If you roll your own, make the routine accept at minimum any integer from 0 up to 999999. If you use a premade library, support at least up to unsigned 64 bit integers. (or the largest integer supported in your language if it is less.)
Four is magic is a popular codegolf task. This is not code golf. Write legible, idiomatic and well formatted code.
 Related tasks
11l
V Small = [‘zero’, ‘one’, ‘two’, ‘three’, ‘four’,
‘five’, ‘six’, ‘seven’, ‘eight’, ‘nine’,
‘ten’, ‘eleven’, ‘twelve’, ‘thirteen’, ‘fourteen’,
‘fifteen’, ‘sixteen’, ‘seventeen’, ‘eighteen’, ‘nineteen’]
V Tens = [‘’, ‘’, ‘twenty’, ‘thirty’, ‘forty’, ‘fifty’, ‘sixty’, ‘seventy’, ‘eighty’, ‘ninety’]
V Illions = [‘’, ‘ thousand’, ‘ million’, ‘ billion’, ‘ trillion’, ‘ quadrillion’, ‘ quintillion’]
F say(Int64 =n) > String
V result = ‘’
I n < 0
result = ‘negative ’
n = n
I n < 20
result ‘’= Small[Int(n)]
E I n < 100
result ‘’= Tens[Int(n I/ 10)]
V m = n % 10
I m != 0
result ‘’= ‘’Small[Int(m)]
E I n < 1000
result ‘’= Small[Int(n I/ 100)]‘ hundred’
V m = n % 100
I m != 0
result ‘’= ‘ ’say(m)
E
V sx = ‘’
V i = 0
L n > 0
V m = n % 1000
n I/= 1000
I m != 0
V ix = say(m)‘’Illions[i]
I sx.len > 0
ix ‘’= ‘ ’sx
sx = ix
i++
result ‘’= sx
R result
F fourIsMagic(=n)
V s = say(n).capitalize()
V result = s
L n != 4
n = s.len
s = say(n)
result ‘’= ‘ is ’s‘, ’s
R result‘ is magic.’
L(n) [Int64(0), 4, 6, 11, 13, 75, 100, 337, 164, 7FFF'FFFF'FFFF'FFFF]
print(fourIsMagic(n))
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine quintillion two hundred twentythree quadrillion three hundred seventytwo trillion thirtysix billion eight hundred fiftyfour million seven hundred seventyfive thousand eight hundred seven is one hundred ninetysix, one hundred ninetysix is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic.
8086 Assembly
puts: equ 9h ; MSDOS syscall to print a string
cpu 8086
bits 16
org 100h
section .text
;;; Read number from the MSDOS command line
;;; The task says numbers up to 999999 need to be
;;; supported, so we can't get away with using MUL.
mov cl,[80h] ; Is there an argument?
test cl,cl
jnz havearg
mov ah,puts ; If not, print "no input"
mov dx,errinput
int 21h
ret ; And stop.
havearg: mov si,82h ; Start of argument string
xor ch,ch ; CX = argument length
dec cx ; Minus one (space before argument)
xor ax,ax ; Accumulator starts out at 0
xor dx,dx
numloop: mov bp,ax ; DX:AX *= 10
mov di,dx
add ax,ax ; ... *2
adc dx,dx
add ax,ax ; ... *4
adc dx,dx
add ax,bp ; ... *5
adc dx,di
add ax,ax ; ... *10
adc dx,dx
mov bx,ax
lodsb ; Get digit
sub al,'0'
xor ah,ah
add ax,bx ; Add digit
adc dx,0
loop numloop ; Next digit if there is one
;;; DX:AX now contains the binary representation of
;;; the decimal input.
cmp dx,0Fh ; Check that DX:AX <= 999999
jb donum
cmp ax,4240h ; 0F4240h = 1000000
jb donum
mov ah,puts ; Otherwise, print error message
mov dx,errhigh
int 21h
ret
;;; DX:AX = current number
donum: push dx ; Keep number
push ax
mov di,numstring ; Create the string for the number
call cardinal
mov [di],byte '$'
xor [numstring],byte 32 ; Capitalize first letter
.print: mov dx,numstring ; Print the string
mov ah,puts
int 21h
mov dx,is ; print ' is ',
int 21h
pop ax ; Retrieve number
pop dx
test dx,dx ; DX:AX = 4 = magic
jnz .nomagic ; DX <> 0 = not magic
cmp ax,4 ; If AX=4 then magic
je .magic
.nomagic: sub di,numstring ; Calculate length of string
xor dx,dx ; Set DX:AX to DI
mov ax,di
push dx ; Store new number on stack
push ax
mov di,numstring ; Make string for new number
call cardinal
mov [di],byte '$'
mov dx,numstring ; Print the string
mov ah,puts
int 21h
mov dx,commaspace ; Print comma and space
int 21h
jmp .print ; Then use next number as input
.magic: mov dx,magic ; print "magic.",
mov ah,puts
int 21h
ret ; and stop
;;; Subroutine: assuming 0 <= DX:AX <= 999999, write
;;; cardinal representation at ES:DI.
cardinal: mov bp,ax
or bp,dx
jz .zero ; If it is zero, return 'Zero'
mov bp,1000 ; Otherwise, get 1000s part
div bp
test ax,ax ; Above 1000?
jz .hundreds_dx ; If not, just find hundreds
push dx ; Otherwise, save <1000s part,
call .hundreds ; get string for how many thousands,
mov si,thousand ; Then add ' thousand',
call stradd
pop dx ; Restore <1000 part,
test dx,dx ; Even thousands?
jnz .hundreds_spc ; Then add hundreds
ret ; Otherwise we're done
.hundreds_spc: mov al,' ' ; Add space betweeen thousand and rest
stosb
.hundreds_dx: mov ax,dx
.hundreds: mov bp,100 ; Get hundreds part
xor dx,dx
div bp ; AX=100s
test ax,ax ; If zero, no hundreds
jz .tens_dx
dec ax ; Otherwise, look up in singles
shl ax,1 ; table,
mov bx,ax
mov si,[single+bx]
call stradd ; Add to the output string,
mov si,hundred ; Add ' hundred',
call stradd
test dx,dx ; Is there any more?
jne .tens_spc ; If so, add tens
ret ; Otherwise we're done
.tens_spc: mov al,' ' ; Add space between 'hundred' and tens
stosb
.tens_dx: mov ax,dx ; Tens in AX (from hundreds)
.tens: aam ; AH=10s digit, AL=1s digit
test ah,ah ; If 10s digit is 0, single digit
jz .ones
cmp ah,1 ; If 10s digit is 1, teens
jz .teens
mov bl,ah ; Look up tens digit in tens table
sub bl,2
shl bl,1
xor bh,bh
mov si,[tens+bx] ; Add to the output string
call stradd
test al,al ; Ones digit left?
jne .ones_dash ; If so, add dash and ones digit
ret ; Otherwise we're done
.ones_dash: mov [di],byte ''
inc di
.ones: mov bl,al ; Look up ones digit in ones table
dec bl
shl bl,1
xor bh,bh
mov si,[single+bx]
jmp stradd
.teens: mov bl,al ; Look up ones digit in teens table
shl bl,1
xor bh,bh
mov si,[teens+bx]
jmp stradd
.zero: mov si,zero
;;; Copy $terminated string at DS:SI to ES:DI, except
;;; the terminator.
stradd: push ax ; Keep AX register
.loop: lodsb ; Get byte from DS:SI
cmp al,'$' ; Are we there yet?
je .out ; If so, stop
stosb ; Otherwise, store at ES:DI
jmp .loop
.out: pop ax
ret
section .data
single: dw one,two,three,four
dw five,six,seven,eight,nine
teens: dw ten,eleven,twelve,thirteen,fourteen
dw fifteen,sixteen,seventeen,eighteen,nineteen
tens: dw twenty,thirty,forty,fifty
dw sixty,seventy,eighty,ninety
zero: db 'zero$'
one: db 'one$'
two: db 'two$'
three: db 'three$'
four: db 'four$'
five: db 'five$'
six: db 'six$'
seven: db 'seven$'
eight: db 'eight$'
nine: db 'nine$'
ten: db 'ten$'
eleven: db 'eleven$'
twelve: db 'twelve$'
thirteen: db 'thirteen$'
fourteen: db 'fourteen$'
fifteen: db 'fifteen$'
sixteen: db 'sixteen$'
seventeen: db 'seventeen$'
eighteen: db 'eighteen$'
nineteen: db 'nineteen$'
twenty: db 'twenty$'
thirty: db 'thirty$'
forty: db 'forty$'
fifty: db 'fifty$'
sixty: db 'sixty$'
seventy: db 'seventy$'
eighty: db 'eighty$'
ninety: db 'ninety$'
hundred: db ' hundred$'
thousand: db ' thousand$'
is: db ' is $'
magic: db 'magic.$'
commaspace: db ', $'
errinput: db 'No input$'
errhigh: db 'Max input 999999$'
section .bss
numstring: resb 1024
 Output:
C:\>magic 0 Zero is four, four is magic. C:\>magic 1 One is three, three is five, five is four, four is magic. C:\>magic 2 Two is three, three is five, five is four, four is magic. C:\>magic 3 Three is five, five is four, four is magic. C:\>magic 4 Four is magic. C:\>magic 123 One hundred twentythree is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic. C:\>magic 123456 One hundred twentythree thousand four hundred fiftysix is fiftysix, fiftysix is nine, nine is four, four is magic. C:\>magic 999999 Nine hundred ninetynine thousand ninehundred ninetynine is fiftyeight, fiftyeight is eleven, eleven is six, six is three, three is five, five is four, four is magic.
APL
magic←{
t20←'one' 'two' 'three' 'four' 'five' 'six' 'seven' 'eight' 'nine'
t20←t20,'ten' 'eleven' 'twelve' 'thirteen' 'fourteen' 'fifteen' 'sixteen'
t20←t20,'seventeen' 'eighteen' 'nineteen'
tens←'twenty' 'thirty' 'forty' 'fifty' 'sixty' 'seventy' 'eighty' 'ninety'
spell←{
⍵=0:'zero'
{
⍵=0:''
⍵<20:⍵⊃t20
⍵<100:∊tens[(⌊⍵÷10)1],((0≠≢r)/''),r←∇10⍵
⍵<1000:(∇⌊⍵÷100),' hundred',((0≠≢r)/' '),r←∇100⍵
⍵<1e6:(∇⌊⍵÷1000),' thousand',((0≠≢r)/' '),r←∇1000⍵
⍵<1e9:(∇⌊⍵÷1e6),' million',((0≠≢r)/' '),r←∇1e6⍵
⍵<1e12:(∇⌊⍵÷1e9),' billion',((0≠≢r)/' '),r←∇1e9⍵
⍵<1e15:(∇⌊⍵÷1e12),' trillion',((0≠≢r)/' '),r←∇1e12⍵
⍵<1e18:(∇⌊⍵÷1e15),' quadrillion',((0≠≢r)/' '),r←∇1e15⍵
⍵<1e21:(∇⌊⍵÷1e18),' quintillion',((0≠≢r)/' '),r←∇1e18⍵
'Overflow' ⎕SIGNAL 11
}⍵
}
1(819⌶)@1⊢{
n←spell ⍵
⍵=4:n,' is magic.'
n,' is ',(spell ≢n),', ',∇≢n
}⍵
}
 Output:
magic 0 Zero is four, four is magic. magic 4 Four is magic. magic 10 Ten is three, three is five, five is four, four is magic. magic 1234567 One million two hundred thirtyfour thousand five hundred sixtyseven is sixtyn ine, sixtynine is ten, ten is three, three is five, five is four, four is magic. magic 2*64 Eighteen quintillion four hundred fortysix quadrillion seven hundred fortyfour trillion seventythree billion seven hundred nine million five hundred fi ftyone thousand six hundred sixteen is one hundred ninety, one hundred ni nety is eighteen, eighteen is eight, eight is five, five is four, four is magic.
AppleScript
(* Uses a Foundation number formatter for brevity. *)
use AppleScript version "2.4"  OS X 10.10 (Yosemite) or later
use framework "Foundation"
on getNumberFormatter(localeID, numberStyle)
set formatter to current application's class "NSNumberFormatter"'s new()
tell formatter to setLocale:(current application's class "NSLocale"'s localeWithLocaleIdentifier:(localeID))
tell formatter to setNumberStyle:(numberStyle)
return formatter
end getNumberFormatter
on join(listOfText, delimiter)
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to delimiter
set txt to listOfText as text
set AppleScript's text item delimiters to astid
return txt
end join
on fourIsMagic(n)
set n to n as number
if (n is 4) then return "Four is magic."
set formatter to getNumberFormatter("en_US", current application's NSNumberFormatterSpellOutStyle)
set nName to (formatter's stringFromNumber:(n)) as text
if (nName begins with "minus") then
set nName to "Negative " & text from word 2 to 1 of nName
else  Crude IDbased capitalisation. Good enough for English number names.
set nName to character id ((id of character 1 of nName)  32) & text 2 thru 1 of nName
end if
set output to {}
repeat until (n is 4)
set n to (count nName)
set lenName to (formatter's stringFromNumber:(n)) as text
set end of output to nName & " is " & lenName
set nName to lenName
end repeat
set end of output to "four is magic."
return join(output, ", ")
end fourIsMagic
local tests, output, n
set tests to {19, 0, 4, 25, 32, 111, 1.234565789E+9}
set output to {}
repeat with n in tests
set end of output to fourIsMagic(n)
end repeat
return join(output, linefeed)
 Output:
"Negative nineteen is seventeen, seventeen is nine, nine is four, four is magic.
Zero is four, four is magic.
Four is magic.
Twentyfive is eleven, eleven is six, six is three, three is five, five is four, four is magic.
Thirtytwo is ten, ten is three, three is five, five is four, four is magic.
One hundred eleven is eighteen, eighteen is eight, eight is five, five is four, four is magic.
One billion two hundred thirtyfour million five hundred sixtyfive thousand seven hundred eightynine is one hundred two, one hundred two is fifteen, fifteen is seven, seven is five, five is four, four is magic."
AutoHotkey
Based on Number names
Four_is_magic(num){
nubmer := num
while (num <> 4)
result .= (res := spell(num)) " is " spell(num := StrLen(res)) ", "
return PrettyNumber(nubmer) " " result "four is magic!"
}
Spell(n) { ; recursive function to spell out the name of a max 36 digit integer, after leading 0s removed
Static p1=" thousand ",p2=" million ",p3=" billion ",p4=" trillion ",p5=" quadrillion ",p6=" quintillion "
, p7=" sextillion ",p8=" septillion ",p9=" octillion ",p10=" nonillion ",p11=" decillion "
, t2="twenty",t3="thirty",t4="forty",t5="fifty",t6="sixty",t7="seventy",t8="eighty",t9="ninety"
, o0="zero",o1="one",o2="two",o3="three",o4="four",o5="five",o6="six",o7="seven",o8="eight"
, o9="nine",o10="ten",o11="eleven",o12="twelve",o13="thirteen",o14="fourteen",o15="fifteen"
, o16="sixteen",o17="seventeen",o18="eighteen",o19="nineteen"
If (11 < d := (StrLen(n)1)//3) ; #of digit groups of 3
Return "Number too big"
If (d) ; more than 3 digits
Return Spell(SubStr(n,1,3*d)) p%d% ((s:=SubStr(n,13*d)) ? ", " Spell(s) : "")
i := SubStr(n,1,1)
If (n > 99) ; 3 digits
Return o%i% " hundred" ((s:=SubStr(n,2)) ? " " Spell(s) : "")
If (n > 19) ; n = 20..99
Return t%i% ((o:=SubStr(n,2)) ? "" o%o% : "")
Return o%n% ; n = 0..19
}
PrettyNumber(n) { ; inserts thousands separators into a number string
Return RegExReplace(n, "\B(?=((\d{3})+$))", ",")
}
Examples:
for i, num in StrSplit("7,54,235,8463,95723,485723,5472539,15750268,853956201,2736452849,94837286837,636478294710", ",")
result .= Four_is_magic(num) "`n"
MsgBox % result
Outputs:
7 seven is five, five is four, four is magic! 54 fiftyfour is ten, ten is three, three is five, five is four, four is magic! 235 two hundred thirtyfive is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic! 8,463 eight thousand , four hundred sixtythree is fortyone, fortyone is nine, nine is four, four is magic! 95,723 ninetyfive thousand , seven hundred twentythree is fortynine, fortynine is ten, ten is three, three is five, five is four, four is magic! 485,723 four hundred eightyfive thousand , seven hundred twentythree is sixtytwo, sixtytwo is nine, nine is four, four is magic! 5,472,539 five million , four hundred seventytwo thousand , five hundred thirtynine is seventyfive, seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic! 15,750,268 fifteen million , seven hundred fifty thousand , two hundred sixtyeight is seventytwo, seventytwo is eleven, eleven is six, six is three, three is five, five is four, four is magic! 853,956,201 eight hundred fiftythree million , nine hundred fiftysix thousand , two hundred one is eightyfive, eightyfive is eleven, eleven is six, six is three, three is five, five is four, four is magic! 2,736,452,849 two billion , seven hundred thirtysix million , four hundred fiftytwo thousand , eight hundred fortynine is one hundred seven, one hundred seven is seventeen, seventeen is nine, nine is four, four is magic! 94,837,286,837 ninetyfour billion , eight hundred thirtyseven million , two hundred eightysix thousand , eight hundred thirtyseven is one hundred nineteen, one hundred nineteen is twenty, twenty is six, six is three, three is five, five is four, four is magic! 636,478,294,710 six hundred thirtysix billion , four hundred seventyeight million , two hundred ninetyfour thousand , seven hundred ten is one hundred twentytwo, one hundred twentytwo is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic!
AWK
# syntax: GAWK f FOUR_IS_MAGIC.AWK
BEGIN {
init_numtowords()
n = split("1 0 1 2 3 4 5 6 7 8 9 11 21 1995 1000000 1234567890 1100100100100",arr," ")
for (i=1; i<=n; i++) {
a = arr[i]
printf("%s: ",a)
do {
if (a == 4) {
break
}
a = numtowords(a)
b = numtowords(length(a))
printf("%s is %s, ",a,b)
a = length(a)
} while (b !~ /^four$/)
printf("four is magic.\n")
}
exit(0)
}
# source: The AWK Programming Language, page 75
function numtowords(n, minus,str) {
if (n < 0) {
n = n * 1
minus = "minus "
}
if (n == 0) {
str = "zero"
}
else {
str = intowords(n)
}
gsub(/ /," ",str)
gsub(/ $/,"",str)
return(minus str)
}
function intowords(n) {
n = int(n)
if (n >= 1000000000000) {
return intowords(n/1000000000000) " trillion " intowords(n%1000000000000)
}
if (n >= 1000000000) {
return intowords(n/1000000000) " billion " intowords(n%1000000000)
}
if (n >= 1000000) {
return intowords(n/1000000) " million " intowords(n%1000000)
}
if (n >= 1000) {
return intowords(n/1000) " thousand " intowords(n%1000)
}
if (n >= 100) {
return intowords(n/100) " hundred " intowords(n%100)
}
if (n >= 20) {
return tens[int(n/10)] " " intowords(n%10)
}
return(nums[n])
}
function init_numtowords() {
split("one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen",nums," ")
split("ten twenty thirty forty fifty sixty seventy eighty ninety",tens," ")
}
 Output:
1: minus one is nine, nine is four, four is magic. 0: zero is four, four is magic. 1: one is three, three is five, five is four, four is magic. 2: two is three, three is five, five is four, four is magic. 3: three is five, five is four, four is magic. 4: four is magic. 5: five is four, four is magic. 6: six is three, three is five, five is four, four is magic. 7: seven is five, five is four, four is magic. 8: eight is five, five is four, four is magic. 9: nine is four, four is magic. 11: eleven is six, six is three, three is five, five is four, four is magic. 21: twenty one is ten, ten is three, three is five, five is four, four is magic. 1995: one thousand nine hundred ninety five is thirty seven, thirty seven is twelve, twelve is six, six is three, three is five, five is four, four is magic. 1000000: one million is eleven, eleven is six, six is three, three is five, five is four, four is magic. 1234567890: one billion two hundred thirty four million five hundred sixty seven thousand eight hundred ninety is ninety eight, ninety eight is twelve, twelve is six, six is three, three is five, five is four, four is magic. 1100100100100: one trillion one hundred billion one hundred million one hundred thousand one hundred is eighty five, eighty five is eleven, eleven is six, six is three, three is five, five is four, four is magic.
C
#include <stdint.h>
#include <stdio.h>
#include <glib.h>
typedef struct named_number_tag {
const char* name;
uint64_t number;
} named_number;
const named_number named_numbers[] = {
{ "hundred", 100 },
{ "thousand", 1000 },
{ "million", 1000000 },
{ "billion", 1000000000 },
{ "trillion", 1000000000000 },
{ "quadrillion", 1000000000000000ULL },
{ "quintillion", 1000000000000000000ULL }
};
const named_number* get_named_number(uint64_t n) {
const size_t names_len = sizeof(named_numbers)/sizeof(named_number);
for (size_t i = 0; i + 1 < names_len; ++i) {
if (n < named_numbers[i + 1].number)
return &named_numbers[i];
}
return &named_numbers[names_len  1];
}
size_t append_number_name(GString* str, uint64_t n) {
static const char* small[] = {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"
};
static const char* tens[] = {
"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
};
size_t len = str>len;
if (n < 20) {
g_string_append(str, small[n]);
}
else if (n < 100) {
g_string_append(str, tens[n/10  2]);
if (n % 10 != 0) {
g_string_append_c(str, '');
g_string_append(str, small[n % 10]);
}
} else {
const named_number* num = get_named_number(n);
uint64_t p = num>number;
append_number_name(str, n/p);
g_string_append_c(str, ' ');
g_string_append(str, num>name);
if (n % p != 0) {
g_string_append_c(str, ' ');
append_number_name(str, n % p);
}
}
return str>len  len;
}
GString* magic(uint64_t n) {
GString* str = g_string_new(NULL);
for (unsigned int i = 0; ; ++i) {
size_t count = append_number_name(str, n);
if (i == 0)
str>str[0] = g_ascii_toupper(str>str[0]);
if (n == 4) {
g_string_append(str, " is magic.");
break;
}
g_string_append(str, " is ");
append_number_name(str, count);
g_string_append(str, ", ");
n = count;
}
return str;
}
void test_magic(uint64_t n) {
GString* str = magic(n);
printf("%s\n", str>str);
g_string_free(str, TRUE);
}
int main() {
test_magic(5);
test_magic(13);
test_magic(78);
test_magic(797);
test_magic(2739);
test_magic(4000);
test_magic(7893);
test_magic(93497412);
test_magic(2673497412U);
test_magic(10344658531277200972ULL);
return 0;
}
 Output:
Five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyeight is thirteen, thirteen is eight, eight is five, five is four, four is magic. Seven hundred ninetyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Two thousand seven hundred thirtynine is thirtyeight, thirtyeight is twelve, twelve is six, six is three, three is five, five is four, four is magic. Four thousand is thirteen, thirteen is eight, eight is five, five is four, four is magic. Seven thousand eight hundred ninetythree is fortyone, fortyone is nine, nine is four, four is magic. Ninetythree million four hundred ninetyseven thousand four hundred twelve is seventyfive, seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Two billion six hundred seventythree million four hundred ninetyseven thousand four hundred twelve is one hundred, one hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Ten quintillion three hundred fortyfour quadrillion six hundred fiftyeight trillion five hundred thirtyone billion two hundred seventyseven million two hundred thousand nine hundred seventytwo is one hundred ninetyseven, one hundred ninetyseven is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic.
C++
Negative numbers are not supported.
#include <iostream>
#include <string>
#include <cctype>
#include <cstdint>
typedef std::uint64_t integer;
const char* small[] = {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight",
"nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"
};
const char* tens[] = {
"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"
};
struct named_number {
const char* name_;
integer number_;
};
const named_number named_numbers[] = {
{ "hundred", 100 },
{ "thousand", 1000 },
{ "million", 1000000 },
{ "billion", 1000000000 },
{ "trillion", 1000000000000 },
{ "quadrillion", 1000000000000000ULL },
{ "quintillion", 1000000000000000000ULL }
};
const named_number& get_named_number(integer n) {
constexpr size_t names_len = std::size(named_numbers);
for (size_t i = 0; i + 1 < names_len; ++i) {
if (n < named_numbers[i + 1].number_)
return named_numbers[i];
}
return named_numbers[names_len  1];
}
std::string cardinal(integer n) {
std::string result;
if (n < 20)
result = small[n];
else if (n < 100) {
result = tens[n/10  2];
if (n % 10 != 0) {
result += "";
result += small[n % 10];
}
} else {
const named_number& num = get_named_number(n);
integer p = num.number_;
result = cardinal(n/p);
result += " ";
result += num.name_;
if (n % p != 0) {
result += " ";
result += cardinal(n % p);
}
}
return result;
}
inline char uppercase(char ch) {
return static_cast<char>(std::toupper(static_cast<unsigned char>(ch)));
}
std::string magic(integer n) {
std::string result;
for (unsigned int i = 0; ; ++i) {
std::string text(cardinal(n));
if (i == 0)
text[0] = uppercase(text[0]);
result += text;
if (n == 4) {
result += " is magic.";
break;
}
integer len = text.length();
result += " is ";
result += cardinal(len);
result += ", ";
n = len;
}
return result;
}
void test_magic(integer n) {
std::cout << magic(n) << '\n';
}
int main() {
test_magic(5);
test_magic(13);
test_magic(78);
test_magic(797);
test_magic(2739);
test_magic(4000);
test_magic(7893);
test_magic(93497412);
test_magic(2673497412U);
test_magic(10344658531277200972ULL);
return 0;
}
 Output:
Five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyeight is thirteen, thirteen is eight, eight is five, five is four, four is magic. Seven hundred ninetyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Two thousand seven hundred thirtynine is thirtyeight, thirtyeight is twelve, twelve is six, six is three, three is five, five is four, four is magic. Four thousand is thirteen, thirteen is eight, eight is five, five is four, four is magic. Seven thousand eight hundred ninetythree is fortyone, fortyone is nine, nine is four, four is magic. Ninetythree million four hundred ninetyseven thousand four hundred twelve is seventyfive, seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Two billion six hundred seventythree million four hundred ninetyseven thousand four hundred twelve is one hundred, one hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Ten quintillion three hundred fortyfour quadrillion six hundred fiftyeight trillion five hundred thirtyone billion two hundred seventyseven million two hundred thousand nine hundred seventytwo is one hundred ninetyseven, one hundred ninetyseven is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic.
Clojure
(require '[clojure.edn :as edn])
(def names { 0 "zero" 1 "one" 2 "two" 3 "three" 4 "four" 5 "five"
6 "six" 7 "seven" 8 "eight" 9 "nine" 10 "ten" 11 "eleven"
12 "twelve" 13 "thirteen" 14 "fourteen" 15 "fifteen"
16 "sixteen" 17 "seventeen" 18 "eighteen" 19 "nineteen"
20 "twenty" 30 "thirty" 40 "forty" 50 "fifty" 60 "sixty"
70 "seventy" 80 "eighty" 90 "ninety" 100 "hundred"
1000 "thousand" 1000000 "million" 1000000000 "billion"
1000000000000 "trillion" 1000000000000000 "quadrillion"
1000000000000000000 "quintillion" })
(def powersof10 (reverse (sort (filter #(clojure.string/endswith? (str %) "00") (keys names)))))
(defn nameof [n]
(let [p (first (filter #(>= n %) powersof10))]
(cond
(not (nil? p))
(let [quotient (quot n p)
remainder (rem n p)]
(str (nameof quotient) " " (names p) (if (> remainder 0) (str " " (nameof remainder)))))
(and (nil? p) (> n 20))
(let [remainder (rem n 10)
tens ( n remainder)]
(str (names tens) (if (> remainder 0) (str " " (nameof remainder)))))
true
(names n))))
(defn fourismagic
([n] (fourismagic n ""))
([n prefix]
(let [name ((if (empty? prefix) clojure.string/capitalize identity) (nameof n))
newprefix (str prefix (if (not (empty? prefix)) ", "))]
(if (= n 4)
(str newprefix name " is magic.")
(let [len (count name)]
(fourismagic len (str newprefix name " is " (nameof len))))))))
(defn report [n]
(println (str n ": " (fourismagic n))))
(defn main [& args]
(doall (map (comp report edn/readstring) args)))
(if (not= "repl" *commandlineargs*)
(apply main *commandlineargs*))
 Output:
$ clj fourismagic.clj 3252003274489856000 1114111 42 23 {0..9} 3252003274489856000: Three quintillion two hundred fifty two quadrillion three trillion two hundred seventy four billion four hundred eighty nine million eight hundred fifty six thousand is one hundred sixty five, one hundred sixty five is twenty two, twenty two is ten, ten is three, three is five, five is four, four is magic. 1114111: One million one hundred fourteen thousand one hundred eleven is sixty, sixty is five, five is four, four is magic. 42: Forty two is nine, nine is four, four is magic. 23: Twenty three is twelve, twelve is six, six is three, three is five, five is four, four is magic. 0: Zero is four, four is magic. 1: One is three, three is five, five is four, four is magic. 2: Two is three, three is five, five is four, four is magic. 3: Three is five, five is four, four is magic. 4: Four is magic. 5: Five is four, four is magic. 6: Six is three, three is five, five is four, four is magic. 7: Seven is five, five is four, four is magic. 8: Eight is five, five is four, four is magic. 9: Nine is four, four is magic.
Common Lisp
(defun integertotext (int)
(format nil "~@(~A~)" (withoutputtostring (out)
(loop for n = int then (length c)
for c = (format nil "~R" n)
while (/= n 4)
do (format out "~A is ~R, " c (length c))
finally (format out "four is magic.")))))
 Output:
"One thousand twentyfour is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic."
Delphi
program Four_is_magic;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
// https://rosettacode.org/wiki/Number_names#Delphi
const
smallies: array[1..19] of string = ('one', 'two', 'three', 'four', 'five',
'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen',
'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen');
tens: array[2..9] of string = ('twenty', 'thirty', 'forty', 'fifty', 'sixty',
'seventy', 'eighty', 'ninety');
function domaxies(number: int64): string;
const
maxies: array[0..5] of string = (' thousand', ' million', ' billion',
' trillion', ' quadrillion', ' quintillion');
begin
domaxies := '';
if number >= 0 then
domaxies := maxies[number];
end;
function doHundreds(number: int64): string;
begin
Result := '';
if number > 99 then
begin
Result := smallies[number div 100];
Result := Result + ' hundred';
number := number mod 100;
if number > 0 then
Result := Result + ' and ';
end;
if number >= 20 then
begin
Result := Result + tens[number div 10];
number := number mod 10;
if number > 0 then
Result := Result + '';
end;
if (0 < number) and (number < 20) then
Result := Result + smallies[number];
end;
function spell(number: int64): string;
var
scaleFactor: int64;
maxieStart, h: int64;
begin
if number = 0 then
exit('zero');
scaleFactor := 1000000000000000000;
Result := '';
if number < 0 then
begin
number := number;
Result := 'negative ';
end;
maxieStart := 5;
if number < 20 then
exit(smallies[number]);
while scaleFactor > 0 do
begin
if number > scaleFactor then
begin
h := number div scaleFactor;
Result := Result + doHundreds(h) + domaxies(maxieStart);
number := number mod scaleFactor;
if number > 0 then
Result := Result + ', ';
end;
scaleFactor := scaleFactor div 1000;
dec(maxieStart);
end;
end;
//****************************************************\\
const
numbers: array of Int64 = [0, 4, 6, 11, 13, 75, 100, 337, 164, int64.MaxValue];
function fourIsMagic(n: int64): string;
var
s: string;
begin
s := spell(n);
s[1] := upcase(s[1]);
var t := s;
while n <> 4 do
begin
n := s.Length;
s := spell(n);
t := t + ' is ' + s + ', ' + s;
end;
t := t + ' is magic.';
exit(t);
end;
begin
// writeln(spell(4));
for var n in numbers do
writeln(fourIsMagic(n));
readln;
end.
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred and thirtyseven is thirty, thirty is six, six is three, three is five, five is four, four is magic. Negative one hundred and sixtyfour is thirtyfive, thirtyfive is eleven, eleven is six, six is three, three is five, five is four, four is magic. Nine quintillion, two hundred and twentythree quadrillion, three hundred and seventytwo trillion, thirtysix billion, eight hundred and fiftyfour million, seven hundred and seventyfive thousand, eight hundred and seven is two hundred and twentytwo, two hundred and twentytwo is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic.
EasyLang
small$[] = [ "zero" "one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve" "thirteen" "fourteen" "fifteen" "sixteen" "seventeen" "eighteen" "nineteen" ]
tens$[] = [ "" "" "twenty" "thirty" "forty" "fifty" "sixty" "seventy" "eighty" "ninety" ]
illions$[] = [ "" " thousand" " million" " billion" " trillion" " quadrillion" " quintillion" ]
func$ say n .
if n < 0
t$ = "negative "
n = n
.
if n < 20
t$ &= small$[n + 1]
elif n < 100
t$ &= tens$[n div 10 + 1]
s = n mod 10
if s > 0
t$ &= "" & small$[s + 1]
.
elif n < 1000
t$ &= small$[n div 100 + 1] & " hundred"
s = n mod 100
if s > 0
t$ &= " " & say s
.
else
i = 1
while n > 0
p = n mod 1000
n = n div 1000
if p > 0
ix$ = say p & illions$[i]
if sx$ <> ""
ix$ &= " " & sx$
.
sx$ = ix$
.
i += 1
.
t$ &= sx$
.
return t$
.
#
func$ toupper c$ .
c = strcode c$
if c >= 97 and c <= 122
c$ = strchar (c  32)
.
return c$
.
func$ four_is_magic n .
s$ = say n
s$ = toupper substr s$ 1 1 & substr s$ 2 99999
t$ = s$
while n <> 4
n = len s$
s$ = say n
t$ &= " is " & s$ & ", " & s$
.
t$ &= " is magic."
return t$
.
for n in [ 6 13 75 111 337 99999999 ]
print four_is_magic n
.
 Output:
Six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred eleven is eighteen, eighteen is eight, eight is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Ninetynine million nine hundred ninetynine thousand nine hundred ninetynine is seventyeight, seventyeight is thirteen, thirteen is eight, eight is five, five is four, four is magic.
F#
The Function
//Express an Integer in English Language. Nigel Galloway: September 19th., 2018
let fN=[["";"one";"two";"three";"four";"five";"six";"seven";"eight";"nine"];
["ten";"eleven";"twelve";"thirteen";"fourteen";"fifteen";"sixteen";"seventeen";"eighteen";"nineteen"];
["";"";"twenty";"thirty";"fourty";"fifty";"sixty";"seventy";"eighty";"ninety"]]
let rec I2α α β=match α with α when α<20 >β+fN.[α/10].[α%10]
α when α<100 >I2α (α%10) (β+fN.[2].[α/10]+if α%10>0 then " " else "")
α when α<1000 >I2α (α(α/100)*100) (β+fN.[0].[α/100]+" hunred"+if α%100>0 then " and " else "")
α when α<1000000>I2α (α%1000) (β+(I2α (α/1000) "")+" thousand"+if α%100=0 then "" else if (α(α/1000)*1000)<100 then " and " else " ")
The Task
let rec printI2α=function 0>printf "naught>"; printI2α 6
4>printfn "four is magic"
n when n<0>let g = I2α n "minus " in printf "%s>" g; printI2α (g.Length)
n >let g = I2α n "" in printf "%s>" g; printI2α (g.Length)
let N=System.Random()
List.init 25 (fun _>N.Next 999999) > List.iter printI2α
 Output:
seven hundred and fifty thousand nine hundred and eighty eight>sixty>five>four is magic nine hundred and fifty four thousand two hundred and twenty two>sixty one>nine>four is magic three hundred and seventy two thousand nine hundred and thirty one>sixty four>ten>three>five>four is magic six hundred and three thousand six hundred and eighteen>fifty three>eleven>six>three>five>four is magic two hundred and forty nine thousand three hundred and eighty eight>sixty five>ten>three>five>four is magic four hundred and sixty two thousand four hundred and ninety nine>sixty two>nine>four is magic six hundred and fifty thousand eight hundred and seventy five>fifty nine>ten>three>five>four is magic six hundred and ninety three thousand two hundred and seventy nine>sixty four>ten>three>five>four is magic one hundred and thirty three thousand four hundred and seventy six>sixty four>ten>three>five>four is magic seven hundred and thirty two thousand nine hundred and fifteen>sixty>five>four is magic seven hundred and seven thousand five hundred and forty one>fifty eight>eleven>six>three>five>four is magic twenty five thousand six hundred and two>thirty nine>eleven>six>three>five>four is magic seven hundred and sixty nine thousand two hundred and sixty four>sixty two>nine>four is magic eight hundred and ninety five thousand eight hundred and two>fifty eight>eleven>six>three>five>four is magic four hundred and eleven thousand one hundred and four>fifty one>nine>four is magic four hundred and ninety five thousand eight hundred and eighty one>sixty four>ten>three>five>four is magic six hundred and fifty six thousand one hundred and eighty seven>sixty one>nine>four is magic five hundred and twenty two thousand seven hundred and fifty>fifty eight>eleven>six>three>five>four is magic three hundred and forty four thousand and ninety two>fifty two>nine>four is magic three hundred and forty one thousand seven hundred and forty four>sixty five>ten>three>five>four is magic eight hundred and eighty four thousand two hundred and fifty>fifty eight>eleven>six>three>five>four is magic six hundred and forty thousand seven hundred and sixteen>fifty five>ten>three>five>four is magic six hundred and eight thousand three hundred and five>fifty one>nine>four is magic three hundred and ninety nine thousand two hundred and sixty eight>sixty four>ten>three>five>four is magic six hundred and ninety two thousand two hundred and seventy five>sixty two>nine>four is magic
Some particular values:
printI2α 0 > naught>six>three>five>four is magic printI2α 4 > four is magic printI2α 999999 > nine hundred and ninety nine thousand nine hundred and ninety nine>sixty four>ten>three>five>four is magic printI2α 23 > minus twenty three>eighteen>eight>five>four is magic
Factor
Factor's math.text.english
vocabulary does most of the heavy lifting. Since number>text
produces " and " and "," in its output, they are removed with a regular expression.
USING: ascii formatting io kernel make math.text.english regexp
sequences ;
IN: rosettacode.fourismagic
! Strip " and " and "," from the output of Factor's number>text
! word with a regular expression.
: number>english ( n  str )
number>text R/ and ,/ "" rereplace ;
! Return the length of the input integer's text form.
! e.g. 1 > 3
: nextlen ( n  m ) number>english length ;
! Given a starting integer, return the sequence of lengths
! terminating with 4.
! e.g. 1 > { 1 3 5 4 }
: lenchain ( n  seq )
[ [ dup 4 = ] [ dup , nextlen ] until , ] { } make ;
! Convert a nonfour number to its phrase form.
! e.g. 6 > "six is three, "
: nonfour ( n  str )
number>english dup length number>english
"%s is %s, " sprintf ;
! Convert any number to its phrase form.
! e.g. 4 > "four is magic."
: phrase ( n  str )
dup 4 = [ drop "four is magic." ] [ nonfour ] if ;
: saymagic ( n  )
lenchain [ phrase ] map concat capitalize print ;
{ 1 4 11 100 112719908181724 612312 } [ saymagic ] each
 Output:
One is three, three is five, five is four, four is magic. Four is magic. Negative eleven is fifteen, fifteen is seven, seven is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. One hundred twelve trillion seven hundred nineteen billion nine hundred eight million one hundred eightyone thousand seven hundred twentyfour is one hundred fortythree, one hundred fortythree is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. Negative six hundred twelve thousand three hundred twelve is fiftyseven, fiftyseven is eleven, eleven is six, six is three, three is five, five is four, four is magic.
Fortran
MODULE FOUR_IS_MAGIC
IMPLICIT NONE
CHARACTER(8), DIMENSION(20) :: SMALL_NUMS
CHARACTER(7), DIMENSION(8) :: TENS
CHARACTER(7) :: HUNDRED
CHARACTER(8) :: THOUSAND
CHARACTER(8) :: MILLION
CHARACTER(8) :: BILLION
CHARACTER(9) :: TRILLION
CHARACTER(11) :: QUADRILLION
CHARACTER(11) :: QUINTILLION
CHARACTER(1) :: SEPARATOR
CHARACTER(1) :: SPACE
CONTAINS
SUBROUTINE INIT_ARRAYS
SMALL_NUMS(1) = "zero"
SMALL_NUMS(2) = "one"
SMALL_NUMS(3) = "two"
SMALL_NUMS(4) = "three"
SMALL_NUMS(5) = "four"
SMALL_NUMS(6) = "five"
SMALL_NUMS(7) = "six"
SMALL_NUMS(8) = "seven"
SMALL_NUMS(9) = "eight"
SMALL_NUMS(10) = "nine"
SMALL_NUMS(11) = "ten"
SMALL_NUMS(12) = "eleven"
SMALL_NUMS(13) = "twelve"
SMALL_NUMS(14) = "thirteen"
SMALL_NUMS(15) = "fourteen"
SMALL_NUMS(16) = "fifteen"
SMALL_NUMS(17) = "sixteen"
SMALL_NUMS(18) = "seventeen"
SMALL_NUMS(19) = "eighteen"
SMALL_NUMS(20) = "nineteen"
TENS(1) = "twenty"
TENS(2) = "thirty"
TENS(3) = "forty"
TENS(4) = "fifty"
TENS(5) = "sixty"
TENS(6) = "seventy"
TENS(7) = "eight"
TENS(8) = "ninety"
HUNDRED = "hundred"
THOUSAND = "thousand"
MILLION = "million"
BILLION = "billion"
TRILLION = "trillion"
QUADRILLION = "quadrillion"
QUINTILLION = "quintillion"
SEPARATOR = ""
SPACE = " "
END SUBROUTINE INIT_ARRAYS
RECURSIVE FUNCTION STRING_REPRESENTATION(NUM) RESULT(NUM_AS_STR)
INTEGER(16), INTENT(IN) :: NUM
CHARACTER(1000) :: NUM_AS_STR
INTEGER(16), DIMENSION(9) :: COMPONENTS
CALL INIT_ARRAYS()
COMPONENTS = GET_COMPONENTS(NUM)
NUM_AS_STR = TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(9), QUINTILLION)))
NUM_AS_STR = TRIM(NUM_AS_STR) // SPACE // TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(8), QUADRILLION)))
NUM_AS_STR = TRIM(NUM_AS_STR) // SPACE // TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(7), TRILLION)))
NUM_AS_STR = TRIM(NUM_AS_STR) // SPACE // TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(6), BILLION)))
NUM_AS_STR = TRIM(NUM_AS_STR) // SPACE // TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(5), MILLION)))
NUM_AS_STR = TRIM(NUM_AS_STR) // SPACE // TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(4), THOUSAND)))
NUM_AS_STR = TRIM(NUM_AS_STR) // SPACE // TRIM(ADJUSTL(GET_SUBSET(COMPONENTS(3), HUNDRED)))
IF (COMPONENTS(2) .EQ. 1) THEN
NUM_AS_STR = TRIM(ADJUSTL(NUM_AS_STR)) // SPACE // TRIM(ADJUSTL(SMALL_NUMS(10 + COMPONENTS(1) + 1)))
ELSE
IF (COMPONENTS(1) .GT. 0) THEN
IF (COMPONENTS(2) .GT. 0) THEN
NUM_AS_STR = TRIM(ADJUSTL(NUM_AS_STR)) // SPACE // TRIM(ADJUSTL(TENS(COMPONENTS(2)  1))) // SEPARATOR
NUM_AS_STR = TRIM(ADJUSTL(NUM_AS_STR)) // TRIM(ADJUSTL(SMALL_NUMS(COMPONENTS(1) + 1)))
ELSE
NUM_AS_STR = TRIM(ADJUSTL(NUM_AS_STR)) // SPACE // TRIM(ADJUSTL(SMALL_NUMS(COMPONENTS(1) + 1)))
ENDIF
ELSE IF (COMPONENTS(2) .GT. 0) THEN
NUM_AS_STR = TRIM(ADJUSTL(NUM_AS_STR)) // SPACE // TRIM(ADJUSTL(TENS(COMPONENTS(2)  1)))
ENDIF
ENDIF
END FUNCTION STRING_REPRESENTATION
FUNCTION GET_COMPONENTS(NUM)
INTEGER(16), INTENT(IN) :: NUM
INTEGER(16), DIMENSION(9) :: GET_COMPONENTS
INTEGER(16) :: I_UNITS
INTEGER(16) :: I_TENS
INTEGER(16) :: I_HUNDREDS
INTEGER(16) :: I_THOUSANDS
INTEGER(16) :: I_MILLIONS
INTEGER(16) :: I_BILLIONS
INTEGER(16) :: I_TRILLIONS
INTEGER(16) :: I_QUADRILLIONS
INTEGER(16) :: I_QUINTILLIONS
REAL(16) DIVIDE_TEMP
I_UNITS = NUM
DIVIDE_TEMP = (I_UNITS  MOD(I_UNITS, 1000000000000000000))/1000000000000000000
I_QUINTILLIONS = FLOOR(DIVIDE_TEMP)
IF (I_QUINTILLIONS .NE. 0) THEN
I_UNITS = I_UNITS  I_QUINTILLIONS*1000000000000000000
ENDIF
DIVIDE_TEMP = (I_UNITS  MOD(I_UNITS, 1000000000000000))/1000000000000000
I_QUADRILLIONS = FLOOR(DIVIDE_TEMP)
IF (I_QUADRILLIONS .NE. 0) THEN
I_UNITS = I_UNITS  I_QUADRILLIONS*1000000000000000
ENDIF
DIVIDE_TEMP = (I_UNITS  MOD(I_UNITS, 1000000000000))/1000000000000
I_TRILLIONS = FLOOR(DIVIDE_TEMP)
IF (I_TRILLIONS .NE. 0) THEN
I_UNITS = I_UNITS  I_TRILLIONS*1000000000000
ENDIF
DIVIDE_TEMP = (I_UNITS  MOD(I_UNITS, 1000000000))/1000000000
I_BILLIONS = FLOOR(DIVIDE_TEMP)
IF (I_BILLIONS .NE. 0) THEN
I_UNITS = I_UNITS  I_BILLIONS*1000000000
ENDIF
DIVIDE_TEMP = (I_UNITS  MOD(I_UNITS, 1000000))/1000000
I_MILLIONS = FLOOR(DIVIDE_TEMP)
IF (I_MILLIONS .NE. 0) THEN
I_UNITS = I_UNITS  I_MILLIONS*1000000
ENDIF
DIVIDE_TEMP = (I_UNITS  MOD(I_UNITS, 1000))/1000
I_THOUSANDS = FLOOR(DIVIDE_TEMP)
IF (I_THOUSANDS .NE. 0) THEN
I_UNITS = I_UNITS  I_THOUSANDS*1000
ENDIF
DIVIDE_TEMP = I_UNITS/1E2
I_HUNDREDS = FLOOR(DIVIDE_TEMP)
IF (I_HUNDREDS .NE. 0) THEN
I_UNITS = I_UNITS  I_HUNDREDS*1E2
ENDIF
DIVIDE_TEMP = I_UNITS/10.
I_TENS = FLOOR(DIVIDE_TEMP)
IF (I_TENS .NE. 0) THEN
I_UNITS = I_UNITS  I_TENS*10
ENDIF
GET_COMPONENTS(1) = I_UNITS
GET_COMPONENTS(2) = I_TENS
GET_COMPONENTS(3) = I_HUNDREDS
GET_COMPONENTS(4) = I_THOUSANDS
GET_COMPONENTS(5) = I_MILLIONS
GET_COMPONENTS(6) = I_BILLIONS
GET_COMPONENTS(7) = I_TRILLIONS
GET_COMPONENTS(8) = I_QUADRILLIONS
GET_COMPONENTS(9) = I_QUINTILLIONS
END FUNCTION GET_COMPONENTS
FUNCTION GET_SUBSET(COUNTER, LABEL) RESULT(OUT_STR)
CHARACTER(*), INTENT(IN) :: LABEL
INTEGER(16), INTENT(IN) :: COUNTER
CHARACTER(100) :: OUT_STR
OUT_STR = ""
IF (COUNTER .GT. 0) THEN
IF (COUNTER .LT. 20) THEN
OUT_STR = SPACE // TRIM(ADJUSTL(SMALL_NUMS(COUNTER + 1)))
ELSE
OUT_STR = SPACE // TRIM(ADJUSTL(STRING_REPRESENTATION(COUNTER)))
ENDIF
OUT_STR = TRIM(ADJUSTL(OUT_STR)) // SPACE // TRIM(LABEL)
ENDIF
END FUNCTION GET_SUBSET
SUBROUTINE FIND_MAGIC(NUM)
INTEGER(16), INTENT(IN) :: NUM
INTEGER(16) :: CURRENT, LEN_SIZE
CHARACTER(1000) :: CURRENT_STR, CURRENT_STR_LEN
CHARACTER(1000) :: OUT_STR
CURRENT = NUM
OUT_STR = ""
DO WHILE (CURRENT .NE. 4)
CURRENT_STR = STRING_REPRESENTATION(CURRENT)
LEN_SIZE = LEN_TRIM(ADJUSTL(CURRENT_STR))
CURRENT_STR_LEN = STRING_REPRESENTATION(LEN_SIZE)
OUT_STR = TRIM(ADJUSTL(OUT_STR)) // SPACE // TRIM(ADJUSTL(CURRENT_STR))
OUT_STR = TRIM(ADJUSTL(OUT_STR)) // " is " // TRIM(ADJUSTL(CURRENT_STR_LEN)) // ","
CURRENT = LEN_SIZE
ENDDO
WRITE(*,*) TRIM(ADJUSTL(OUT_STR)) // SPACE // "four is magic."
END SUBROUTINE FIND_MAGIC
END MODULE FOUR_IS_MAGIC
PROGRAM TEST_NUM_NAME
USE FOUR_IS_MAGIC
IMPLICIT NONE
INTEGER(2) I
INTEGER(16), DIMENSION(10) :: TEST_NUMS = (/5, 13, 78, 797, 2739, 4000, 7893, 93497412, 2673497412, 10344658531277200972/)
CHARACTER(1000) :: NUM_NAME
DO I=1, SIZE(TEST_NUMS)
CALL FIND_MAGIC(TEST_NUMS(I))
ENDDO
END PROGRAM
five is four, four is magic. thirteen is eight, eight is five, five is four, four is magic. seventyeight is thirteen, thirteen is eight, eight is five, five is four, four is magic. seven hundred ninetyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. two thousand seven hundred thirtynine is thirtyeight, thirtyeight is twelve, twelve is six, six is three, three is five, five is four, four is magic. four thousand is thirteen, thirteen is eight, eight is five, five is four, four is magic. seven thousand eight hundred ninetythree is fortyone, fortyone is nine, nine is four, four is magic. ninetythree million four hundred ninetyseven thousand four hundred twelve is seventyfive, seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. two billion six hundred seventythree million four hundred ninetyseven thousand four hundred twelve is one hundred, one hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. ten quintillion three hundred fortyfour quadrillion six hundred fiftyeight trillion five hundred thirtyone billion two hundred seventyseven million two hundred thousand nine hundred seventytwo is one hundred ninetyseven, one hundred ninetyseven is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic.
FreeBASIC
#define floor(x) ((x*2.00.5) Shr 1)
Dim Shared veintes(1 To 20) As String*9 => _
{"zero", "one", "two", "three", "four", "five", "six", _
"seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", _
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"}
Dim Shared decenas(1 To 8) As String*7 => _
{"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}
Type myorder
var1 As Double
var2 As String*8
End Type
Dim Shared orders(1 To 4) As myorder => _
{(10^12,"trillion"), (10^9,"billion"), (10^6,"million"), (10^3,"thousand")}
Function centenas(n As Integer) As String
If n < 20 Then
Return veintes((n Mod 20)+1)
Elseif (n Mod 10) = 0 Then
Return decenas((floor(n/10) Mod 10)1)
End If
Return decenas((floor(n/10) Mod 10)1) & "" & veintes((n Mod 10)+1)
End Function
Function miles(n As Integer) As String
If n < 100 Then
Return centenas(n)
Elseif (n Mod 100) = 0 Then
Return veintes((floor(n/100) Mod 20)+1) & " centenas"
End If
Return veintes((floor(n/100) Mod 20)+1) & " centenas " & centenas(n Mod 100)
End Function
Function triplet(n As Integer) As String
Dim As Integer order, high, low
Dim As String nombre, res = ""
For i As Integer = 1 To Ubound(orders)
order = orders(i).var1
nombre = orders(i).var2
high = floor(n/order)
low = (n Mod order)
If high <> 0 Then res &= miles(high) & " " & nombre
n = low
If low = 0 Then Exit For : End If
If Len(res) And high <> 0 Then res &= " "
Next i
If n <> 0 Or res="" Then
res &= miles(floor(n))
End If
Return res
End Function
Function deletrear(n As Integer) As String
Dim As String res = ""
If n < 0 Then
res = "negative "
n = n
End If
res &= triplet(n)
Return res
End Function
Function fourIsMagic(n As Integer) As String
Dim As String s = deletrear(n)
s = Mid(Ucase(s), 1, 1) & Mid(s, 2, Len(s))
Dim As String t = s
While n <> 4
n = Len(s)
s = deletrear(n)
t &= " is " & s & ", " & s
Wend
t &= " is magic."
Return t
End Function
Dim As Longint tests(1 To 21) = _
{21, 1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 12, _
34, 123, 456, 1024, 1234, 12345, 123456, 1010101}
For i As Integer = 1 To Ubound(tests)
Print Using "#######: &"; tests(i); fourIsMagic(tests(i))
Next i
Sleep
 Output:
21: Negative twentyone is nineteen, nineteen is eight, eight is five, five is four, four is magic. 1: Negative one is twelve, twelve is six, six is three, three is five, five is four, four is magic. 0: Zero is four, four is magic. 1: One is three, three is five, five is four, four is magic. 2: Two is three, three is five, five is four, four is magic. 3: Three is five, five is four, four is magic. 4: Four is magic. 5: Five is four, four is magic. 6: Six is three, three is five, five is four, four is magic. 7: Seven is five, five is four, four is magic. 8: Eight is five, five is four, four is magic. 9: Nine is four, four is magic. 12: Twelve is six, six is three, three is five, five is four, four is magic. 34: Thirtyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic. 123: One centenas twentythree is twentyfive, twentyfive is eleven, eleven is six, six is three, three is five, five is four, four is magic. 456: Four centenas fiftysix is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. 1024: One thousand twentyfour is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic. 1234: One thousand two centenas thirtyfour is thirtyseven, thirtyseven is twelve, twelve is six, six is three, three is five, five is four, four is magic. 12345: Twelve thousand three centenas fortyfive is fortyone, fortyone is nine, nine is four, four is magic. 123456: One centenas twentythree thousand four centenas fiftysix is fiftyeight, fiftyeight is eleven, eleven is six, six is three, three is five, five is four, four is magic. 1010101: One million ten thousand one centenas one is fortyone, fortyone is nine, nine is four, four is magic.
FutureBasic
include "NSLog.incl"
local fn FourIsMagic( number as CFNumberRef ) as CFStringRef
CFMutableStringRef result = fn MutableStringNew
NumberFormatterRef formatter = fn NumberFormatterWithStyle( NSNumberFormatterSpellOutStyle )
NumberFormatterSetLocale( formatter, fn LocaleWithIdentifier( @"en_EN" ) )
CFStringRef numberString = fn NumberFormatterStringFromNumber( formatter, number )
MutableStringAppendString( result, fn StringCapitalizedString( numberString ) )
while ( fn StringIsEqual( numberString, @"four" ) == NO )
numberString = fn NumberFormatterStringFromNumber( formatter, fn NumberWithInteger( len(numberString) ) )
MutableStringAppendString( result, fn StringWithFormat( @" is %@, %@", numberString, numberString ) )
wend
MutableStringAppendString( result, @" is magic." )
end fn = result
NSInteger i
CFNumberRef testInput
CFArrayRef testNumbers : testNumbers = @[@23, @1000000000, @20140, @100, @130, @151, @7]
NSLog( @"Outputs 0 through 9:\n" )
for i = 0 to 9
NSLog( @"%@", fn FourIsMagic( fn NumberWithInteger( i ) ) )
next
NSLog( @"\nOther number tests:\n" )
for testInput in testNumbers
NSLog( @"%@", fn FourIsMagic( testInput ) )
next
HandleEvents
 Output:
Outputs 0 through 9: Zero is four, four is magic. One is three, three is five, five is four, four is magic. Two is three, three is five, five is four, four is magic. Three is five, five is four, four is magic. Four is magic. Five is four, four is magic. Six is three, three is five, five is four, four is magic. Seven is five, five is four, four is magic. Eight is five, five is four, four is magic. Nine is four, four is magic. Other number tests: TwentyThree is twelve, twelve is six, six is three, three is five, five is four, four is magic. One Billion is eleven, eleven is six, six is three, three is five, five is four, four is magic. Twenty Thousand One Hundred Forty is thirtythree, thirtythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. One Hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. One Hundred Thirty is eighteen, eighteen is eight, eight is five, five is four, four is magic. One Hundred FiftyOne is twentyone, twentyone is ten, ten is three, three is five, five is four, four is magic. Minus Seven is eleven, eleven is six, six is three, three is five, five is four, four is magic.
Go
Uses the say
function from the
Number names task.
package main
import (
"fmt"
"math"
"strings"
)
func main() {
for _, n := range [...]int64{
0, 4, 6, 11, 13, 75, 100, 337, 164,
math.MaxInt64,
} {
fmt.Println(fourIsMagic(n))
}
}
func fourIsMagic(n int64) string {
s := say(n)
s = strings.ToUpper(s[:1]) + s[1:]
t := s
for n != 4 {
n = int64(len(s))
s = say(n)
t += " is " + s + ", " + s
}
t += " is magic."
return t
}
// Following is from https://rosettacode.org/wiki/Number_names#Go
var small = [...]string{"zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"}
var tens = [...]string{"", "", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"}
var illions = [...]string{"", " thousand", " million", " billion",
" trillion", " quadrillion", " quintillion"}
func say(n int64) string {
var t string
if n < 0 {
t = "negative "
// Note, for math.MinInt64 this leaves n negative.
n = n
}
switch {
case n < 20:
t += small[n]
case n < 100:
t += tens[n/10]
s := n % 10
if s > 0 {
t += "" + small[s]
}
case n < 1000:
t += small[n/100] + " hundred"
s := n % 100
if s > 0 {
t += " " + say(s)
}
default:
// work righttoleft
sx := ""
for i := 0; n > 0; i++ {
p := n % 1000
n /= 1000
if p > 0 {
ix := say(p) + illions[i]
if sx != "" {
ix += " " + sx
}
sx = ix
}
}
t += sx
}
return t
}
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine quintillion two hundred twentythree quadrillion three hundred seventytwo trillion thirtysix billion eight hundred fiftyfour million seven hundred seventyfive thousand eight hundred seven is one hundred ninetysix, one hundred ninetysix is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic.
Haskell
Negative numbers are supported.
module Main where
import Data.List (find)
import Data.Char (toUpper)
firstNums :: [String]
firstNums =
[ "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
]
tens :: [String]
tens = ["twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
biggerNumbers :: [(Int, String)]
biggerNumbers =
[(100, "hundred"), (1000, "thousand"), (1000000, "million"), (1000000000, "billion"), (1000000000000, "trillion")]
cardinal :: Int > String
cardinal n
 n' < 20 =
negText ++ firstNums !! n'
 n' < 100 =
negText ++ tens !! (n' `div` 10  2) ++ if n' `mod` 10 /= 0 then "" ++ firstNums !! (n' `mod` 10) else ""
 otherwise =
let (num, name) =
maybe
(last biggerNumbers)
fst
(find (\((num_, _), (num_', _)) > n' < num_') (zip biggerNumbers (tail biggerNumbers)))
smallerNum = cardinal (n' `div` num)
in negText ++ smallerNum ++ " " ++ name ++ if n' `mod` num /= 0 then " " ++ cardinal (n' `mod` num) else ""
where
n' = abs n
negText = if n < 0 then "negative " else ""
capitalized :: String > String
capitalized (x : xs) = toUpper x : xs
capitalized [] = []
magic :: Int > String
magic =
go True
where
go first num =
let cardiNum = cardinal num
in (if first then capitalized else id) cardiNum ++ " is "
++ if num == 4
then "magic."
else cardinal (length cardiNum) ++ ", " ++ go False (length cardiNum)
main :: IO ()
main = do
putStrLn $ magic 3
putStrLn $ magic 15
putStrLn $ magic 4
putStrLn $ magic 10
putStrLn $ magic 20
putStrLn $ magic (13)
putStrLn $ magic 999999
 Output:
Three is five, five is four, four is magic. Fifteen is seven, seven is five, five is four, four is magic. Four is magic. Ten is three, three is five, five is four, four is magic. Twenty is six, six is three, three is five, five is four, four is magic. Negative thirteen is seventeen, seventeen is nine, nine is four, four is magic. Nine hundred ninetynine thousand nine hundred ninetynine is fiftyeight, fiftyeight is eleven, eleven is six, six is three, three is five, five is four, four is magic.
J
names =. 'one';'two';'three';'four';'five';'six';'seven';'eight';'nine';'ten';'eleven';'twelve';'thirteen';'fourteen';'fifteen';'sixteen';'seventeen';'eighteen';'nineteen'
tens =. '';'twenty';'thirty';'forty';'fifty';'sixty';'seventy';'eighty';'ninety'
NB. selects the xth element from list y
lookup =: >@{:@{.
NB. string formatting
addspace =: ((' '"_, ]) ` ]) @. (<&0 @ {: @ $)
NB. numbers in range 1 to 19
s1 =: lookup&names
NB. numbers in range 20 to 99
s2d=: (lookup&tens @ <. @ %&10) , addspace @ (s1 @ (10&))
NB. numbers in range 100 to 999
s3d =: s1 @ (<.@%&100), ' hundred', addspace @ s2d @ (100&)
NB. numbers in range 1 to 999
s123d =: s1 ` s2d ` s3d @. (>& 19 + >&99)
NB. numbers in range 1000 to 999999
s456d =: (s123d @<.@%&1000), ' thousand', addspace @ s123d @ (1000&)
NB. stringify numbers in range 1 to 999999
stringify =: s123d ` s456d @. (>&999)
NB. takes an int and returns an int of the length of the string of the input
lengthify =: {: @ $ @ stringify
NB. determines the string that should go after ' is '
what =: ((stringify @ lengthify), (', '"_)) ` ('magic'"_) @. (=&4)
runonce =: stringify , ' is ', what
run =: runonce, ((run @ lengthify) ` (''"_) @. (=&4))
doall =: run"0
inputs =: 4 8 16 25 89 365 2586 25865 369854
doall inputs
 Output:
four is magic eight is five, five is four, four is magic sixteen is seven, seven is five, five is four, four is magic twenty five is eleven, eleven is six, six is three, three is five, five is four, four is magic eighty nine is eleven, eleven is six, six is three, three is five, five is four, four is magic three hundred sixty five is twenty four, twenty four is eleven, eleven is six, six is three, three is five, five is four, four is magic two thousand five hundred eighty six is thirty six, thirty six is ten, ten is three, three is five, five is four, four is magic twenty five thousand eight hundred sixty five is forty five, forty five is ten, ten is three, three is five, five is four, four is magic three hundred sixty nine thousand eight hundred fifty four is fifty eight, fifty eight is eleven, eleven is six, six is three, three is five, five is four, four is magic
Java
public class FourIsMagic {
public static void main(String[] args) {
for ( long n : new long[] {6, 60, 89, 300, 670, 2000, 2467, 20000, 24500,200000, 230000, 246571, 2300000, 2465712, 20000000, 24657123, 230000000, 245000000, 246570000, 123456789712345l, 8777777777777777777L, Long.MAX_VALUE}) {
String magic = fourIsMagic(n);
System.out.printf("%d = %s%n", n, toSentence(magic));
}
}
private static final String toSentence(String s) {
return s.substring(0,1).toUpperCase() + s.substring(1) + ".";
}
private static final String[] nums = new String[] {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
private static final String[] tens = new String[] {"zero", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"};
private static final String fourIsMagic(long n) {
if ( n == 4 ) {
return numToString(n) + " is magic";
}
String result = numToString(n);
return result + " is " + numToString(result.length()) + ", " + fourIsMagic(result.length());
}
private static final String numToString(long n) {
if ( n < 0 ) {
return "negative " + numToString(n);
}
int index = (int) n;
if ( n <= 19 ) {
return nums[index];
}
if ( n <= 99 ) {
return tens[index/10] + (n % 10 > 0 ? " " + numToString(n % 10) : "");
}
String label = null;
long factor = 0;
if ( n <= 999 ) {
label = "hundred";
factor = 100;
}
else if ( n <= 999999) {
label = "thousand";
factor = 1000;
}
else if ( n <= 999999999) {
label = "million";
factor = 1000000;
}
else if ( n <= 999999999999L) {
label = "billion";
factor = 1000000000;
}
else if ( n <= 999999999999999L) {
label = "trillion";
factor = 1000000000000L;
}
else if ( n <= 999999999999999999L) {
label = "quadrillion";
factor = 1000000000000000L;
}
else {
label = "quintillion";
factor = 1000000000000000000L;
}
return numToString(n / factor) + " " + label + (n % factor > 0 ? " " + numToString(n % factor ) : "");
}
}
 Output:
6 = Six is three, three is five, five is four, four is magic. 60 = Sixty is five, five is four, four is magic. 89 = Eighty nine is eleven, eleven is six, six is three, three is five, five is four, four is magic. 300 = Three hundred is thirteen, thirteen is eight, eight is five, five is four, four is magic. 670 = Six hundred seventy is nineteen, nineteen is eight, eight is five, five is four, four is magic. 2000 = Two thousand is twelve, twelve is six, six is three, three is five, five is four, four is magic. 2467 = Two thousand four hundred sixty seven is thirty seven, thirty seven is twelve, twelve is six, six is three, three is five, five is four, four is magic. 20000 = Twenty thousand is fifteen, fifteen is seven, seven is five, five is four, four is magic. 24500 = Twenty four thousand five hundred is thirty three, thirty three is twelve, twelve is six, six is three, three is five, five is four, four is magic. 200000 = Two hundred thousand is twenty, twenty is six, six is three, three is five, five is four, four is magic. 230000 = Two hundred thirty thousand is twenty seven, twenty seven is twelve, twelve is six, six is three, three is five, five is four, four is magic. 246571 = Two hundred forty six thousand five hundred seventy one is fifty five, fifty five is ten, ten is three, three is five, five is four, four is magic. 2300000 = Two million three hundred thousand is thirty four, thirty four is eleven, eleven is six, six is three, three is five, five is four, four is magic. 2465712 = Two million four hundred sixty five thousand seven hundred twelve is sixty five, sixty five is ten, ten is three, three is five, five is four, four is magic. 20000000 = Twenty million is fourteen, fourteen is eight, eight is five, five is four, four is magic. 24657123 = Twenty four million six hundred fifty seven thousand one hundred twenty three is seventy seven, seventy seven is thirteen, thirteen is eight, eight is five, five is four, four is magic. 230000000 = Two hundred thirty million is twenty six, twenty six is ten, ten is three, three is five, five is four, four is magic. 245000000 = Two hundred forty five million is thirty, thirty is six, six is three, three is five, five is four, four is magic. 246570000 = Negative two hundred forty six million five hundred seventy thousand is sixty eight, sixty eight is eleven, eleven is six, six is three, three is five, five is four, four is magic. 123456789712345 = One hundred twenty three trillion four hundred fifty six billion seven hundred eighty nine million seven hundred twelve thousand three hundred forty five is one hundred fifty three, one hundred fifty three is twenty three, twenty three is twelve, twelve is six, six is three, three is five, five is four, four is magic. 8777777777777777777 = Eight quintillion seven hundred seventy seven quadrillion seven hundred seventy seven trillion seven hundred seventy seven billion seven hundred seventy seven million seven hundred seventy seven thousand seven hundred seventy seven is two hundred thirty one, two hundred thirty one is twenty two, twenty two is ten, ten is three, three is five, five is four, four is magic. 9223372036854775807 = Nine quintillion two hundred twenty three quadrillion three hundred seventy two trillion thirty six billion eight hundred fifty four million seven hundred seventy five thousand eight hundred seven is one hundred ninety six, one hundred ninety six is twenty two, twenty two is ten, ten is three, three is five, five is four, four is magic.
JavaScript
Utilizing the new BigInt type (added in ECMAScript 2019), and akin to the Python example, this implementation supports numbers as high as at least 10^3003, and could support even higher values by adding items to the dictionary.
To test whether a particular JavaScript interpreter implements BigInt
, we can evaluate a boolean expression like:
Object.getOwnPropertyNames(this).includes('BigInt')
const reverseOrderedNumberToTextMap = (function () {
const rawNumberToTextMapping = { // Ported over from the Python solution.
[1n]: "one",
[2n]: "two",
[3n]: "three",
[4n]: "four",
[5n]: "five",
[6n]: "six",
[7n]: "seven",
[8n]: "eight",
[9n]: "nine",
[10n]: "ten",
[11n]: "eleven",
[12n]: "twelve",
[13n]: "thirteen",
[14n]: "fourteen",
[15n]: "fifteen",
[16n]: "sixteen",
[17n]: "seventeen",
[18n]: "eighteen",
[19n]: "nineteen",
[20n]: "twenty",
[30n]: "thirty",
[40n]: "forty",
[50n]: "fifty",
[60n]: "sixty",
[70n]: "seventy",
[80n]: "eighty",
[90n]: "ninety",
[100n]: "hundred",
[1000n]: "thousand",
[10n ** 6n]: "million",
[10n ** 9n]: "billion",
[10n ** 12n]: "trillion",
[10n ** 15n]: "quadrillion",
[10n ** 18n]: "quintillion",
[10n ** 21n]: "sextillion",
[10n ** 24n]: "septillion",
[10n ** 27n]: "octillion",
[10n ** 30n]: "nonillion",
[10n ** 33n]: "decillion",
[10n ** 36n]: "undecillion",
[10n ** 39n]: "duodecillion",
[10n ** 42n]: "tredecillion",
[10n ** 45n]: "quattuordecillion",
[10n ** 48n]: "quinquadecillion",
[10n ** 51n]: "sedecillion",
[10n ** 54n]: "septendecillion",
[10n ** 57n]: "octodecillion",
[10n ** 60n]: "novendecillion",
[10n ** 63n]: "vigintillion",
[10n ** 66n]: "unvigintillion",
[10n ** 69n]: "duovigintillion",
[10n ** 72n]: "tresvigintillion",
[10n ** 75n]: "quattuorvigintillion",
[10n ** 78n]: "quinquavigintillion",
[10n ** 81n]: "sesvigintillion",
[10n ** 84n]: "septemvigintillion",
[10n ** 87n]: "octovigintillion",
[10n ** 90n]: "novemvigintillion",
[10n ** 93n]: "trigintillion",
[10n ** 96n]: "untrigintillion",
[10n ** 99n]: "duotrigintillion",
[10n ** 102n]: "trestrigintillion",
[10n ** 105n]: "quattuortrigintillion",
[10n ** 108n]: "quinquatrigintillion",
[10n ** 111n]: "sestrigintillion",
[10n ** 114n]: "septentrigintillion",
[10n ** 117n]: "octotrigintillion",
[10n ** 120n]: "noventrigintillion",
[10n ** 123n]: "quadragintillion",
[10n ** 153n]: "quinquagintillion",
[10n ** 183n]: "sexagintillion",
[10n ** 213n]: "septuagintillion",
[10n ** 243n]: "octogintillion",
[10n ** 273n]: "nonagintillion",
[10n ** 303n]: "centillion",
[10n ** 306n]: "uncentillion",
[10n ** 309n]: "duocentillion",
[10n ** 312n]: "trescentillion",
[10n ** 333n]: "decicentillion",
[10n ** 336n]: "undecicentillion",
[10n ** 363n]: "viginticentillion",
[10n ** 366n]: "unviginticentillion",
[10n ** 393n]: "trigintacentillion",
[10n ** 423n]: "quadragintacentillion",
[10n ** 453n]: "quinquagintacentillion",
[10n ** 483n]: "sexagintacentillion",
[10n ** 513n]: "septuagintacentillion",
[10n ** 543n]: "octogintacentillion",
[10n ** 573n]: "nonagintacentillion",
[10n ** 603n]: "ducentillion",
[10n ** 903n]: "trecentillion",
[10n ** 1203n]: "quadringentillion",
[10n ** 1503n]: "quingentillion",
[10n ** 1803n]: "sescentillion",
[10n ** 2103n]: "septingentillion",
[10n ** 2403n]: "octingentillion",
[10n ** 2703n]: "nongentillion",
[10n ** 3003n]: "millinillion"
};
return new Map(Object.entries(rawNumberToTextMapping)
.sort((a, b) => BigInt(a[0]) > BigInt(b[0]) ? 1 : 1)
.map(numberAndText => [BigInt(numberAndText[0]), numberAndText[1]]));
})();
function getCardinalRepresentation(number)
{
if (number == 0n)
{
return "zero";
}
function* generateCardinalRepresentationTokens(number)
{
if (number <= 0n)
{
yield "negative";
number *= 1n;
}
for (const [currentEntryNumber, currentEntryText] of reverseOrderedNumberToTextMap.entries())
{
if (number >= currentEntryNumber)
{
if (currentEntryNumber >= 100n)
{
yield* generateCardinalRepresentationTokens(number / currentEntryNumber);
}
yield currentEntryText;
number = currentEntryNumber;
}
}
}
return [...generateCardinalRepresentationTokens(number)].join(" ");
}
function* generateFourIsMagicParts(number)
{
if (typeof number != "bigint")
{
number = BigInt(number);
}
if (number == 4n)
{
yield "four is magic";
}
else
{
const cardinalRepresentation = getCardinalRepresentation(number);
yield `${cardinalRepresentation} is ${getCardinalRepresentation(BigInt(cardinalRepresentation.length))}`;
yield* generateFourIsMagicParts(cardinalRepresentation.length);
}
}
function capitalizeFirstLetter(str)
{
return str.replace(/^([az])/, chr => chr.toUpperCase());
}
function fourIsMagic(number)
{
return capitalizeFirstLetter(`${[...generateFourIsMagicParts(number)].join(", ")}.`);
}
[
0,
150,
210,
10n ** 2703n + 1225n,
4,
4,
10n ** 3003n + 42n
].map(fourIsMagic).join("\n\n");
 Output:
Zero is four, four is magic. Negative one hundred fifty is twenty six, twenty six is ten, ten is three, three is five, five is four, four is magic. Two hundred ninety twenty is twenty five, twenty five is eleven, eleven is six, six is three, three is five, five is four, four is magic. One nongentillion one thousand two hundred ninety thirty five is sixty one, sixty one is nine, nine is four, four is magic. Four is magic. Negative four is thirteen, thirteen is eight, eight is five, five is four, four is magic. One millinillion forty two is twenty six, twenty six is ten, ten is three, three is five, five is four, four is magic.
jq
Adapted from Wren
Also works with gojq, the Go implementation of jq
Also works with fq, a Go implementation of a large subset of jq
def small: ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
def tens: ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];
def illions: ["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion"];
def say:
{n: ., t: ""}
 if .n < 0
then .t = "negative "  .n = .n
else . end
 if .n < 20
then .t += small[.n]
elif .n < 100
then .t += tens[(.n/10)floor]
 .s = .n % 10
 if (.s > 0) then .t += "" + small[.s] else . end
elif .n < 1000
then .t += small[(.n/100)floor] + " hundred"
 .s = .n % 100
 if .s > 0 then .t += " " + (.ssay) else . end
else .sx = ""
 .i = 0
 until(.n == 0;
.p = .n % 1000
 .n = (.n / 1000 floor)
 if (.p > 0)
then .ix = (.psay) + illions[.i]
 if (.sx != "") then .ix += " " + .sx else . end
 .sx = .ix
else .
end
 .i += 1 )
 .t += .sx
end
 .t;
def capitalize:
.[:1] as $x
 ($x  ascii_upcase) as $X
 if $x == $X then . else $X + .[1:] end;
def fourIsMagic:
{n: ., s: (say  capitalize)}
 .t = .s
 until(.n == 4;
.n = (.slength)
 .s = (.n  say)
 .t += " is " + .s + ", " + .s )
 .t + " is magic." ;
(0, 4, 6, 11, 13, 75, 100, 337, 164, 9007199254740991)
 fourIsMagic
Invocation: jq rn f fourismagic.jq
 Output:
As for Wren.
Julia
# The num2text routines are from the "Number names" task, updated for Julia 1.0
const stext = ["one", "two", "three", "four", "five",
"six", "seven", "eight", "nine"]
const teentext = ["eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen",
"eighteen", "nineteen"]
const tenstext = ["ten", "twenty", "thirty", "forty", "fifty",
"sixty", "seventy", "eighty", "ninety"]
const ordstext = ["million", "billion", "trillion",
"quadrillion", "quintillion", "sextillion",
"septillion", "octillion", "nonillion",
"decillion", "undecillion", "duodecillion",
"tredecillion", "quattuordecillion", "quindecillion",
"sexdecillion", "septendecillion", "octodecillion",
"novemdecillion", "vigintillion"]
function normalize_digits!(a)
while 0 < length(a) && a[end] == 0
pop!(a)
end
return length(a)
end
function digits2text!(d, use_short_scale=true)
ndig = normalize_digits!(d)
0 < ndig  return ""
if ndig < 7
s = ""
if 3 < ndig
t = digits2text!(d[1:3])
s = digits2text!(d[4:end])*" thousand"
0 < length(t)  return s
if occursin("and", t)
return s*" "*t
else
return s*" and "*t
end
end
if ndig == 3
s *= stext[pop!(d)]*" hundred"
ndig = normalize_digits!(d)
0 < ndig  return s
s *= " and "
end
1 < ndig  return s*stext[pop!(d)]
j, i = d
j != 0  return s*tenstext[i]
i != 1  return s*teentext[j]
return s*tenstext[i]*""*stext[j]
end
s = digits2text!(d[1:6])
d = d[7:end]
dgrp = use_short_scale ? 3 : 6
ord = 0
while(dgrp < length(d))
ord += 1
t = digits2text!(d[1:dgrp])
d = d[(dgrp+1):end]
0 < length(t)  continue
t = t*" "*ordstext[ord]
if length(s) == 0
s = t
else
s = t*" "*s
end
end
ord += 1
t = digits2text!(d)*" "*ordstext[ord]
0 < length(s)  return t
return t*" "*s
end
function num2text(n, use_short_scale=true)
1 < n  return "minus "*num2text(n, use_short_scale)
0 < n  return "zero"
toobig = use_short_scale ? big(10)^66 : big(10)^126
n < toobig  return "too big to say"
return digits2text!(digits(n, base=10), use_short_scale)
end
function magic(n)
str = uppercasefirst(num2text(n))
n = length(str)
while true
numtext = num2text(n)
str *= " is " * numtext
if numtext == "four"
break
end
str *= ", " * numtext
n = length(numtext)
end
println(str[1:7] == "Four is" ? "Four is magic." : "$str, four is magic.")
end
for n in [0, 4, 6, 11, 13, 75, 337, 164, 9_876_543_209]
magic(n)
end
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Three hundred and thirtyseven is thirty, thirty is six, six is three, three is five, five is four, four is magic. Minus one hundred and sixtyfour is thirtytwo, thirtytwo is ten, ten is three, three is five, five is four, four is magic. Nine billion eight hundred and seventysix million five hundred and fortythree thousand two hundred and nine is one hundred and nine, one hundred and nine is twenty, twenty is six, six is three, three is five, five is four, four is magic.
Kotlin
This uses the code I wrote for the Number names task, appropriately adjusted to deal with this task. Input is limited to signed 64 bit integers as Kotlin doesn't currently support unsigned types.
// version 1.1.43
val names = mapOf(
1 to "one",
2 to "two",
3 to "three",
4 to "four",
5 to "five",
6 to "six",
7 to "seven",
8 to "eight",
9 to "nine",
10 to "ten",
11 to "eleven",
12 to "twelve",
13 to "thirteen",
14 to "fourteen",
15 to "fifteen",
16 to "sixteen",
17 to "seventeen",
18 to "eighteen",
19 to "nineteen",
20 to "twenty",
30 to "thirty",
40 to "forty",
50 to "fifty",
60 to "sixty",
70 to "seventy",
80 to "eighty",
90 to "ninety"
)
val bigNames = mapOf(
1_000L to "thousand",
1_000_000L to "million",
1_000_000_000L to "billion",
1_000_000_000_000L to "trillion",
1_000_000_000_000_000L to "quadrillion",
1_000_000_000_000_000_000L to "quintillion"
)
fun numToText(n: Long): String {
if (n == 0L) return "zero"
val neg = n < 0L
val maxNeg = n == Long.MIN_VALUE
var nn = if (maxNeg) (n + 1) else if (neg) n else n
val digits3 = IntArray(7)
for (i in 0..6) { // split number into groups of 3 digits from the right
digits3[i] = (nn % 1000).toInt()
nn /= 1000
}
fun threeDigitsToText(number: Int) : String {
val sb = StringBuilder()
if (number == 0) return ""
val hundreds = number / 100
val remainder = number % 100
if (hundreds > 0) {
sb.append(names[hundreds], " hundred")
if (remainder > 0) sb.append(" ")
}
if (remainder > 0) {
val tens = remainder / 10
val units = remainder % 10
if (tens > 1) {
sb.append(names[tens * 10])
if (units > 0) sb.append("", names[units])
}
else sb.append(names[remainder])
}
return sb.toString()
}
val strings = Array<String>(7) { threeDigitsToText(digits3[it]) }
var text = strings[0]
var big = 1000L
for (i in 1..6) {
if (digits3[i] > 0) {
var text2 = strings[i] + " " + bigNames[big]
if (text.length > 0) text2 += " "
text = text2 + text
}
big *= 1000
}
if (maxNeg) text = text.dropLast(5) + "eight"
if (neg) text = "negative " + text
return text
}
fun fourIsMagic(n: Long): String {
if (n == 4L) return "Four is magic."
var text = numToText(n).capitalize()
val sb = StringBuilder()
while (true) {
val len = text.length.toLong()
if (len == 4L) return sb.append("$text is four, four is magic.").toString()
val text2 = numToText(len)
sb.append("$text is $text2, ")
text = text2
}
}
fun main(args: Array<String>) {
val la = longArrayOf(0, 4, 6, 11, 13, 75, 100, 337, 164, 9_223_372_036_854_775_807L)
for (i in la) {
println(fourIsMagic(i))
println()
}
}
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine quintillion two hundred twentythree quadrillion three hundred seventytwo trillion thirtysix billion eight hundred fiftyfour million seven hundred seventyfive thousand eight hundred seven is one hundred ninetysix, one hundred ninetysix is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic.
Lua
 Four is magic, in Lua, 6/16/2020 db
local oneslist = { [0]="", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }
local teenlist = { [0]="ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" }
local tenslist = { [0]="", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }
local lionlist = { [0]="", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion", "septillion", "octillion", "nonillion", "decillion" }
local abs, floor = math.abs, math.floor
local function numname(num)
if (num == 0) then return "zero" end
local absnum, lion, result = abs(num), 0, ""
local function dashed(s) return s=="" and s or ""..s end
local function spaced(s) return s=="" and s or " "..s end
while (absnum > 0) do
local word, ones, tens, huns = "", absnum%10, floor(absnum/10)%10, floor(absnum/100)%10
if (tens==0) then word = oneslist[ones]
elseif (tens==1) then word = teenlist[ones]
else word = tenslist[tens] .. dashed(oneslist[ones]) end
if (huns > 0) then word = oneslist[huns] .. " hundred" .. spaced(word) end
if (word ~= "") then result = word .. spaced(lionlist[lion]) .. spaced(result) end
absnum = floor(absnum / 1000)
lion = lion + 1
end
if (num < 0) then result = "negative " .. result end
return result
end
local function fourismagic(num)
local function fim(num)
local name = numname(num)
if (num == 4) then
return name .. " is magic."
else
local what = numname(#name)
return name .. " is " .. what .. ", " .. fim(#name)
end
end
local result = fim(num):gsub("^%l", string.upper)
return result
end
local numbers = { 21,1, 0,1,2,3,4,5,6,7,8,9, 12,34,123,456,1024,1234,12345,123456,1010101 }
for _, num in ipairs(numbers) do
print(num, fourismagic(num))
end
 Output:
21 Negative twentyone is nineteen, nineteen is eight, eight is five, five is four, four is magic. 1 Negative one is twelve, twelve is six, six is three, three is five, five is four, four is magic. 0 Zero is four, four is magic. 1 One is three, three is five, five is four, four is magic. 2 Two is three, three is five, five is four, four is magic. 3 Three is five, five is four, four is magic. 4 Four is magic. 5 Five is four, four is magic. 6 Six is three, three is five, five is four, four is magic. 7 Seven is five, five is four, four is magic. 8 Eight is five, five is four, four is magic. 9 Nine is four, four is magic. 12 Twelve is six, six is three, three is five, five is four, four is magic. 34 Thirtyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic. 123 One hundred twentythree is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic. 456 Four hundred fiftysix is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic. 1024 One thousand twentyfour is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic. 1234 One thousand two hundred thirtyfour is thirtysix, thirtysix is ten, ten is three, three is five, five is four, four is magic. 12345 Twelve thousand three hundred fortyfive is forty, forty is five, five is four, four is magic. 123456 One hundred twentythree thousand four hundred fiftysix is fiftysix, fiftysix is nine, nine is four, four is magic. 1010101 One million ten thousand one hundred one is forty, forty is five, five is four, four is magic.
Mathematica/Wolfram Language
Define a simple function which generates the output, using FixedPointList to iterate until a magic number is reached.
magic[num_] := Capitalize[ StringRiffle[ Partition[
FixedPointList[IntegerName[StringLength[#], "Cardinal"] &, IntegerName[num, "Cardinal"]],
2, 1] /. {n_, n_} :> {n, "magic"}, ", ", " is "] <> "."]
Call the function a few times to show the expected output:
 Output:
In[1]:= magic[0] Out[1]= "Zero is four, four is magic." In[2]:= magic[1] Out[2]= "One is three, three is five, five is four, four is magic." In[3]:= magic[10] Out[3]= "Ten is three, three is five, five is four, four is magic." In[4]:= magic[999999] Out[4]= "Nine hundred ninetynine thousand nine hundred ninetynine is fiftyeight, fiftyeight is eleven, eleven is six, six is three, three is five, five is four, four is magic." In[5]:= magic[RandomInteger[10^6]] Out[5]= "One hundred ninetyfour thousand sixtyfour is fortythree, fortythree is eleven, eleven is six, six is three, three is five, five is four, four is magic."
Nim
import strutils
const
Small = ["zero", "one", "two", "three", "four",
"five", "six", "seven", "eight", "nine",
"ten", "eleven", "twelve", "thirteen", "fourteen",
"fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
Tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
Illions = ["", " thousand", " million", " billion", " trillion", " quadrillion", " quintillion"]
#
func say(n: int64): string =
var n = n
if n < 0:
result = "negative "
n = n
if n < 20:
result &= Small[n]
elif n < 100:
result &= Tens[n div 10]
let m = n mod 10
if m != 0: result &= '' & Small[m]
elif n < 1000:
result &= Small[n div 100] & " hundred"
let m = n mod 100
if m != 0: result &= ' ' & m.say()
else:
# Work from right to left.
var sx = ""
var i = 0
while n > 0:
let m = n mod 1000
n = n div 1000
if m != 0:
var ix = m.say() & Illions[i]
if sx.len > 0: ix &= " " & sx
sx = ix
inc i
result &= sx
#
func fourIsMagic(n: int64): string =
var n = n
var s = n.say().capitalizeAscii()
result = s
while n != 4:
n = s.len.int64
s = n.say()
result &= " is " & s & ", " & s
result &= " is magic."
#———————————————————————————————————————————————————————————————————————————————————————————————————
for n in [int64 0, 4, 6, 11, 13, 75, 100, 337, 164, int64.high]:
echo fourIsMagic(n)
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine quintillion two hundred twentythree quadrillion three hundred seventytwo trillion thirtysix billion eight hundred fiftyfour million seven hundred seventyfive thousand eight hundred seven is one hundred ninetysix, one hundred ninetysix is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic.
Perl
use Lingua::EN::Numbers qw(num2en);
sub cardinal {
my($n) = @_;
(my $en = num2en($n)) =~ s/\ and,//g;
$en;
}
sub magic {
my($int) = @_;
my $str;
while () {
$str .= cardinal($int) . " is ";
if ($int == 4) {
$str .= "magic.\n";
last
} else {
$int = length cardinal($int);
$str .= cardinal($int) . ", ";
}
}
ucfirst $str;
}
print magic($_) for 0, 4, 6, 11, 13, 75, 337, 164, 9_876_543_209;
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine billion eight hundred seventysix million five hundred fortythree thousand two hundred nine is ninetyseven, ninetyseven is twelve, twelve is six, six is three, three is five, five is four, four is magic.
Phix
Note that on 32bit Phix integers/atoms are only accurate to 9,007,199,254,740,992 (a hardware limit of 64bit floating point registers) and on 64bit the limit is 18,446,744,073,709,551,616 (ditto 80bit floating points) so if you need more than that this will need to be reworked to use gmp or similar.
with javascript_semantics <adapted from demo\rosetta\number_names.exw, which alas outputs ",", "and", uses "minus" instead of "negative", etc...> constant twenties = {"zero","one","two","three","four","five","six","seven","eight","nine","ten", "eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"}, decades = {"twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"} function hundred(integer n) if n<20 then return twenties[mod(n,20)+1] elsif mod(n,10)=0 then return decades[mod(floor(n/10),10)1] end if return decades[mod(floor(n/10),10)1] & '' & twenties[mod(n,10)+1] end function function thousand(integer n) if n<100 then return hundred(n) elsif mod(n,100)=0 then return twenties[mod(floor(n/100),20)+1]&" hundred" end if return twenties[mod(floor(n/100),20)+1] & " hundred " & hundred(mod(n,100)) end function constant orders = {{power(10,12),"trillion"}, {power(10,9),"billion"}, {power(10,6),"million"}, {power(10,3),"thousand"}} function triplet(integer n) string res = "" for i=1 to length(orders) do {atom order, string name} = orders[i] atom high = floor(n/order), low = mod(n,order) if high!=0 then res &= thousand(high)&' '&name end if n = low if low=0 then exit end if if length(res) and high!=0 then res &= " " end if end for if n!=0 or res="" then res &= thousand(floor(n)) end if return res end function function spell(integer n) string res = "" if n<0 then res = "negative " n = n end if res &= triplet(n) return res end function </adapted from number_names.exw> function fourIsMagic(atom n) string s = spell(n) s[1] = upper(s[1]) string t = s while n!=4 do n = length(s) s = spell(n) t &= " is " & s & ", " & s end while t &= " is magic.\n" return t end function constant tests = {7, 1, 0, 1, 2, 3, 4, 23, 1e9, 20140, 100, 130, 151, 999999} for i=1 to length(tests) do puts(1,fourIsMagic(tests[i])) end for
 Output:
Negative seven is fourteen, fourteen is eight, eight is five, five is four, four is magic. Negative one is twelve, twelve is six, six is three, three is five, five is four, four is magic. Zero is four, four is magic. One is three, three is five, five is four, four is magic. Two is three, three is five, five is four, four is magic. Three is five, five is four, four is magic. Four is magic. Twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. One billion is eleven, eleven is six, six is three, three is five, five is four, four is magic. Twenty thousand one hundred forty is thirtythree, thirtythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. One hundred thirty is eighteen, eighteen is eight, eight is five, five is four, four is magic. One hundred fiftyone is twentyone, twentyone is ten, ten is three, three is five, five is four, four is magic. Nine hundred ninetynine thousand nine hundred ninetynine is fiftyeight, fiftyeight is eleven, eleven is six, six is three, three is five, five is four, four is magic.
Python
Python 3 version. Should work for integers up to at least 10^3003. It can be extended easily to arbitrary integers by adding to the numbers dict.
import random
from collections import OrderedDict
numbers = { # taken from https://en.wikipedia.org/wiki/Names_of_large_numbers#cite_refa_143
1: 'one',
2: 'two',
3: 'three',
4: 'four',
5: 'five',
6: 'six',
7: 'seven',
8: 'eight',
9: 'nine',
10: 'ten',
11: 'eleven',
12: 'twelve',
13: 'thirteen',
14: 'fourteen',
15: 'fifteen',
16: 'sixteen',
17: 'seventeen',
18: 'eighteen',
19: 'nineteen',
20: 'twenty',
30: 'thirty',
40: 'forty',
50: 'fifty',
60: 'sixty',
70: 'seventy',
80: 'eighty',
90: 'ninety',
100: 'hundred',
1000: 'thousand',
10 ** 6: 'million',
10 ** 9: 'billion',
10 ** 12: 'trillion',
10 ** 15: 'quadrillion',
10 ** 18: 'quintillion',
10 ** 21: 'sextillion',
10 ** 24: 'septillion',
10 ** 27: 'octillion',
10 ** 30: 'nonillion',
10 ** 33: 'decillion',
10 ** 36: 'undecillion',
10 ** 39: 'duodecillion',
10 ** 42: 'tredecillion',
10 ** 45: 'quattuordecillion',
10 ** 48: 'quinquadecillion',
10 ** 51: 'sedecillion',
10 ** 54: 'septendecillion',
10 ** 57: 'octodecillion',
10 ** 60: 'novendecillion',
10 ** 63: 'vigintillion',
10 ** 66: 'unvigintillion',
10 ** 69: 'duovigintillion',
10 ** 72: 'tresvigintillion',
10 ** 75: 'quattuorvigintillion',
10 ** 78: 'quinquavigintillion',
10 ** 81: 'sesvigintillion',
10 ** 84: 'septemvigintillion',
10 ** 87: 'octovigintillion',
10 ** 90: 'novemvigintillion',
10 ** 93: 'trigintillion',
10 ** 96: 'untrigintillion',
10 ** 99: 'duotrigintillion',
10 ** 102: 'trestrigintillion',
10 ** 105: 'quattuortrigintillion',
10 ** 108: 'quinquatrigintillion',
10 ** 111: 'sestrigintillion',
10 ** 114: 'septentrigintillion',
10 ** 117: 'octotrigintillion',
10 ** 120: 'noventrigintillion',
10 ** 123: 'quadragintillion',
10 ** 153: 'quinquagintillion',
10 ** 183: 'sexagintillion',
10 ** 213: 'septuagintillion',
10 ** 243: 'octogintillion',
10 ** 273: 'nonagintillion',
10 ** 303: 'centillion',
10 ** 306: 'uncentillion',
10 ** 309: 'duocentillion',
10 ** 312: 'trescentillion',
10 ** 333: 'decicentillion',
10 ** 336: 'undecicentillion',
10 ** 363: 'viginticentillion',
10 ** 366: 'unviginticentillion',
10 ** 393: 'trigintacentillion',
10 ** 423: 'quadragintacentillion',
10 ** 453: 'quinquagintacentillion',
10 ** 483: 'sexagintacentillion',
10 ** 513: 'septuagintacentillion',
10 ** 543: 'octogintacentillion',
10 ** 573: 'nonagintacentillion',
10 ** 603: 'ducentillion',
10 ** 903: 'trecentillion',
10 ** 1203: 'quadringentillion',
10 ** 1503: 'quingentillion',
10 ** 1803: 'sescentillion',
10 ** 2103: 'septingentillion',
10 ** 2403: 'octingentillion',
10 ** 2703: 'nongentillion',
10 ** 3003: 'millinillion'
}
numbers = OrderedDict(sorted(numbers.items(), key=lambda t: t[0], reverse=True))
def string_representation(i: int) > str:
"""
Return the english string representation of an integer
"""
if i == 0:
return 'zero'
words = ['negative'] if i < 0 else []
working_copy = abs(i)
for key, value in numbers.items():
if key <= working_copy:
times = int(working_copy / key)
if key >= 100:
words.append(string_representation(times))
words.append(value)
working_copy = times * key
if working_copy == 0:
break
return ' '.join(words)
def next_phrase(i: int):
"""
Generate all the phrases
"""
while not i == 4: # Generate phrases until four is reached
str_i = string_representation(i)
len_i = len(str_i)
yield str_i, 'is', string_representation(len_i)
i = len_i
# the last phrase
yield string_representation(i), 'is', 'magic'
def magic(i: int) > str:
phrases = []
for phrase in next_phrase(i):
phrases.append(' '.join(phrase))
return f'{", ".join(phrases)}.'.capitalize()
if __name__ == '__main__':
for j in (random.randint(0, 10 ** 3) for i in range(5)):
print(j, ':\n', magic(j), '\n')
for j in (random.randint(10 ** 24, 10 ** 24) for i in range(2)):
print(j, ':\n', magic(j), '\n')
 Output:
475 : Four hundred seventy five is twenty five, twenty five is eleven, eleven is six, six is three, three is five, five is four, four is magic. 968 : Nine hundred sixty eight is twenty four, twenty four is eleven, eleven is six, six is three, three is five, five is four, four is magic. 304 : Three hundred four is eighteen, eighteen is eight, eight is five, five is four, four is magic. 544 : Five hundred forty four is twenty three, twenty three is twelve, twelve is six, six is three, three is five, five is four, four is magic. 394 : Three hundred ninety four is twenty five, twenty five is eleven, eleven is six, six is three, three is five, five is four, four is magic. 49587779907680717664396 : Negative forty nine sextillion five hundred eighty seven quintillion seven hundred seventy nine quadrillion nine hundred seven trillion six hundred eighty billion seven hundred seventeen million six hundred sixty four thousand three hundred ninety six is two hundred fifty one, two hundred fifty one is twenty one, twenty one is ten, ten is three, three is five, five is four, four is magic. 874143425855745733896030 : Eight hundred seventy four sextillion one hundred forty three quintillion four hundred twenty five quadrillion eight hundred fifty five trillion seven hundred forty five billion seven hundred thirty three million eight hundred ninety six thousand thirty is two hundred fifty three, two hundred fifty three is twenty three, twenty three is twelve, twelve is six, six is three, three is five, five is four, four is magic.
q
C:``one`two`three`four`five`six`seven`eight`nine`ten,
`eleven`twelve`thirteen`fourteen`fifteen`sixteen`seventeen`eighteen`nineteen / cardinal numbers <20
T:``ten`twenty`thirty`forty`fifty`sixty`seventy`eighty`ninety / tens
M:``thousand`million`billion`trillion`quadrillion`quintillion`sextillion`septillion / magnitudes
st:{ / stringify <1000
$[x<20; C x;
x<100; (T;C)@'10 vs x;
{C[y],`hundred,$[z=0;`;x z]}[.z.s] . 100 vs x] }
s:{$[x=0; "zero"; {" "sv string except[;`]raze x{$[x~`;x;x,y]}'M reverse til count x} st each 1000 vs x]} / stringify
fim:{@[;0;upper],[;"four is magic.\n"] raze 1_{y," is ",x,", "}prior s each(count s@)\[x]} / four is magic
1 raze fim each 0 4 8 16 25 89 365 2586 25865 369854 40000000001; / tests
 Output:
Zero is four, four is magic. Four is magic. Eight is five, five is four, four is magic. Sixteen is seven, seven is five, five is four, four is magic. Twenty five is eleven, eleven is six, six is three, three is five, five is four, four is magic. Eighty nine is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred sixty five is twenty four, twenty four is eleven, eleven is six, six is three, three is five, five is four, four is magic. Two thousand five hundred eighty six is thirty six, thirty six is ten, ten is three, three is five, five is four, four is magic. Twenty five thousand eight hundred sixty five is forty five, forty five is ten, ten is three, three is five, five is four, four is magic. Three hundred sixty nine thousand eight hundred fifty four is fifty eight, fifty eight is eleven, eleven is six, six is three, three is five, five is four, four is magic. Forty billion one is seventeen, seventeen is nine, nine is four, four is magic.
Comment
In q the same syntax applies a function to an argument or a list to its indexes. A consequence is that, with the Converge iterator \
the lengths alone form a finitestate machine which can generate the convergence.
q)show sl:count each string C / string lengths
0 3 3 5 4 4 3 5 5 4 3 6 6 8 8 7 7 9 8 8
q)sl\[18]
18 8 5 4
q)sl\[19]
19 8 5 4
R
# provided by neonira
integerToText < function(value_n_1) {
english_words_for_numbers < list(
simples = c(
'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine',
'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen'
),
tens = c('twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'),
powers = c(
'hundred' = 100,
'thousand' = 1000,
'million' = 1000000,
'billion' = 1000000000,
'trillion' = 1000000000000,
'quadrillion' = 1000000000000000,
'quintillion' = 1000000000000000000
)
)
buildResult < function(x_s) {
if (value_n_1 < 0) return(paste('minus', x_s))
x_s
}
withDash < function(a_s, b_s) paste(a_s, b_s, sep = '')
val < abs(value_n_1)
if (val < 20L) return(buildResult(english_words_for_numbers$simples[val + 1L]))
if (val < 100L) {
tens < val %/% 10L  1L
reminder < val %% 10L
if (reminder == 0L) return(buildResult(english_words_for_numbers$ten[tens]))
return(buildResult(withDash(english_words_for_numbers$ten[tens], Recall(reminder))))
}
index < l < length(english_words_for_numbers$powers)
for(power in seq_len(l)) {
if (val < english_words_for_numbers$powers[power]) {
index < power  1L
break
}
}
f < Recall(val %/% english_words_for_numbers$powers[index])
reminder < val %% english_words_for_numbers$powers[index]
if (reminder == 0L) return(buildResult(paste(f, names(english_words_for_numbers$powers)[index])))
buildResult(paste(f, names(english_words_for_numbers$powers)[index], Recall(reminder)))
}
magic < function(value_n_1) {
text < vector('character')
while(TRUE) {
r < integerToText(value_n_1)
nc < nchar(r)
complement < ifelse(value_n_1 == 4L, "is magic", paste("is", integerToText(nc)))
text[length(text) + 1L] < paste(r, complement)
if (value_n_1 == 4L) break
value_n_1 < nc
}
buildSentence < function(x_s) paste0(toupper(substr(x_s, 1L, 1L)), substring(x_s, 2L), '.')
buildSentence(paste(text, collapse = ', '))
}
 Output:
0 "Zero is four, four is magic." 199 "One hundred ninetynine is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic." 4567 "Four thousand five hundred sixtyseven is thirtyeight, thirtyeight is twelve, twelve is six, six is three, three is five, five is four, four is magic."
Racket
#lang racket
(require rackunit)
(define smalls
(map symbol>string
'(zero one two three four five six seven eight nine ten eleven twelve
thirteen fourteen fifteen sixteen seventeen eighteen nineteen)))
(define tens
(map symbol>string
'(zero ten twenty thirty forty fifty sixty seventy eighty ninety)))
(define larges
(map symbol>string
'(thousand million billion trillion quadrillion quintillion sextillion
septillion octillion nonillion decillion undecillion duodecillion
tredecillion quattuordecillion quindecillion sexdecillion
septendecillion octodecillion novemdecillion vigintillion)))
(define (number>words n)
(define (step div suffix separator [subformat number>words])
(definevalues [q r] (quotient/remainder n div))
(define S (if suffix (~a (subformat q) " " suffix) (subformat q)))
(if (zero? r) S (~a S separator (number>words r))))
(cond [(< n 0) (~a "negative " (number>words ( n)))]
[(< n 20) (listref smalls n)]
[(< n 100) (step 10 #f "" (curry listref tens))]
[(< n 1000) (step 100 "hundred" " ")]
[else (let loop ([N 1000000] [D 1000] [unit larges])
(cond [(null? unit)
(error 'number>words "number too big: ~e" n)]
[(< n N) (step D (car unit) " ")]
[else (loop (* 1000 N) (* 1000 D) (cdr unit))]))]))
(define (firstcap s)
(~a (stringupcase (substring s 0 1)) (substring s 1)))
(define (magic word [acc null])
(if (equal? word "four")
(stringjoin (reverse (cons "four is magic." acc)) ", \n")
(let* ([wordlen (stringlength word)]
[words (number>words wordlen)])
(magic words
(cons (stringappend word " is " words) acc)))))
(define (numbermagic n)
(firstcap (magic (number>words n))))
(for ([n (append (range 11)
'(10 23 172 20140 100 130 999999 876000000
874143425855745733896030))])
(displayln n)
(displayln (numbermagic n))
(newline))
 Output:
0 Zero is four, four is magic. 1 One is three, three is five, five is four, four is magic. 2 Two is three, three is five, five is four, four is magic. 3 Three is five, five is four, four is magic. 4 Four is magic. 5 Five is four, four is magic. 6 Six is three, three is five, five is four, four is magic. 7 Seven is five, five is four, four is magic. 8 Eight is five, five is four, four is magic. 9 Nine is four, four is magic. 10 Ten is three, three is five, five is four, four is magic. 10 Negative ten is twelve, twelve is six, six is three, three is five, five is four, four is magic. 23 Twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. 172 One hundred seventytwo is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. 20140 Twenty thousand one hundred forty is thirtythree, thirtythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. 100 One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. 130 One hundred thirty is eighteen, eighteen is eight, eight is five, five is four, four is magic. 999999 Nine hundred ninetynine thousand nine hundred ninetynine is fiftyeight, fiftyeight is eleven, eleven is six, six is three, three is five, five is four, four is magic. 876000000 Eight hundred seventysix million is thirtythree, thirtythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. 874143425855745733896030 Eight hundred seventyfour sextillion one hundred fortythree quintillion four hundred twentyfive quadrillion eight hundred fiftyfive trillion seven hundred fortyfive billion seven hundred thirtythree million eight hundred ninetysix thousand thirty is two hundred fiftythree, two hundred fiftythree is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic.
Raku
(formerly Perl 6)
Lingua::EN::Numbers module available from the Raku ecosystem.
use Lingua::EN::Numbers; # Version 2.4.0 or higher
sub card ($n) { cardinal($n).subst(/','/, '', :g) }
sub magic (Int $int is copy) {
my $string;
loop {
$string ~= "{ card($int) } is ";
if $int = ($int == 4) ?? 0 !! card($int).chars {
$string ~= "{ card($int) }, "
} else {
$string ~= "magic.\n";
last
}
}
$string.tc
}
.&magic.say for 0, 4, 6, 11, 13, 75, 337, 164, 9876543209, 2**256;
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine billion eight hundred seventysix million five hundred fortythree thousand two hundred nine is ninetyseven, ninetyseven is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred fifteen quattuorvigintillion seven hundred ninetytwo trevigintillion eightynine duovigintillion two hundred thirtyseven unvigintillion three hundred sixteen vigintillion one hundred ninetyfive novemdecillion four hundred twentythree octodecillion five hundred seventy septendecillion nine hundred eightyfive sexdecillion eight quindecillion six hundred eightyseven quattuordecillion nine hundred seven tredecillion eight hundred fiftythree duodecillion two hundred sixtynine undecillion nine hundred eightyfour decillion six hundred sixtyfive nonillion six hundred forty octillion five hundred sixtyfour septillion thirtynine sextillion four hundred fiftyseven quintillion five hundred eightyfour quadrillion seven trillion nine hundred thirteen billion one hundred twentynine million six hundred thirtynine thousand nine hundred thirtysix is eight hundred sixtynine, eight hundred sixtynine is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic.
REXX
The numbers used for the default were taken from the Kotlin example.
Numbers are limited to 3,003 decimal digits, the maximum number that the $SPELL# REXX program will handle.
/*REXX pgm converts a # to English into the phrase: a is b, b is c, ... four is magic. */
numeric digits 3003 /*be able to handle gihugic numbers. */
parse arg x /*obtain optional numbers from the C.L.*/
if x='' then x= 164 0 4 6 11 13 75 100 337 9223372036854775807 /*use these defaults?*/
@.= . /*stemmed array used for memoization. */
do j=1 for words(x) /*process each of the numbers in list. */
say 4_is( word(x, j) ) /*display phrase that'll be returned. */
say /*display a blank line between outputs.*/
end /*j*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
4_is: procedure expose @.; parse arg #,,$ /*obtain the start number.*/
if #\==4 then do until L==4 /*Not 4? Process number.*/
@.#= $spell#(# 'quiet minus negative') /*spell number in English.*/
#= @.#; L= length(#) /*get the length of spelt#*/
if @.L==. then @.L= $spell#(L 'quiet') /*¬spelt before? Spell it.*/
$= $ # "is" @.L',' /*add phrase to the answer*/
#= L /*use the new number, ··· */
end /*until*/ /* ··· which will be spelt*/
$= strip($ 'four is magic.') /*finish the sentence with the finale. */
parse var $ first 2 other; upper first /*capitalize the first letter of output*/
return first  other /*return the sentence to the invoker. */
The $SPELL#.REX routine can be found here ───► $SPELL#.REX.
 output when using the default inputs:
Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Nine quintillion two hundred twentythree quadrillion three hundred seventytwo trillion thirtysix billion eight hundred fiftyfour million seven hundred seventyfive thousand eight hundred seven is one hundred ninetysix, one hundred ninetysix is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic.
Ring
/* Checking numbers from 0 to 10 */
for c = 0 to 10
See checkmagic(c) + NL
next
/* The functions */
Func CheckMagic numb
CardinalN = ""
Result = ""
if isnumber(numb) = false or numb < 0 or numb > 999_999_999_999_999
Return "ERROR: Number entered is incorrect"
ok
if numb = 4
Result = "Four is magic."
else
While True
if CardinalN = "four"
Result += "four is magic"
exit
ok
strnumb = StringNumber(numb)
CardinalN = StringNumber(len(strnumb))
Result += strnumb + " is " + CardinalN + ", "
numb = len(strnumb)
End
Result += "."
Result = upper(Result[1]) + Right(Result, len(Result) 1)
ok
Return Result
Func StringNumber cnumb
NumStr = [:n0 = "zero", :n1 = "one", :n2 = "two", :n3 = "three", :n4 = "four", :n5 = "five",
:n6 = "six", :n7 = "seven", :n8 = "eight", :n9 = "nine", :n10 = "ten",
:n11 = "eleven", :n12 = "twelve", :n13 = "thirteen", :n14 = "fourteen", :n15 = "fifteen",
:n16 = "sixteen", :n17 = "seventeen", :n18 = "eighteen", :n19 = "nineteen",
:n20 = "twenty", :n30 = "thirty", :n40 = "fourty", :n50 = "fifty", :n60 = "sixty", :n70 = "seventy", :n80 = "eighty", :n90 = "ninety"]
numLev = [:l1 = "", :l2 = "thousand", :l3 = "million", :l4 = "billion", :l5 = "trillion"]
Result = ""
if cnumb > 0
decimals(0)
snumb = string((cnumb))
lnumb = [""]
fl = floor(len(snumb) / 3)
if fl > 0
for i = 1 to fl
lnumb[i] = right(snumb, 3)
snumb = left(snumb, len(snumb) 3)
lnumb + ""
next
if (len(snumb) % 3) > 0
lnumb[len(lnumb)] = snumb
else
del(lnumb, len(lnumb))
ok
else
lnumb[1] = snumb
ok
for l = len(lnumb) to 1 step 1
bnumb = lnumb[l]
bResult = ""
if number(bnumb) != 0
for n = len(bnumb) to 1 step 1
if (len(bnumb) = 3 and n = 2) or (len(bnumb) = 2 and n = 1)
if number(bnumb[n]) > 1
eval("bResult = NumStr[:n" + bnumb[n] + "0] + ' ' + bResult")
elseif number(bnumb[n]) = 1
eval("bResult = NumStr[:n" + bnumb[n] + bnumb[n+1] + "] + ' ' + bResult")
ok
else
if len(bnumb) = 3 and n = 1 and number(bnumb[1]) > 0
if trim(bResult) != ""
bResult = " " + bResult
ok
if number(bnumb[1]) > 1
bResult = "hundreds" + bResult
else
bResult = "hundred" + bResult
ok
if left(trim(bResult), 7) = "hundred"
bResult = bResult + " "
ok
ok
if (len(bnumb) = 3 and n = 1 and number(bnumb[1]) = 0) OR (len(bnumb) = n and number(bnumb[n]) = 0) OR (len(bnumb) = 3 and number(bnumb[2]) = 1) OR (len(bnumb) = 2 and number(bnumb[1]) = 1)
loop
ok
eval("bResult = NumStr[:n" + bnumb[n] + "] + ' ' + bResult")
ok
next
Result = Result + bResult
if l > 1
if number(bnumb) > 1
eval("Result = Result + numLev[:l" + l + "] + 's ' ")
else
eval("Result = Result + numLev[:l" + l + "] + ' ' ")
ok
ok
ok
next
else
Result = Result + NumStr[:n0]
ok
Return trim(Result)
Output:
Zero is four, four is magic. One is three, three is five, five is four, four is magic. Two is three, three is five, five is four, four is magic. Three is five, five is four, four is magic. Four is magic. Five is four, four is magic. Six is three, three is five, five is four, four is magic. Seven is five, five is four, four is magic. Eight is five, five is four, four is magic. Nine is four, four is magic. Ten is three, three is five, five is four, four is magic.
Ruby
Using a 'refinement' to the Integer class, a way to a way to extend a class locally.
module NumberToWord
NUMBERS = { # taken from https://en.wikipedia.org/wiki/Names_of_large_numbers#cite_refa_143
1 => 'one',
2 => 'two',
3 => 'three',
4 => 'four',
5 => 'five',
6 => 'six',
7 => 'seven',
8 => 'eight',
9 => 'nine',
10 => 'ten',
11 => 'eleven',
12 => 'twelve',
13 => 'thirteen',
14 => 'fourteen',
15 => 'fifteen',
16 => 'sixteen',
17 => 'seventeen',
18 => 'eighteen',
19 => 'nineteen',
20 => 'twenty',
30 => 'thirty',
40 => 'forty',
50 => 'fifty',
60 => 'sixty',
70 => 'seventy',
80 => 'eighty',
90 => 'ninety',
100 => 'hundred',
1000 => 'thousand',
10 ** 6 => 'million',
10 ** 9 => 'billion',
10 ** 12 => 'trillion',
10 ** 15 => 'quadrillion',
10 ** 18 => 'quintillion',
10 ** 21 => 'sextillion',
10 ** 24 => 'septillion',
10 ** 27 => 'octillion',
10 ** 30 => 'nonillion',
10 ** 33 => 'decillion'}.reverse_each.to_h
refine Integer do
def to_english
return 'zero' if i.zero?
words = self < 0 ? ['negative'] : []
i = self.abs
NUMBERS.each do k, v
if k <= i then
times = i/k
words << times.to_english if k >= 100
words << v
i = times * k
end
return words.join(" ") if i.zero?
end
end
end
end
using NumberToWord
def magic4(n)
words = []
until n == 4
s = n.to_english
n = s.size
words << "#{s} is #{n.to_english}"
end
words << "four is magic."
words.join(", ").capitalize
end
[0, 4, 6, 11, 13, 75, 337, 164, 9_876_543_209].each{n puts magic4(n) }
 Output:
Zero is four, four is magic.Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventy five is twelve, twelve is six, six is three, three is five, five is four, four is magic. Three hundred thirty seven is twenty six, twenty six is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixty four is thirty one, thirty one is ten, ten is three, three is five, five is four, four is magic. Nine billion eight hundred seventy six million five hundred forty three thousand two hundred nine is ninety seven, ninety seven is twelve, twelve is six, six is three, three is five, five is four, four is magic.
Rust
fn main() {
magic(4);
magic(2_340);
magic(765_000);
magic(27_000_001);
magic(999_123_090);
magic(239_579_832_723_441);
magic(std::u64::MAX);
}
fn magic(num: u64) {
if num == 4 {
println!("four is magic!");
println!();
return;
}
let name = number_name(num);
let len = name.len() as u64;
print!("{} is {}, ", name, number_name(len));
magic(len);
}
const LOW: &'static [&'static str] = &[
"zero", "one", "two", "three", "four", "five",
"six", "seven", "eight","nine", "ten",
"eleven", "twelve", "thirteen", "fourteen", "fifteen",
"sixteen", "seventeen", "eighteen", "nineteen"
];
const MED: &'static [&'static str] = &[
"twenty", "thirty", "forty", "fifty",
"sixy", "seventy", "eighty", "ninety"
];
const HIGH: &'static [&'static str] = &[
"thousand", "million", "billion",
"trillion", "quadrillion", "quintillion"
];
fn number_name(num: u64) > String {
if num < 20 {
return LOW[num as usize].to_string();
}
if num < 100 {
let index = ((num / 10)  2) as usize;
let tens = MED[index].to_string();
let remainder = num % 10;
if remainder > 0 {
return format!("{}{}", tens, number_name(remainder));
}
return tens;
}
if num < 1000 {
let hundreds = LOW[(num / 100) as usize];
let remainder = num % 100;
if remainder > 0 {
return format!("{} hundred {}", hundreds, number_name(remainder));
}
return format!("{} hundred", hundreds);
}
let mut remainder = num % 1000;
let mut cur = if remainder > 0 { number_name(remainder) } else { "".to_string() };
let mut n = num / 1000;
for noun in HIGH.iter() {
if n > 0 {
remainder = n % 1000;
if remainder > 0 {
// this condition resolves double space issues
cur =
if cur.len() > 0 { format!("{} {} {}", number_name(remainder), noun, cur ) }
else { format!("{} {}", number_name(remainder), noun) }
}
n /= 1000;
}
}
return cur;
}
 Output:
four is magic! two thousand three hundred forty is thirtytwo, thirtytwo is ten, ten is three, three is five, five is four, four is magic! seven hundred sixyfive thousand is thirtytwo, thirtytwo is ten, ten is three, three is five, five is four, four is magic! twentyseven million one is twentyfour, twentyfour is eleven, eleven is six, six is three, three is five, five is four, four is magic! nine hundred ninetynine million one hundred twentythree thousand ninety is seventythree, seventythree is thirteen, thirteen is eight, eight is five, five is four, four is magic! two hundred thirtynine trillion five hundred seventynine billion eight hundred thirtytwo million seven hundred twentythree thousand four hundred fortyone is one hundred fiftyeight, one hundred fiftyeight is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic! eighteen quintillion four hundred fortysix quadrillion seven hundred fortyfour trillion seventythree billion seven hundred nine million five hundred fiftyone thousand six hundred fifteen is one hundred ninety, one hundred ninety is eighteen, eighteen is eight, eight is five, five is four, four is magic!
Sidef
func cardinal(n) {
static lingua_en = frequire("Lingua::EN::Numbers")
lingua_en.num2en(n)  / and,/g
}
func four_is_magic(n) {
var str = ""
loop {
str += (cardinal(n) + " is ")
if (n == 4) {
str += "magic."
break
} else {
n = cardinal(n).len
str += (cardinal(n) + ", ")
}
}
str.tc
}
[0, 4, 6, 11, 13, 75, 337, 164, 9_876_543_209].each { n
say four_is_magic(n)
}
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine billion eight hundred seventysix million five hundred fortythree thousand two hundred nine is ninetyseven, ninetyseven is twelve, twelve is six, six is three, three is five, five is four, four is magic.
Swift
import Foundation
func fourIsMagic(_ number: NSNumber) > String {
let formatter = NumberFormatter()
formatter.numberStyle = .spellOut
formatter.locale = Locale(identifier: "en_EN")
var result: [String] = []
var numberString = formatter.string(from: number)!
result.append(numberString.capitalized)
while numberString != "four" {
numberString = formatter.string(from: NSNumber(value: numberString.count))!
result.append(contentsOf: [" is ", numberString, ", ", numberString])
}
result.append(" is magic.")
return result.joined()
}
for testInput in [23, 1000000000, 20140, 100, 130, 151, 7] {
print(fourIsMagic(testInput as NSNumber))
}
 Output:
TwentyThree is twelve, twelve is six, six is three, three is five, five is four, four is magic. One Billion is eleven, eleven is six, six is three, three is five, five is four, four is magic. Twenty Thousand One Hundred Forty is thirtythree, thirtythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. One Hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. One Hundred Thirty is eighteen, eighteen is eight, eight is five, five is four, four is magic. One Hundred FiftyOne is twentyone, twentyone is ten, ten is three, three is five, five is four, four is magic. Minus Seven is eleven, eleven is six, six is three, three is five, five is four, four is magic.
UNIX Shell
#!/usr/bin/env bash
name_of() {
# return the English name for a numeric value
local i n=$1
if (( n < 0 )); then
printf 'negative %s\n' "$(name_of $(( n )))"
return 0
fi
# Names for numbers that fit in a bash integer
local A names=([0]=zero [1]=one [2]=two [3]=three [4]=four [5]=five
[6]=six [7]=seven [8]=eight [9]=nine [10]=ten [11]=eleven
[12]=twelve [13]=thirteen [14]=fourteen [15]=fifteen
[16]=sixteen [17]=seventeen [18]=eighteen [19]=nineteen
[20]=twenty [30]=thirty [40]=forty [50]=fifty [60]=sixty
[70]=seventy [80]=eighty [90]=ninety [100]=hundred
[1000]=thousand [1000000]=million [1000000000]=billion
[1000000000000]=trillion [1000000000000000]=quadrillion
[1000000000000000000]=quintillion)
# The powers of 10 above 10, in descending order
local powers_of_10=($(printf '%s\n' "${!names[@]}"  sort nr  grep '00$'))
# find the largest power of 10 that is smaller than n
local i i=0
local i p=${powers_of_10[i]}
while (( p > n && i < ${#powers_of_10[@]}1 )); do
i=i+1
p=${powers_of_10[$i]}
done
# if we found one, split on it and construct quotient 'name' remainder
if (( n >= p )); then
local i quotient=n/p
local i remainder=n%p
local remname=
if (( remainder > 0 )); then
remname=$(name_of $remainder)
fi
printf '%s %s\n' "$(name_of $quotient)" "${names[$p]}${remname:+ $remname}"
elif (( n > 20 )); then
# things are a little different under 100, since the multiples of
# 10 have their own names
local i remainder=n%10
local i tens=nremainder
local remname=
if (( remainder > 0 )); then
remname=$(name_of $remainder)
fi
printf '%s\n' "${names[$tens]}${remname:+$remname}"
else
printf '%s\n' "${names[$n]}"
fi
return 0
}
# Convert numbers into the length of their names
# Display the series of values in name form until
# the length turns into four; then terminate with "four is magic."
# Again, takes a second argument, this time a prefix, to
# facilitate tail recursion.
four_is_magic() {
local i n=$1
local prefix=$2
local name=$(name_of $n)
# capitalize the first entry
if [[ z $prefix ]]; then
name=${name^}
fi
# Stop at 4, otherwise count the length of the name and recurse
if (( $n == 4 )); then
printf '%s%s is magic.\n' "${prefix:+$prefix, }" "$name"
else
local i len=${#name}
four_is_magic "$len" "${prefix:+$prefix, }$name is $(name_of $len)"
fi
}
 Output:
# sadly the number of Rubik's Cube permutations won't fit into a bash int, # but this is that value minus the first digit (40 quintillion) $ four_is_magic 3252003274489856000 Three quintillion two hundred fiftytwo quadrillion three trillion two hundred seventyfour billion four hundred eightynine million eight hundred fiftysix thousand is one hundred sixtyfive, one hundred sixtyfive is twentytwo, twentytwo is ten, ten is three, three is five, five is four, four is magic. # Max Unicode code point $ four_is_magic 1114111 One million one hundred fourteen thousand one hundred eleven is sixty, sixty is five, five is four, four is magic. # Some usual suspects $ four_is_magic 42 Fortytwo is nine, nine is four, four is magic. $ four_is_magic 23 Twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic. # the units for (( i=0; i<10; i++ )); do four_is_magic $i done Zero is four, four is magic. One is three, three is five, five is four, four is magic. Two is three, three is five, five is four, four is magic. Three is five, five is four, four is magic. Four is magic. Five is four, four is magic. Six is three, three is five, five is four, four is magic. Seven is five, five is four, four is magic. Eight is five, five is four, four is magic. Nine is four, four is magic.
V (Vlang)
import math
fn main() {
for n in [i64(0), 4, 6, 11, 13, 75, 100, 337, 164,
math.max_i64,
] {
println(four_is_magic(n))
}
}
fn four_is_magic(nn i64) string {
mut n := nn
mut s := say(n)
s = s[..1].to_upper() + s[1..]
mut t := s
for n != 4 {
n = i64(s.len)
s = say(n)
t += " is " + s + ", " + s
}
t += " is magic."
return t
}
const small = ["zero", "one", "two", "three", "four", "five", "six",
"seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen",
"fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
const tens = ["", "", "twenty", "thirty", "forty",
"fifty", "sixty", "seventy", "eighty", "ninety"]
const illions = ["", " thousand", " million", " billion",
" trillion", " quadrillion", " quintillion"]
fn say(nn i64) string {
mut t := ''
mut n := nn
if n < 0 {
t = "negative "
// Note, for math.MinInt64 this leaves n negative.
n = n
}
match true {
n < 20 {
t += small[n]
}
n < 100 {
t += tens[n/10]
s := n % 10
if s > 0 {
t += "" + small[s]
}
}
n < 1000 {
t += small[n/100] + " hundred"
s := n % 100
if s > 0 {
t += " " + say(s)
}
}
else {
// work righttoleft
mut sx := ""
for i := 0; n > 0; i++ {
p := n % 1000
n /= 1000
if p > 0 {
mut ix := say(p) + illions[i]
if sx != "" {
ix += " " + sx
}
sx = ix
}
}
t += sx
}
}
return t
}
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine quadrillion seven trillion one hundred ninetynine billion two hundred fiftyfour million seven hundred forty thousand nine hundred ninetyone is one hundred fortyseven, one hundred fortyseven is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic.
Wren
This reuses the say
function from the Number names task.
Note that it is not safe to use this script for numbers with an absolute magnitude >= 2^53 as integers cannot be expressed exactly by Wren's Num type beyond that limit.
import "./str" for Str
var small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven",
"twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
var tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
var illions = ["", " thousand", " million", " billion"," trillion", " quadrillion", " quintillion"]
var say
say = Fn.new { n
var t = ""
if (n < 0) {
t = "negative "
n = n
}
if (n < 20) {
t = t + small[n]
} else if (n < 100) {
t = t + tens[(n/10).floor]
var s = n % 10
if (s > 0) t = t + "" + small[s]
} else if (n < 1000) {
t = t + small[(n/100).floor] + " hundred"
var s = n % 100
if (s > 0) t = t + " " + say.call(s)
} else {
var sx = ""
var i = 0
while (n > 0) {
var p = n % 1000
n = (n/1000).floor
if (p > 0) {
var ix = say.call(p) + illions[i]
if (sx != "") ix = ix + " " + sx
sx = ix
}
i = i + 1
}
t = t + sx
}
return t
}
var fourIsMagic = Fn.new { n
var s = Str.capitalize(say.call(n))
var t = s
while (n != 4) {
n = s.count
s = say.call(n)
t = t + " is " + s + ", " + s
}
return t + " is magic."
}
for (n in [0, 4, 6, 11, 13, 75, 100, 337, 164, 9007199254740991]) {
System.print(fourIsMagic.call(n))
}
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. One hundred is eleven, eleven is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine quadrillion seven trillion one hundred ninetynine billion two hundred fiftyfour million seven hundred forty thousand nine hundred ninetyone is one hundred fortyseven, one hundred fortyseven is twentythree, twentythree is twelve, twelve is six, six is three, three is five, five is four, four is magic.
zkl
Limitiation: zkl only has 64 bit signed integars.
Uses the nth function from Spelling_of_ordinal_numbers#zkl
fcn fourIsMagic(int){
if(int==0) return("Zero is four, four is magic.");
string:="";
while(1){ c:=nth(int,False);
string+="%s is ".fmt(c);
if(int = ( if(int==4) 0 else c.len() )){
string+="%s, ".fmt(nth(int,False));
}else{
string+="magic.";
break;
}
}
string[0].toUpper() + string[1,*]
}
foreach n in (T(0,4,6,11,13,75,337,164,9876543209)){
println(fourIsMagic(n),"\n")
}
 Output:
Zero is four, four is magic. Four is magic. Six is three, three is five, five is four, four is magic. Eleven is six, six is three, three is five, five is four, four is magic. Thirteen is eight, eight is five, five is four, four is magic. Seventyfive is twelve, twelve is six, six is three, three is five, five is four, four is magic. Three hundred thirtyseven is twentysix, twentysix is ten, ten is three, three is five, five is four, four is magic. Negative one hundred sixtyfour is thirtyone, thirtyone is ten, ten is three, three is five, five is four, four is magic. Nine billion eight hundred seventysix million five hundred fortythree thousand two hundred nine is ninetyseven, ninetyseven is twelve, twelve is six, six is three, three is five, five is four, four is magic.
 Programming Tasks
 Solutions by Programming Task
 11l
 8086 Assembly
 APL
 AppleScript
 AutoHotkey
 AWK
 C
 GLib
 C++
 Clojure
 Common Lisp
 Delphi
 System.SysUtils
 EasyLang
 F Sharp
 Factor
 Fortran
 FreeBASIC
 FutureBasic
 Go
 Haskell
 J
 Java
 JavaScript
 Jq
 Julia
 Kotlin
 Lua
 Mathematica
 Wolfram Language
 Nim
 Perl
 Phix
 Python
 Q
 R
 Racket
 Raku
 REXX
 Ring
 Ruby
 Rust
 Sidef
 Swift
 UNIX Shell
 V (Vlang)
 Wren
 Wrenstr
 Zkl