NumbersToWords := module() local ModuleApply , NumbersToWords , Natural , small, decade, millinary , convert20_99 , convert100_999 , convertLarge ; description "convert an integer into American English words"; ModuleApply := proc(n) if n < 0 then sprintf("minus %s", Natural(-n)) elif n = 0 then "zero" else Natural(n); end if end proc; Natural := proc(n::posint) if n < 20 then small[n] elif n < 100 then convert20_99(n) elif n < 1000 then convert100_999(n) else convertLarge(n) end if end proc; convert20_99 := proc(n::nonnegint) local tens, rem; tens := decade[iquo(n,10,'rem')]; if rem = 0 then tens else sprintf("%s-%s", tens, small[rem]) end if; end proc; convert100_999 := proc(n::nonnegint) local huns,rem; huns := sprintf("%s hundred", small[iquo(n,100,'rem')]); if rem = 0 then huns elif rem < 20 then sprintf("%s %s", huns, small[rem]); else sprintf("%s %s", huns, convert20_99(rem)); end if; end proc; convertLarge := proc(n) local kilos,num,rem; kilos := iquo(ilog10(n),3); if kilos > 20 then error "number too large" end if; num := sprintf("%s %s", Natural(iquo(n,10^(3*kilos),'rem')) , `if`(kilos=1 , "thousand" , sprintf("%sillion", millinary[kilos-1]) ) ); if rem = 0 then num else sprintf("%s %s", num, Natural(rem)); end if; end proc; small := rtable(1..19, [ NULL , "one" , "two" , "three" , "four" , "five" , "six" , "seven" , "eight" , "nine" , "ten" , "eleven" , "twelve" , "thirteen" , "fourteen" , "fifteen" , "sixteen" , "seventeen" , "eighteen" , "nineteen" ]); decade := rtable(2..9, [ NULL , "twenty" , "thirty" , "forty" , "fifty" , "sixty" , "seventy" , "eighty" , "ninety" ]); millinary := rtable(1..20, [ NULL , "m" , "b" , "tr" , "quadr" , "quint" , "sext" , "sept" , "oct" , "non" , "dec" , "undec" , "duodec" , "tredec" , "quattuordec" , "quindec" , "sexdec" , "septendec" , "octodec" , "novemdec" , "vigint" ]); end module: