Task

Show how to spell out a number in English.

You can use a preexisting implementation or roll your own, but you should support inputs up to at least one million (or the maximum value of your language's default bounded integer type, if that's less).

Support for inputs other than positive integers (like zero, negative integers, and floating-point numbers) is optional.



Related task

   Spelling of ordinal numbers.


--
-- demo\rosetta\Number_names.exw
-- -----------------------------
--
with javascript_semantics

constant twenties = {"zero","one","two","three","four","five","six","seven","eight","nine","ten",
    "eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen"}
 
function twenty(integer n)
    return twenties[mod(n,20)+1]
end function
 
constant decades = {"twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety"}
 
function decade(integer n)
    return decades[mod(n,10)-1]
end function
 
function hundred(integer n)
    if n<20 then
        return twenty(n)
    elsif mod(n,10)=0 then
        return decade(mod(floor(n/10),10))
    end if
    return decade(floor(n/10)) & '-' & twenty(mod(n,10))
end function
 
function thousand(integer n, string withand)
    if n<100 then
        return withand & hundred(n)
    elsif mod(n,100)=0 then
        return withand & twenty(floor(n/100))&" hundred"
    end if
    return twenty(floor(n/100)) & " hundred and " & hundred(mod(n,100))
end function
 
constant orders = {{power(10,15),"quadrillion"},
                   {power(10,12),"trillion"},
                   {power(10,9),"billion"},
                   {power(10,6),"million"},
                   {power(10,3),"thousand"}}
 
function triplet(atom 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),iff(res=""?"":"and "))
        n = abs(mod(n,1))
        if n>1e-6 then
            res &= " point"
            for i=1 to 10 do
                integer t = floor(n*10.0000001)
                res &= ' '&twenties[t+1]
                n = n*10-t
                if abs(n)<1e-6 then exit end if
            end for
        end if
    end if
    return res
end function
 
global 
function spell(atom n)
    string res = ""
    if n<0 then
        res = "minus "
        n = -n
    end if
    res &= triplet(n)
    return res
end function
 
global 
constant samples = {99, 300, 310, 417,1_501, 12_609, 200000000000100, 999999999999999,
                    -123456787654321,102003000400005,1020030004,102003,102,1,0,-1,-99, 
                    -1501,1234,12.34,10000001.2,1E-3,-2.7182818,
                    201021002001,-20102100200,2010210020,-201021002,20102100,-2010210,
                    201021,-20102,2010,-201,20,-2}

global 
function smartp(atom n)
    if n=floor(n) then return sprintf("%d",n) end if
    string res = sprintf("%18.8f",n)
    if find('.',res) then
        res = trim_tail(res,"0")
    end if
    return res
end function
 
procedure main()
    for i=1 to length(samples) do
        atom si = samples[i]
        printf(1,"%18s %s\n",{smartp(si),spell(si)})
    end for
end procedure

if include_file()=1 then
    main()
    {} = wait_key()
end if
