Number names
You are encouraged to solve this task according to the task description, using any language you may know.
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.
Ada
<lang ada>with Ada.Text_IO; use Ada.Text_IO;
procedure Integers_In_English is
type Spellable is range 0..999_999_999_999_999_999; function Spell (N : Spellable) return String is function Twenty (N : Spellable) return String is begin case N mod 20 is when 0 => return "zero"; when 1 => return "one"; when 2 => return "two"; when 3 => return "three"; when 4 => return "four"; when 5 => return "five"; when 6 => return "six"; when 7 => return "seven"; when 8 => return "eight"; when 9 => return "nine"; when 10 => return "ten"; when 11 => return "eleven"; when 12 => return "twelve"; when 13 => return "thirteen"; when 14 => return "fourteen"; when 15 => return "fifteen"; when 16 => return "sixteen"; when 17 => return "seventeen"; when 18 => return "eighteen"; when others => return "nineteen"; end case; end Twenty;
function Decade (N : Spellable) return String is begin case N mod 10 is when 2 => return "twenty"; when 3 => return "thirty"; when 4 => return "forty"; when 5 => return "fifty"; when 6 => return "sixty"; when 7 => return "seventy"; when 8 => return "eighty"; when others => return "ninety"; end case; end Decade;
function Hundred (N : Spellable) return String is begin if N < 20 then return Twenty (N); elsif 0 = N mod 10 then return Decade (N / 10 mod 10); else return Decade (N / 10) & '-' & Twenty (N mod 10); end if; end Hundred;
function Thousand (N : Spellable) return String is begin if N < 100 then return Hundred (N); elsif 0 = N mod 100 then return Twenty (N / 100) & " hundred"; else return Twenty (N / 100) & " hundred and " & Hundred (N mod 100); end if; end Thousand;
function Triplet ( N : Spellable; Order : Spellable; Name : String; Rest : not null access function (N : Spellable) return String ) return String is High : Spellable := N / Order; Low : Spellable := N mod Order; begin if High = 0 then return Rest (Low); elsif Low = 0 then return Thousand (High) & ' ' & Name; else return Thousand (High) & ' ' & Name & ", " & Rest (Low); end if; end Triplet;
function Million (N : Spellable) return String is begin return Triplet (N, 10**3, "thousand", Thousand'Access); end Million;
function Milliard (N : Spellable) return String is begin return Triplet (N, 10**6, "million", Million'Access); end Milliard;
function Billion (N : Spellable) return String is begin return Triplet (N, 10**9, "milliard", Milliard'Access); end Billion;
function Billiard (N : Spellable) return String is begin return Triplet (N, 10**12, "billion", Billion'Access); end Billiard;
begin return Triplet (N, 10**15, "billiard", Billiard'Access); end Spell;
begin
Put_Line (" 99 " & Spell ( 99)); Put_Line (" 300 " & Spell ( 300)); Put_Line (" 310 " & Spell ( 310)); Put_Line (" 1_501 " & Spell ( 1_501)); Put_Line (" 12_609 " & Spell ( 12_609)); Put_Line (" 512_609 " & Spell ( 512_609)); Put_Line (" 43_112_609 " & Spell ( 43_112_609)); Put_Line (" 77_000_112_609 " & Spell ( 77_000_112_609)); Put_Line ("2_000_000_000_100 " & Spell (2_000_000_000_100));
end Integers_In_English;</lang> The solution is recursive by the triplets of decimal numbers. The implementation goes up to 1018-1. Sample output:
99 ninety-nine 300 three hundred 310 three hundred and ten 1_501 one thousand, five hundred and one 12_609 twelve thousand, six hundred and nine 512_609 five hundred and twelve thousand, six hundred and nine 43_112_609 forty-three million, one hundred and twelve thousand, six hundred and nine 77_000_112_609 seventy-seven milliard, one hundred and twelve thousand, six hundred and nine 2_000_000_000_100 two billion, one hundred
ALGOL 68
<lang algol68>PROC number words = (INT n)STRING:(
# returns a string representation of n in words. Currently deals with anything from 0 to 999 999 999. # []STRING digits = []STRING ("zero","one","two","three","four","five","six","seven","eight","nine")[@0]; []STRING teens = []STRING ("ten","eleven","twelve","thirteen","fourteen","fifteen","sixteen","seventeen","eighteen","nineteen")[@0]; []STRING decades = []STRING ("twenty","thirty","forty","fifty","sixty","seventy","eighty","ninety")[@2]; PROC three digits = (INT n)STRING: ( # does the conversion for n from 0 to 999. # INT tens = n MOD 100 OVER 10; INT units = n MOD 10; (n >= 100|digits[n OVER 100] + " " + "hundred" + (n MOD 100 /= 0|" and "|"")|"") + (tens /= 0|(tens = 1|teens[units]|decades[tens] + (units /= 0|"-"|""))|"") + (units /= 0 AND tens /= 1 OR n = 0|digits[units]|"") ); INT m = n OVER 1 000 000; INT k = n MOD 1 000 000 OVER 1000; INT u = n MOD 1000; (m /= 0|three digits(m) + " million"|"") + (m /= 0 AND (k /= 0 OR u >= 100)|", "|"") + (k /= 0|three digits(k) + " thousand"|"") + ((m /= 0 OR k /= 0) AND u > 0 AND u < 100|" and " |: k /= 0 AND u /= 0|", "|"") + (u /= 0 OR n = 0|three digits(u)|"") );
on logical file end(stand in, (REF FILE f)BOOL: GOTO stop iteration); on value error(stand in, (REF FILE f)BOOL: GOTO stop iteration); DO # until user hits EOF #
INT n; print("n? "); read((n, new line)); print((number words(n), new line))
OD; stop iteration:
SKIP</lang>
Example input with output:
n? 43112609 forty-three million, one hundred and twelve thousand, six hundred and nine
<lang Algol68>MODE EXCEPTION = STRUCT(STRING name, PROC VOID handler); EXCEPTION value error = ("Value Error", stop);
PROC raise = (EXCEPTION exception, STRING str error)VOID: (
put(stand error, (name OF exception,": ",str error, new line)); handler OF exception
);
MODE LINT = LONG LONG INT;
BOOL locale euro := TRUE;
PROC spell integer = (LINT n)STRING: (
[]STRING tens = []STRING (~, ~, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety")[@0]; []STRING small = []STRING ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen")[@0]; []STRING bl = []STRING (~, ~, "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", "dec")[@0]; PROC nonzero = (STRING c, LINT n)STRING: IF n = 0 THEN "" ELSE c + spell integer(n) FI; PROC big =(INT e, LINT n)STRING: spell integer(n) + CASE e+1 IN #0# "", #1# " thousand" OUT " " + IF locale euro THEN # handle millard, billard & trillard etc # bl[e OVER 2 + 1 ]+"ill" + CASE e MOD 2 IN "ard" OUT "ion" ESAC ELSE bl[e]+"illion" FI ESAC; PROC base1000 rev = (LINT in n, PROC (INT,LINT)VOID yield)VOID: ( # generates the value of the digits of n in base 1000 # # (i.e. 3-digit chunks), in reverse. # LINT n := in n; FOR e FROM 0 WHILE n /= 0 DO LINT r = n MOD 1000; n := n OVER 1000; yield(e, r) OD ); IF n < 1000 THEN INT ssn := SHORTEN SHORTEN n; IF ssn < 0 THEN raise (value error, "spell integer: negative input"); ~ ELIF ssn < 20 THEN small[ssn] ELIF ssn < 100 THEN INT a = ssn OVER 10, b = ssn MOD 10; tens[a] + nonzero("-", b) ELIF ssn < 1000 THEN INT a = ssn OVER 100, b = ssn MOD 100; small[a] + " hundred" + ( b NE 0 | " and" | "") + nonzero(" ", b) FI ELSE STRING out := "", sep:=""; # FOR e, x IN # base1000 rev(n, # DO # (INT e, LINT x)VOID: IF x NE 0 THEN big(e,x) + sep +=: out; sep := IF e = 0 AND x < 100 THEN " and " ELSE ", " FI FI ) # OD #; out FI
);
PROC example = (LINT n)VOID:
print((whole(n,0),": ", spell integer(n), new line));
- examples #
LINT prod := 0; FOR i TO 6 DO prod := prod * 10**i + i; example(prod) OD;
example(1278); example(1572); example(2010)</lang>Test output:
1: one 102: one hundred and two 102003: one hundred and two thousand and three 1020030004: one millard, twenty million, thirty thousand and four 102003000400005: one hundred and two billion, three millard, four hundred thousand and five 102003000400005000006: one hundred and two trillion, three billard, four hundred millard, five million and six 1278: one thousand, two hundred and seventy-eight 1572: one thousand, five hundred and seventy-two 2010: two thousand and ten
AutoHotkey
<lang autohotkey>Loop { ; TEST LOOP
n = Random Digits, 1, 36 ; random number with up to 36 digits Loop %Digits% { Random Digit, 0, 9 ; can have leading 0s n .= Digit } MsgBox 1, Number Names, % PrettyNumber(n) "`n`n" Spell(n) "`n`n" IfMsgBox Cancel, Break
}
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"
n :=RegExReplace(n,"^0+(\d)","$1") ; remove leading 0s from n
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,1-3*d)) ? ", " Spell(s) : "")
i := SubStr(n,1,1) If (n > 99) ; 3 digits Return o%i% " hundred" ((s:=SubStr(n,2)) ? " and " 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( RegExReplace(n,"^0+(\d)","$1"), "\G\d+?(?=(\d{3})+(?:\D|$))", "$0,")
}</lang>
BASIC
<lang qbasic>DECLARE FUNCTION int2Text$ (number AS LONG)
'small DATA "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" DATA "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" 'tens DATA "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" 'big DATA "thousand", "million", "billion"
DIM SHARED small(1 TO 19) AS STRING, tens(7) AS STRING, big(2) AS STRING
DIM tmpInt AS INTEGER
FOR tmpInt = 1 TO 19
READ small(tmpInt)
NEXT FOR tmpInt = 0 TO 7
READ tens(tmpInt)
NEXT FOR tmpInt = 0 TO 2
READ big(tmpInt)
NEXT
DIM n AS LONG
INPUT "Gimme a number! ", n PRINT int2Text$(n)
FUNCTION int2Text$ (number AS LONG)
DIM num AS LONG, outP AS STRING, unit AS INTEGER DIM tmpLng1 AS LONG
IF 0 = number THEN int2Text$ = "zero" EXIT FUNCTION END IF
num = ABS(number)
DO tmpLng1 = num MOD 100 SELECT CASE tmpLng1 CASE 1 TO 19 outP = small(tmpLng1) + " " + outP CASE 20 TO 99 SELECT CASE tmpLng1 MOD 10 CASE 0 outP = tens((tmpLng1 \ 10) - 2) + " " + outP CASE ELSE outP = tens((tmpLng1 \ 10) - 2) + "-" + small(tmpLng1 MOD 10) + " " + outP END SELECT END SELECT
tmpLng1 = (num MOD 1000) \ 100 IF tmpLng1 THEN outP = small(tmpLng1) + " hundred " + outP END IF
num = num \ 1000 IF num < 1 THEN EXIT DO tmpLng1 = num MOD 1000 IF tmpLng1 THEN outP = big(unit) + " " + outP
unit = unit + 1 LOOP
IF number < 0 THEN outP = "negative " + outP
int2Text$ = RTRIM$(outP)
END FUNCTION</lang>
Sample outputs (including the answer to the ultimate question of life, the universe, and everything):
Gimme a number! 1 one Gimme a number! 0 zero Gimme a number! -1 negative one Gimme a number! 42 forty-two Gimme a number! 1000000 one million Gimme a number! 1000000001 one billion one Gimme a number! &h7fffffff two billion one hundred forty-seven million four hundred eighty-three thousand six hundred forty-seven
C
This uses the code from Basic string manipulation functions. <lang c>#include <stdio.h>
- include "estrings.h"
- define setStringFromCStr(S, N) setString((S), (N), strlen(N))
- define appendString(S, N) do { String _t, _s; \
_s = newString(); setStringFromCStr(_s, (N)); \ _t = joinStrings((S),_s); \ copyString((S), _t); destroyString(_t); destroyString(_s); } while(0)
const char* smallNumbers[] = {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
String spellHundreds(unsigned int n) {
String res; res = newString(); if (n > 99) { setStringFromCStr(res, smallNumbers[n/100]); appendString(res, " hundred"); n %= 100; if (n) appendString(res, " and "); } if (n >= 20) { static const char* Decades[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; appendString(res, Decades[n/10]); n %= 10; if (n) appendString(res, "-"); } if (n < 20 && n > 0) appendString(res,smallNumbers[n]); return res;
}
const char* thousandPowers[] = {
" billion", " million", " thousand", "" };
typedef unsigned long Spellable;
String spell(Spellable n) {
String res; res = newString(); if (n < 20) return setStringFromCStr(res, smallNumbers[n]); const char** pScaleName = thousandPowers; Spellable scaleFactor = 1000000000; // 1 billion while (scaleFactor > 0) { if (n >= scaleFactor) { Spellable h = n / scaleFactor; String t1 = spellHundreds(h); String t2 = joinStrings(res, t1); copyString(res, t2); destroyString(t2); destroyString(t1); appendString(res, *pScaleName); n %= scaleFactor; if (n) appendString(res, ", "); } scaleFactor /= 1000; ++pScaleName; } return res;
}
- define SPELL_IT(x) do { \
String sp; \ sp = spell(x); appendChar(sp, 0); \ printf("%d %s\n", x, sp->bstring); destroyString(sp); \ } while(0)
int main() {
SPELL_IT( 99); SPELL_IT( 300); SPELL_IT( 310); SPELL_IT( 1501); SPELL_IT( 12609); SPELL_IT( 512609); SPELL_IT(43112609); SPELL_IT(1234567890); return 0;
}</lang>
C++
<lang cpp>#include <string>
- include <iostream>
using std::string;
const char* smallNumbers[] = {
"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
};
string spellHundreds(unsigned n) {
string res; if (n > 99) { res = smallNumbers[n/100]; res += " hundred"; n %= 100; if (n) res += " and "; } if (n >= 20) { static const char* Decades[] = { "", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" }; res += Decades[n/10]; n %= 10; if (n) res += "-"; } if (n < 20 && n > 0) res += smallNumbers[n]; return res;
}
const char* thousandPowers[] = {
" billion", " million", " thousand", "" };
typedef unsigned long Spellable;
string spell(Spellable n) {
if (n < 20) return smallNumbers[n]; string res; const char** pScaleName = thousandPowers; Spellable scaleFactor = 1000000000; // 1 billion while (scaleFactor > 0) { if (n >= scaleFactor) { Spellable h = n / scaleFactor; res += spellHundreds(h) + *pScaleName; n %= scaleFactor; if (n) res += ", "; } scaleFactor /= 1000; ++pScaleName; } return res;
}
int main() {
- define SPELL_IT(x) std::cout << #x " " << spell(x) << std::endl;
SPELL_IT( 99); SPELL_IT( 300); SPELL_IT( 310); SPELL_IT( 1501); SPELL_IT( 12609); SPELL_IT( 512609); SPELL_IT(43112609); SPELL_IT(1234567890); return 0;
}</lang> Sample output:
99 ninety-nine 300 three hundred 310 three hundred and ten 1501 one thousand, five hundred and one 12609 twelve thousand, six hundred and nine 512609 five hundred and twelve thousand, six hundred and nine 43112609 forty-three million, one hundred and twelve thousand, six hundred and nine 1234567890 one billion, two hundred and thirty-four million, five hundred and sixty-seven thousand, eight hundred and ninety
C#
<lang csharp>using System;
class NumberNamer {
static readonly string[] incrementsOfOne = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
static readonly string[] incrementsOfTen = { "", "", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety" };
const string millionName = "million", thousandName = "thousand", hundredName = "hundred", andName = "and";
public static string GetName( int i ) { string output = ""; if( i >= 1000000 ) { output += ParseTriplet( i / 1000000 ) + " " + millionName; i %= 1000000; if( i == 0 ) return output; }
if( i >= 1000 ) { if( output.Length > 0 ) { output += ", "; } output += ParseTriplet( i / 1000 ) + " " + thousandName; i %= 1000; if( i == 0 ) return output; }
if( output.Length > 0 ) { output += ", "; } output += ParseTriplet( i ); return output; }
static string ParseTriplet( int i ) { string output = ""; if( i >= 100 ) { output += incrementsOfOne[i / 100] + " " + hundredName; i %= 100; if( i == 0 ) return output; }
if( output.Length > 0 ) { output += " " + andName + " "; } if( i >= 20 ) { output += incrementsOfTen[i / 10]; i %= 10; if( i == 0 ) return output; }
if( output.Length > 0 ) { output += " "; } output += incrementsOfOne[i]; return output; }
}
class Program { // Test class
static void Main( string[] args ) { Console.WriteLine( NumberNamer.GetName( 1 ) ); Console.WriteLine( NumberNamer.GetName( 234 ) ); Console.WriteLine( NumberNamer.GetName( 31337 ) ); Console.WriteLine( NumberNamer.GetName( 987654321 ) ); }
} /* Sample output: one two hundred and thirty four thirty one thousand, three hundred and thirty seven nine hundred and eighty seven million, six hundred and fifty four thousand, three hundred and twenty one
- /</lang>
Common Lisp
<lang lisp>(format nil "~R" 1234) => "one thousand two hundred thirty-four"</lang>
D
<lang d>import std.stdio: writefln; import std.string: join;
string spell_integer(long n) {
static string[] tens = [ ""[], "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];
static string[] small = [ "zero"[], "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"];
static string[] bl = [""[], "", "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", "dec"];
string nonzero(string c, long n) { return n == 0 ? "" : c ~ spell_integer(n); }
string big(long e, long n) { if (e == 0) return spell_integer(n); else if (e == 1) return spell_integer(n) ~ " thousand"; else return spell_integer(n) ~ " " ~ bl[e] ~ "illion"; }
long[] base1000_rev(long n) { // generates the value of the digits of n in base 1000 // (i.e. 3-digit chunks), in reverse. long[] result; while (n != 0) { result ~= n % 1000; n /= 1000; } return result; }
if (n < 0) { throw new Exception("spell_integer: negative input"); } else if (n < 20) { return small[n]; } else if (n < 100) { return tens[n / 10] ~ nonzero("-", n % 10); } else if (n < 1000) { return small[n / 100] ~ " hundred" ~ nonzero(" ", n % 100); } else { string[] pieces; foreach (e, x; base1000_rev(n)) pieces ~= big(e, x); return pieces.reverse.join(", "); }
}
void main() { // example
for (int i; i < 1000; i++) writefln(spell_integer(i));
}</lang>
Fortran
<lang fortran>program spell
implicit none integer :: e integer :: i integer :: m integer :: n character (9), dimension (19), parameter :: small = & & (/'one ', 'two ', 'three ', 'four ', & & 'five ', 'six ', 'seven ', 'eight ', & & 'nine ', 'ten ', 'eleven ', 'twelve ', & & 'thirteen ', 'fourteen ', 'fifteen ', 'sixteen ', & & 'seventeen', 'eighteen ', 'nineteen '/) character (7), dimension (2 : 9), parameter :: tens = & & (/'twenty ', 'thirty ', 'forty ', 'fifty ', 'sixty ', & & 'seventy', 'eighty ', 'ninety '/) character (8), dimension (3), parameter :: big = & & (/'thousand', 'million ', 'billion '/) character (256) :: r
do read (*, *, iostat = i) n if (i /= 0) then exit end if if (n == 0) then r = 'zero' else r = m = abs (n) e = 0 do if (m == 0) then exit end if if (modulo (m, 1000) > 0) then if (e > 0) then r = trim (big (e)) // ' ' // r end if if (modulo (m, 100) > 0) then if (modulo (m, 100) < 20) then r = trim (small (modulo (m, 100))) // ' ' // r else if (modulo (m, 10) > 0) then r = trim (small (modulo (m, 10))) // ' ' // r r = trim (tens (modulo (m, 100) / 10)) // '-' // r else r = trim (tens (modulo (m, 100) / 10)) // ' ' // r end if end if end if if (modulo (m, 1000) / 100 > 0) then r = 'hundred' // ' ' // r r = trim (small (modulo (m, 1000) / 100)) // ' ' // r end if end if m = m / 1000 e = e + 1 end do if (n < 0) then r = 'negative' // ' ' // r end if end if write (*, '(a)') trim (r) end do
end program spell</lang> Sample input: <lang>-1 0 1 42 2147483647</lang> Output: <lang>negative one zero one forty-two two billion one hundred forty-seven million four hundred eighty-three thousand six hundred forty-seven</lang>
Haskell
<lang haskell>import Data.List (intercalate, unfoldr)
spellInteger :: Integer -> String spellInteger n
| n < 0 = "negative " ++ spellInteger (-n) | n < 20 = small n | n < 100 = let (a, b) = n `divMod` 10 in tens a ++ nonzero '-' b | n < 1000 = let (a, b) = n `divMod` 100 in small a ++ " hundred" ++ nonzero ' ' b | otherwise = intercalate ", " $ map big $ reverse $ filter ((/= 0) . snd) $ zip [0..] $ unfoldr uff n
where nonzero :: Char -> Integer -> String nonzero _ 0 = "" nonzero c n = c : spellInteger n
uff :: Integer -> Maybe (Integer, Integer) uff 0 = Nothing uff n = Just $ uncurry (flip (,)) $ n `divMod` 1000
small, tens :: Integer -> String small = (["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] !!) . fromEnum tens = ([undefined, undefined, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"] !!) . fromEnum
big :: (Int, Integer) -> String big (0, n) = spellInteger n big (1, n) = spellInteger n ++ " thousand" big (e, n) = spellInteger n ++ ' ' : (l !! e) ++ "illion" where l = [undefined, undefined, "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", "dec"]</lang>
HicEst
<lang HicEst>SUBROUTINE NumberToWords(number)
CHARACTER outP*255, small*130, tens*80, big*80 REAL :: decimal_places = 7 INIT( APPENDIX("#literals"), small, tens, big)
num = ABS( INT(number) ) order = 0 outP = ' ' DO i = 1, num + 1 tmp = MOD(num, 100) IF(tmp > 19) THEN EDIT(Text=tens, ITeM=INT(MOD(tmp/10, 10)), Parse=medium) IF( MOD(tmp, 10) ) THEN EDIT(Text=small, ITeM=MOD(tmp,10)+1, Parse=mini) outP = medium // '-' // mini // ' ' // outP ELSE outP = medium // ' ' // outP ENDIF ELSEIF(tmp > 0) THEN EDIT(Text=small, ITeM=tmp+1, Parse=mini) outP = mini // ' '// outP ELSEIF(number == 0) THEN outP = 'zero' ENDIF
tmp = INT(MOD(num, 1000) / 100) IF(tmp) THEN EDIT(Text=small, ITeM=tmp+1, Parse=oneto19) outP = oneto19 // ' hundred ' // outP ENDIF
num = INT(num /1000) IF( num == 0) THEN IF(number < 0) outP = 'minus ' // outP fraction = ABS( MOD(number, 1) ) IF(fraction) WRITE(Text=outP, APPend) ' point' DO j = 1, decimal_places IF( fraction >= 10^(-decimal_places) ) THEN num = INT( 10.01 * fraction ) EDIT(Text=small, ITeM=num+1, Parse=digit) WRITE(Text=outP, APPend) ' ', digit fraction = 10*fraction - num ENDIF ENDDO OPEN(FIle="temp.txt", APPend) WRITE(FIle="temp.txt", Format='F10, " = ", A', CLoSe=1) number, outP RETURN ENDIF
order = order + 1 EDIT(Text=big, ITeM=order, Parse=kilo) IF( MOD(num, 1000) ) outP = kilo // ' and '// outP ENDDO
END
CALL NumberToWords( 0 ) CALL NumberToWords( 1234 ) CALL NumberToWords( 1234/100 ) CALL NumberToWords( 10000000 + 1.2 ) CALL NumberToWords( 2^15 ) CALL NumberToWords( 0.001 ) CALL NumberToWords( -EXP(1) )
- literals
SMALL= zero one two three four five six seven eight nine ten & eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen
TENS=ten twenty thirty forty fifty sixty seventy eighty ninety
BIG=thousand million billion trillion quadrillion</lang>
<lang HicEst>0 = zero 1234 = one thousand and two hundred thirty-four 12.34 = twelve point three four 10000001.2 = ten million and one point two 32768 = thirty-two thousand and seven hundred sixty-eight 1E-3 = point zero zero one -2.7182818 = minus two point seven one eight two eight one eight</lang>
Icon and Unicon
Icon
<lang Icon>link numbers # commas, spell
procedure main(arglist) every x := !arglist do
write(commas(x), " -> ",spell(x))
end</lang>
numbers:spell was used as a based for this procedure.
<lang Icon>procedure spell(n) #: spell out integer (short scale)
local m, i static scale initial { scale := [ "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion","septillion"] every scale[i := 1 to *scale ] := [ integer(repl("999",i + 1)), -3 * i, " "||scale[i] ] push(scale,[999,2," hundred"]) }
n := integer(n) | stop(image(n)," is not an integer") if n < 0 then return "negative " || spell(-n) if n <= 12 then return { "0zero,1one,2two,3three,4four,5five,6six,7seven,8eight,_ 9nine,10ten,11eleven,12twelve," ? { tab(find(n)) move(*n) tab(find(",")) } } else if n <= 19 then return { spell(n[2] || "0") ? (if ="for" then "four" else tab(find("ty"))) || "teen" } else if n <= 99 then return { "2twen,3thir,4for,5fif,6six,7seven,8eigh,9nine," ? { tab(find(n[1])) move(1) tab(find(",")) || "ty" || (if n[2] ~= 0 then "-" || spell(n[2]) else "") } } else if n <= scale[i := 1 to *scale,1] then return { # generalize based on scale spell(n[1:scale[i,2]]) || scale[i,3] || (if (m := n[scale[i,2]:0]) ~= 0 then " and " || spell(m) else "") } else fail # really big
end</lang> Sample output:
#spell.exe 5 11 15 67 10132767 65535 -1234567890123456 5 -> five 11 -> eleven 15 -> fifteen 67 -> sixty-seven 10,132,767 -> ten million and one hundred and thirty-two thousand and seven hundred and sixty-seven 65,535 -> sixty-five thousand and five hundred and thirty-five -1,234,567,890,123,456 -> negative one quadrillion and two hundred and thirty-four trillion and five hundred and sixty-seven billion and eight hundred and ninety million and one hundred and twenty-three thousand and four hundred and fifty-six
Unicon
This Icon solution works in Unicon.
Inform 7
<lang inform7>say 32767 in words;</lang>
<lang inform7>say 2147483647 in words;</lang>
J
Solutions: <lang j>u=. ;:'one two three four five six seven eight nine' v=. ;:'ten eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen' t=. ;:'twenty thirty forty fifty sixty seventy eighty ninety' EN100=: ; u , v , , t ,&.>/ ;'-',&.>u
z=. ; 'thousand' ; (;:'m b tr quadr quint sext sept oct non'),&.> <'illion' u=. ;:'un duo tre quattuor quin sex septen octo novem' t=. (;:'dec vigint trigint quadragint quinquagint sexagint septuagint octogint nonagint'),&.><'illion' ENU=: z , (, t ,~&.>/ ;u) , <'centillion'
en3=: 4 : 0
'p q'=. 0 100#:y (p{::EN100),((*p)#' hundred'),((p*&*q)#x),q{::EN100
)
en=: 4 : 0
d=. 1000&#.^:_1 y assert. (0<:y) *. ((=<.)y) *. d <:&# ENU c=. x&en3&.> (*d)#d ((0=y)#'zero') , (-2+*{:d) }. ; , c,.(<' '),.(ENU{~I.&.|.*d),.<', '
)
uk=: ' and '&en NB. British us=: ' ' &en NB. American</lang>
Example: <lang> uk 123456789 one hundred and twenty-three million, four hundred and fifty-six thousand, seven hundred and eighty-nine
us 123456789
one hundred twenty-three million, four hundred fifty-six thousand, seven hundred eighty-nine
us 1234567890123456789012345678901234567890123456789012345678901234567890x
one duovigintillion, two hundred thirty-four unvigintillion, five hundred sixty-seven vigintillion, eight hundred ninety novemdecillion, one hundred twenty-three octodecillion, four hundred fifty-six septendecillion, seven hundred eighty-nine sexdecillion, twelve quindecillion, three hundred forty-five quattuordecillion, six hundred seventy-eight tredecillion, nine hundred one duodecillion, two hundred thirty-four undecillion, five hundred sixty-seven decillion, eight hundred ninety nonillion, one hundred twenty-three octillion, four hundred fifty-six septillion, seven hundred eighty-nine sextillion, twelve quintillion, three hundred forty-five quadrillion, six hundred seventy-eight trillion, nine hundred one billion, two hundred thirty-four million, five hundred sixty-seven thousand, eight hundred ninety</lang>
Java
<lang java>public class Int2Words {
static String[] small = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"}; static String[] tens = {"twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"}; static String[] big = {"thousand", "million", "billion", "trillion"};
public static void main(String[] args) { System.out.println(int2Text(900000001)); System.out.println(int2Text(1234567890)); System.out.println(int2Text(-987654321)); System.out.println(int2Text(0)); }
public static String int2Text(long number) { long num = 0; String outP = ""; int unit = 0; long tmpLng1 = 0;
if (number == 0) { return "zero"; }
num = Math.abs(number);
for (;;) { tmpLng1 = num % 100; if (tmpLng1 >= 1 && tmpLng1 <= 19) { outP = small[(int) tmpLng1 - 1] + " " + outP; } else if (tmpLng1 >= 20 && tmpLng1 <= 99) { if (tmpLng1 % 10 == 0) { outP = tens[(int) (tmpLng1 / 10) - 2] + " " + outP; } else { outP = tens[(int) (tmpLng1 / 10) - 2] + "-" + small[(int) (tmpLng1 % 10) - 1] + " " + outP; } }
tmpLng1 = (num % 1000) / 100; if (tmpLng1 != 0) { outP = small[(int) tmpLng1 - 1] + " hundred " + outP; }
num /= 1000; if (num == 0) { break; }
tmpLng1 = num % 1000; if (tmpLng1 != 0) { outP = big[unit] + " " + outP; } unit++; }
if (number < 0) { outP = "negative " + outP; }
return outP.trim(); }
}</lang> Output:
nine hundred million one one billion two hundred thirty-four million five hundred sixty-seven thousand eight hundred ninety negative nine hundred eighty-seven million six hundred fifty-four thousand three hundred twenty-one zero
Logo
<lang logo> make "numbers {one two three four five six seven eight nine ten
eleven twelve thirteen fourteen fifteen sixteen seventeen eighteen nineteen}
make "tens {twenty thirty forty fifty sixty seventy eighty ninety}@2
make "thou [[] thousand million billion trillion] ; expand as desired
to to.english.thou :n :thou
if :n = 0 [output []] if :n < 20 [output sentence item :n :numbers first :thou] if :n < 100 [output (sentence item int :n/10 :tens to.english.thou modulo :n 10 [[]] first :thou)] if :n < 1000 [output (sentence item int :n/100 :numbers "hundred to.english.thou modulo :n 100 [[]] first :thou)] output (sentence to.english.thou int :n/1000 butfirst :thou to.english.thou modulo :n 1000 :thou)
end
to to.english :n
if :n = 0 [output "zero] if :n > 0 [output to.english.thou :n :thou] [output sentence "negative to.english.thou minus :n :thou]
end
print to.english 1234567 ; one million two hundred thirty four thousand five hundred sixty seven </lang>
Lua
<lang lua> words = {"one ", "two ", "three ", "four ", "five ", "six ", "seven ", "eight ", "nine "} levels = {"thousand ", "million ", "billion ", "trillion ", "quadrillion ", "quintillion ", "sextillion ", "septillion ", "octillion ", [0] = ""} iwords = {"ten ", "twenty ", "thirty ", "forty ", "fifty ", "sixty ", "seventy ", "eighty ", "ninety "} twords = {"eleven ", "twelve ", "thirteen ", "fourteen ", "fifteen ", "sixteen ", "seventeen ", "eighteen ", "nineteen "}
function digits(n)
local i, ret = -1 return function() i, ret = i + 1, n % 10
if n > 0 then
n = math.floor(n / 10)
return i, ret end
end
end
level = false function getname(pos, dig) --stateful, but effective.
level = level or pos % 3 == 0 if(dig == 0) then return "" end local name = (pos % 3 == 1 and iwords[dig] or words[dig]) .. (pos % 3 == 2 and "hundred " or "") if(level) then name, level = name .. levels[math.floor(pos / 3)], false end return name
end
local val, vword = io.read() + 0, ""
for i, v in digits(val) do
vword = getname(i, v) .. vword
end
for i, v in ipairs(words) do
vword = vword:gsub("ty " .. v, "ty-" .. v) vword = vword:gsub("ten " .. v, twords[i])
end
if #vword == 0 then print "zero" else print(vword) end </lang>
MAXScript
This example isn't a very succinct way to solve the problem, but the way it works should be quite obvious. The function will work for values up to 1000 <lang MAXScript>fn NumberToWord myNum = ( local Result = "" while myNum != 0 do ( Result += case of ( (myNum >= 1000):(myNum -= 1000; "one thousand") (myNum > 900): (myNum -= 900 ; "nine hundred and") (myNum == 900): (myNum -= 900 ; "nine hundred") (myNum > 800): (myNum -= 800 ; "eight hundred and") (myNum == 800): (myNum -= 900 ; "eight hundred") (myNum > 700): (myNum -= 700 ; "seven hundred and") (myNum == 700): (myNum -= 900 ; "seven hundred") (myNum > 600): (myNum -= 600 ; "six hundred and") (myNum == 600): (myNum -= 900 ; "six hundred") (myNum > 500): (myNum -= 500 ; "five hundred and") (myNum == 500): (myNum -= 900 ; "five hundred") (myNum > 400): (myNum -= 400 ; "four hundred and") (myNum == 400): (myNum -= 900 ; "four hundred") (myNum > 300): (myNum -= 300 ; "three hundred and") (myNum == 300): (myNum -= 900 ; "three hundred") (myNum > 200): (myNum -= 200 ; "two hundred and") (myNum == 200): (myNum -= 900 ; "two hundred") (myNum > 100): (myNum -= 100 ; "one hundred and") (myNum == 100): (myNum -= 100 ; "one hundred") (myNum >= 90): (myNum -= 90 ; "ninety") (myNum >= 80): (myNum -= 80 ; "eighty") (myNum >= 70): (myNum -= 70 ; "seventy") (myNum >= 60): (myNum -= 60 ; "sixty") (myNum >= 50): (myNum -= 50 ; "fifty") (myNum >= 40): (myNum -= 40 ; "fourty") (myNum >= 30): (myNum -= 30 ; "thirty") (myNum >= 20): (myNum -= 20 ; "twenty") (myNum >= 19): (myNum -= 19 ; "nineteen") (myNum >= 18): (myNum -= 18 ; "eighteen") (myNum >= 17): (myNum -= 17 ; "seventeen") (myNum >= 16): (myNum -= 16 ; "sixteen") (myNum >= 15): (myNum -= 15 ; "fifteen") (myNum >= 14): (myNum -= 14 ; "fourteen") (myNum >= 13): (myNum -= 13 ; "thirteen") (myNum >= 12): (myNum -= 12 ; "twelve") (myNum >= 11): (myNum -= 11 ; "eleven") (myNum >= 10): (myNum -= 10 ; "ten") (myNum >= 9): (myNum -= 9 ; "nine") (myNum >= 8): (myNum -= 8 ; "eight") (myNum >= 7): (myNum -= 7 ; "seven") (myNum >= 6): (myNum -= 6 ; "six") (myNum >= 5): (myNum -= 5 ; "five") (myNum >= 4): (myNum -= 4 ; "four") (myNum >= 3): (myNum -= 3 ; "three") (myNum >= 2): (myNum -= 2 ; "two") (myNum >= 1): (myNum -= 1 ; "one") ) if myNum != 0 then result += " " ) result )</lang>
Example: <lang MAXScript>NumberToWord(123)</lang>
OCaml
<lang ocaml>let div_mod n d = (n / d, n mod d) let join = String.concat ", " ;;
let rec nonzero = function
| _, 0 -> "" | c, n -> c ^ (spell_integer n)
and tens n =
[| ""; ""; "twenty"; "thirty"; "forty"; "fifty"; "sixty"; "seventy"; "eighty"; "ninety" |].(n)
and small n =
[| "zero"; "one"; "two"; "three"; "four"; "five"; "six"; "seven"; "eight"; "nine"; "ten"; "eleven"; "twelve"; "thirteen"; "fourteen"; "fifteen"; "sixteen";"seventeen"; "eighteen"; "nineteen" |].(n)
and bl = [| ""; ""; "m"; "b"; "tr"; "quadr"; "quint";
"sext"; "sept"; "oct"; "non"; "dec" |]
and big = function
| 0, n -> (spell_integer n) | 1, n -> (spell_integer n) ^ " thousand" | e, n -> (spell_integer n) ^ " " ^ bl.(e) ^ "illion"
and uff acc = function
| 0 -> List.rev acc | n -> let a, b = div_mod n 1000 in uff (b::acc) a
and spell_integer = function
| n when n < 0 -> invalid_arg "spell_integer: negative input" | n when n < 20 -> small n | n when n < 100 -> let a, b = div_mod n 10 in (tens a) ^ nonzero("-", b) | n when n < 1000 -> let a, b = div_mod n 100 in (small a) ^ " hundred" ^ nonzero(" ", b) | n -> let seg = (uff [] n) in let _, segn = (* just add the index of the item in the list *) List.fold_left (fun (i,acc) v -> (succ i, (i,v)::acc)) (0,[]) seg in let fsegn = (* remove right part "zero" *) List.filter (function (_,0) -> false | _ -> true) segn in join(List.map big fsegn)
- </lang>
PARI/GP
<lang>Eng(n:int)={ my(tmp,s=""); if (n >= 1000000, tmp = n\1000000; s = Str(Eng(tmp), " million"); n -= tmp * 1000000; if (!n, return(s)); s = Str(s, " ") ); if (n >= 1000, tmp = n\1000; s = Str(Eng(tmp), " thousand"); n -= tmp * 1000; if (!n, return(s)); s = Str(s, " ") ); if (n >= 100, tmp = n\100; s = Str(Edigit(tmp), " hundred"); n -= tmp * 100; if (!n, return(s)); s = Str(s, " ") ); if (n < 20, return (Str(s, ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "ninteen"][n])) ); tmp = n\10; s = Str(s, [0, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"][tmp]); n -= tmp * 10; if (n, Str(s, "-", Edigit(n)), s) }; Edigit(n)={ ["one", "two", "three", "four", "five", "six", "seven", "eight", "nine"][n] };</lang>
Perl
<lang perl>use Lingua::EN::Numbers 'num2en';
print num2en(123456789), "\n";</lang>
PHP
<lang php>$orderOfMag = array("Hundred", "Thousand,", "Million,", "Billion,", "Trillion,"); $smallNumbers = array("Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"); $decades = array("", "", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety");
function NumberToEnglish($num, $count = 0){
global $orderOfMag, $smallNumbers, $decades; $isLast = true; $str = "";
if ($num < 0){ $str = "Negative "; $num = abs($num); }
(int) $thisPart = substr((string) $num, -3);
if (strlen((string) $num) > 3){ // Number still too big, work on a smaller chunk $str .= NumberToEnglish((int) substr((string) $num, 0, strlen((string) $num) - 3), $count + 1); $isLast = false; }
// do translation stuff if (($count == 0 || $isLast) && ($str == "" || $str == "Negative ")) // This is either a very small number or the most significant digits of the number. Either way we don't want a preceeding "and" $and = ""; else $and = " and ";
if ($thisPart > 99){ // Hundreds part of the number chunk $str .= ($isLast ? "" : " ") . "{$smallNumbers[$thisPart/100]} {$orderOfMag[0]}";
if(($thisPart %= 100) == 0){ // There is nothing else to do for this chunk (was a multiple of 100) $str .= " {$orderOfMag[$count]}"; return $str; } $and = " and "; // Set up our and string to the word "and" since there is something in the hundreds place of this chunk }
if ($thisPart >= 20){ // Tens part of the number chunk $str .= "{$and}{$decades[$thisPart /10]}"; $and = " "; // Make sure we don't have any extranious "and"s if(($thisPart %= 10) == 0) return $str . ($count != 0 ? " {$orderOfMag[$count]}" : ""); }
if ($thisPart < 20 && $thisPart > 0) // Ones part of the number chunk return $str . "{$and}{$smallNumbers[(int) $thisPart]} " . ($count != 0 ? $orderOfMag[$count] : ""); elseif ($thisPart == 0 && strlen($thisPart) == 1) // The number is zero return $str . "{$smallNumbers[(int)$thisPart]}";
}</lang> Example: <lang>NumberToEnglish(0); NumberToEnglish(12); NumberToEnglish(123); NumberToEnglish(1234567890123); NumberToEnglish(65535); NumberToEnglish(-54321);</lang> Returns: <lang>Zero Twelve One Hundred and Twenty Three One Trillion, Two Hundred and Thirty Four Billion, Five Hundred and Sixty Seven Million, Eight Hundred and Ninety Thousand, One Hundred and Twenty Three Sixty Five Thousand, Five Hundred and Thirty Five Negative Fifty Four Thousand, Three Hundred and Twenty One</lang>
PicoLisp
<lang PicoLisp>(de numName (N)
(cond ((=0 N) "zero") ((lt0 N) (pack "minus " (numName (- N)))) (T (numNm N)) ) )
(de numNm (N)
(cond ((=0 N)) ((> 14 N) (get '("one" "two" "three" "four" "five" "six" "seven" "eight" "nine" "ten" "eleven" "twelve" "thirteen") N) ) ((= 15 N) "fifteen") ((= 18 N) "eighteen") ((> 20 N) (pack (numNm (% N 10)) "teen")) ((> 100 N) (pack (get '("twen" "thir" "for" "fif" "six" "seven" "eigh" "nine") (dec (/ N 10))) "ty" (unless (=0 (% N 10)) (pack "-" (numNm (% N 10))) ) ) ) ((rank N '((100 . "hundred") (1000 . "thousand") (1000000 . "million"))) (pack (numNm (/ N (car @))) " " (cdr @) " " (numNm (% N (car @)))) ) ) )</lang>
PL/I
<lang PL/I>
declare integer_names (0:20) character (9) varying static initial ('zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty' ); declare x(10) character (7) varying static initial ('ten', 'twenty', 'thirty', 'fourty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety', 'hundred'); declare y(0:5) character (10) varying static initial (, , ' thousand ', ' million ', ' billion ', ' trillion '); declare (i, j, m, t) fixed binary (31); declare (units, tens, hundreds, thousands) fixed binary (7); declare (h, v, value) character (200) varying; declare (d, k, n) fixed decimal (15); declare three_digits fixed decimal (3);
value = ; i = 5; k = n; do d = 1000000000000 repeat d/1000 while (d > 0); i = i - 1; three_digits = k/d; k = mod(k, d); if three_digits = 0 then iterate;
units = mod(three_digits, 10); t = three_digits / 10; tens = mod(t, 10); hundreds = three_digits / 100; m = mod(three_digits, 100); if m <= 20 then v = integer_names(m); else if units = 0 then v = ; else v = integer_names(units); if tens >= 2 & units ^= 0 then v = x(tens) || v; else if tens > 2 & units = 0 then v = v || x(tens);
if units + tens = 0 then if n > 0 then v = ; if hundreds > 0 then h = integer_names(hundreds) || ' hundred '; else h = ; if three_digits > 100 & (tens + units > 0) then v = 'and ' || v; if i = 1 & value ^= & three_digits <= 9 then v = 'and ' || v; value = value ||h || v || y(i); end; put skip edit (trim(N), ' = ', value) (a);
</lang>
PowerBASIC
Note that the PB compiler seems to have some bugs related to the QUAD
data type; see the sample output below the code.
<lang powerbasic>FUNCTION int2Text (number AS QUAD) AS STRING
IF 0 = number THEN FUNCTION = "zero" EXIT FUNCTION END IF
DIM num AS QUAD, outP AS STRING, unit AS LONG DIM tmpLng1 AS QUAD
DIM small(1 TO 19) AS STRING, tens(7) AS STRING, big(5) AS STRING
DIM tmpInt AS LONG, dcnt AS LONG
ARRAY ASSIGN small() = "one", "two", "three", "four", "five", "six", _ "seven", "eight", "nine", "ten", "eleven", _ "twelve", "thirteen", "fourteen", "fifteen", _ "sixteen", "seventeen", "eighteen", "nineteen" ARRAY ASSIGN tens() = "twenty", "thirty", "forty", "fifty", "sixty", _ "seventy", "eighty", "ninety" ARRAY ASSIGN big() = "thousand", "million", "billion", "trillion", _ "quadrillion", "quintillion"
num = ABS(number)
DO tmpLng1 = num MOD 100 SELECT CASE tmpLng1 CASE 1 TO 19 outP = small(tmpLng1) + " " + outP CASE 20 TO 99 SELECT CASE tmpLng1 MOD 10 CASE 0 outP = tens((tmpLng1 \ 10) - 2) + " " + outP CASE ELSE outP = tens((tmpLng1 \ 10) - 2) + "-" + small(tmpLng1 MOD 10) + " " + outP END SELECT END SELECT
tmpLng1 = (num MOD 1000) \ 100 IF tmpLng1 THEN outP = small(tmpLng1) + " hundred " + outP END IF
num = num \ 1000 IF num < 1 THEN EXIT DO
tmpLng1 = num MOD 1000 IF tmpLng1 THEN outP = big(unit) + " " + outP
unit = unit + 1 LOOP
IF number < 0 THEN outP = "negative " + outP
FUNCTION = RTRIM$(outP)
END FUNCTION
FUNCTION PBMAIN () AS LONG
DIM n AS QUAD
#IF %DEF(%PB_CC32) INPUT "Gimme a number! ", n #ELSE n = VAL(INPUTBOX$("Gimme a number!", "Now!")) #ENDIF ? int2Text(n)
END FUNCTION</lang>
Sample output:
Gimme a number! 1111111111111111111 one quintillion one hundred eleven quadrillion one hundred eleven trillion one h undred eleven billion one hundred eleven million one hundred eleven thousand one hundred ten
PureBasic
The range of integers handled has been set at an obscene 45 digits. <lang PureBasic>DataSection
numberNames: ;small Data.s "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten" Data.s "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" ;tens Data.s "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" ;big, non-Chuquet system Data.s "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion" Data.s "septillion", "octillion", "nonillion", "decillion", "undecillion", "duodecillion" Data.s "tredecillion"
EndDataSection
Procedure.s numberWords(number.s)
;handles integers from -1E45 to +1E45 Static isInitialized = #False Static Dim small.s(19) Static Dim tens.s(9) Static Dim big.s(14) If Not isInitialized Restore numberNames For i = 1 To 19 Read.s small(i) Next For i = 2 To 9 Read.s tens(i) Next For i = 1 To 14 Read.s big(i) Next isInitialized = #True EndIf For i = 1 To Len(number) If Not FindString("- 0123456789", Mid(number,i,1), 1) number = Left(number, i - 1) ;trim number to the last valid character Break ;exit loop EndIf Next Protected IsNegative = #False number = Trim(number) If Left(number,1) = "-" IsNegative = #True number = Trim(Mid(number, 2)) EndIf If CountString(number, "0") = Len(number) ProcedureReturn "zero" EndIf If Len(number) > 45 ProcedureReturn "Number is too big!" EndIf Protected num.s = number, output.s, unit, unitOutput.s, working Repeat working = Val(Right(num, 2)) unitOutput = "" Select working Case 1 To 19 unitOutput = small(working) Case 20 To 99 If working % 10 unitOutput = tens(working / 10) + "-" + small(working % 10) Else unitOutput = tens(working / 10) EndIf EndSelect working = Val(Right(num, 3)) / 100 If working If unitOutput <> "" unitOutput = small(working) + " hundred " + unitOutput Else unitOutput = small(working) + " hundred" EndIf EndIf If unitOutput <> "" And unit > 0 unitOutput + " " + big(unit) If output <> "" unitOutput + ", " EndIf EndIf output = unitOutput + output If Len(num) > 3 num = Left(num, Len(num) - 3) unit + 1 Else Break ;exit loop EndIf ForEver If IsNegative output = "negative " + output EndIf ProcedureReturn output
EndProcedure
Define n$ If OpenConsole()
Repeat Repeat Print("Give me an integer (or q to quit)! ") n$ = Input() Until n$ <> "" If Left(Trim(n$),1) = "q" Break ;exit loop EndIf PrintN(numberWords(n$)) ForEver CloseConsole()
EndIf </lang> Sample output:
Give me an integer (or q to quit)! 3 three Give me an integer (or q to quit)! -1327 negative one thousand, three hundred twenty-seven Give me an integer (or q to quit)! 0 zero Give me an integer (or q to quit)! 100000000002000000000000000300000000000000004 one hundred tredecillion, two decillion, three hundred quadrillion, four
Python
<lang python>def spell_integer(n):
tens = [None, None, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
bl = [None, None, "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", "dec"]
def nonzero(c, n): return "" if n == 0 else c + spell_integer(n)
def big(e, n): if e == 0: return spell_integer(n) elif e == 1: return spell_integer(n) + " thousand" else: return spell_integer(n) + " " + bl[e] + "illion"
def base1000_rev(n): # generates the value of the digits of n in base 1000 # (i.e. 3-digit chunks), in reverse. while n != 0: n, r = divmod(n, 1000) yield r
if n < 0: raise ValueError, "spell_integer: negative input" elif n < 20: return small[n] elif n < 100: a, b = divmod(n, 10) return tens[a] + nonzero("-", b) elif n < 1000: a, b = divmod(n, 100) return small[a] + " hundred" + nonzero(" ", b) else: return ", ".join([big(e, x) for e, x in enumerate(base1000_rev(n)) if x][::-1])
- example
print spell_integer(1278) print spell_integer(1752) print spell_integer(2010) </lang>
one thousand, two hundred seventy-eight one thousand, seven hundred fifty-two two thousand, ten
REXX
As I understand the task's parameters, it was OK to used a pre-existing program to solve this task. I had first considered taking the original program and ripping out all the good stuff and just solve the primary task (and optional requirements), but it was taking too much time so I left the program intact, negated the use of the $T program (which essentially is a TYPE command that can show text in colors, does vertical and horizontal [indentation] tabbing, boxing, centering/justification, and writing the output to a file, waits on confirmation, block letters, splitting of message text [multiple lines], highlighting of text portions [in colors], among other things). Also not included is the $H program which shows (among other things) the help (documentation), and the $ERR program which issues error messages (in red). I assume that most people could figure out what the error message(s) would be by observing the context. This REXX program supports: * long & short scale (American and British styles) * ordinal numbers and cardinal numbers * expressing the number as a YEAR (1975 would be nineteen seventy-five) * decimal points (6 is different than 6.) * decimal fractions * numbers with leading zeroes (as well as trailing zeroes) * leading signs (+ or -) * exponential notation * currency symbols * adding commas (or whatever) to the output (including blanks) * numbers (American) up to 3,000 digits, (English) up to 6,000 digits * numbers with suffixes such as K, M, Gi, etc, and also some common ones as well as factorials * user-defineable names for: signs, decimal point, power, curreny symbols, zero (digit), etc. The program has a pretty hefty prologue which determines (among other things): * the operating system (and maybe the type) * the name of the REXX program: it's filename, filetype, filemode (or path, if you will) * the access-name to acquire environmental variables * if EBCDIC or ASCII system * which REXX (or KEXX) is being used * the name of the program (command) to clear the terminal screen * if appropriate, invokes $H to show the help/logic flow/sample uses/or program author If there are strong feelings that the code should be removed because of it's length, I'll remove it. I'm still working on the program to reduce the amount of names by programatically generating any number of names (instead of having a fixed amount of names in text form). Also note that there appears not to be a consensus on the names of some numbers: nonillion is also called noventillion noven* are also named novem* septen* are also named septem* ses* are also named sex* tre* are also named tres*
REXX program
/**/trace o;parse arg !;if !all(arg()) then exit;if !cms then address '';signal on halt;signal on novalue;signal on syntax @abc='abcdefghijklmnopqrstuvwxyz' american=0 andcent='and' asayear=0 asis=0 blanks= british=0 cent='cent' clear=0 colors=!cms | !pcrexx | !r4 | !roo dollar='dollar' dot= english=0 euro='euro' exponents= fractions= franc='franc' leading= leadingz= logs=0 minus='minus ' n= nothing='zero' ops=space(!!) ordinal=0 piseta='piseta' plus='plus ' point='point' pound='pound' power='power' quiet=0 raised='times ten raised to the' sep='none' single=0 tfid= /*temporary file id. */ tops= xcurr= yen='yen' zero='oh' do while ops\=='' /*process user arguments & options*/ parse var ops _1 2 1 _ . 1 _o ops upper _ select when isnum(_) then n=n||_ when _==',' | _=="(" | _==')' then nop when _1=='.' & pos("=",_)\==0 then tops=tops _o when abbn('AMERican') then american=no() when abbn('ASAYEAR')|, abbn('ASYEAR')|, abbn('YEAR') then asayear=no() when abb('BEINGRAISed')|, abb('RAISEd') then raised=na() when abb('BLANKs') then blanks=na() when abbn('BRITish') then british=no() when abb('CENTs') then cent=na() when abbn('CLearscreen') then clear=no() when abbn('COLORs') then colors=no() when abb('DECIMALpoints')|, abb('DOLLARs') then dollar=na() when abbn('ENGlish') then english=no() when abb('EUROs') then euro=na() when abb('FRANCs') then franc=na() when abb('LEADINGzeroes')|, abb('LEADINGzeros') then leading=na() when abbn('LOGs') then logs=no() when abb('MINUSsigns')|, abb('MINUSes') then minus=na()' ' when abb('NOTHINGs') then nothing=na() when abbn('ORDinal') then ordinal=no() when abb('PISETAs') then piseta=na() when abb('POWer') then power=na() when abb('PLUSsigns')|, abb('PLUSes') then plus=na()' ' when abb('POINTs') then point=na() when abb('POUNDs') then pound=na() when abbn('Quiet') then quiet=no() when abb('SEPerators') then sep=na() when abbn('SINGley') then single=no() when abb('YENs') then yen=na() when abb('ZEROs')|, abb('ZEROes') then zero=na() otherwise n=n||_o end end if sep=='none' then if pos(',',n)\==0 then sep=',' if sep=='none' then sep= ogn=n /* original number that was entered*/ _=blanks /* validate BLANKS= option.*/ l=length(_) if l>3 then call er 55,_ if l==3 then do /* decimal value.*/ if \isint(_) then call er 92,_ "BLANK=" if _<0|_>255 then call er 81,0 255 _ "BLANKS=" blanks=d2c(_) end if l==2 then do /* hexadecimal value.*/ if \ishex(_) then call er 40,_ blanks=x2c(_) end if colors then tops='.P=1 .A=1 .C=green' tops /*colors used by $T.*/ if logs then tops='.F='gettfid(,"ANS") tops /*logfile used by $T.*/ tops=space(tops) /*options used by $T.*/ if n=='' then call er 54 if asayear & ordinal then call er 61,'ASAYEAR ORDINAL' if single & ordinal then call er 61,'SINGLEY ORDINAL' if american & english then call er 61,'AMERICAN ENGLISH' if american & british then call er 61,'AMERICAN BRITISH' if \american & \english & \british then american=1 if english then british=1 if clear then !cls /*clear the screen ? */ dig.=;dig.0=zero;dig.1='one';dig.2='two';dig.3='three';dig.4='four';dig.5='five';dig.6='six';dig.7='seven';dig.8='eight';dig.9='nine' _='0 thousand m b tr quadr quint sext sept oct non dec undec duodec tredec quattuordec quinquadec sedec septendec octodec novendec vigin unvigin duovigin tresvigin quattuorvigin quinquavigin sesvigin septemvigin octovigin novemvigin trigin' _=_ 'untrigin duotrigin trestrigin quattuortrigin quinquatrigin sestrigin septentrigin octotrigin noventrigin quadragin unquadragin duoquadragin tresquadragin quattuorquadragin quinquaquadragin sesquadragin septenquadragin octoquadragin' _=_ 'novenquadragin quinquagin unquinquagin duoquinquagin tresquinquagin quattuorquinquagin quinquaquinquagin sesquinquagin septenquinquagin octoquinquagin novenquinquagin sexagin unsexagin duosexagin tresexagin quattuorsexagin quinquasexagin' _=_ 'sesexagin septensexagin octosexagin novensexagin septuagin unseptuagin duoseptuagin treseptuagin quattuorseptuagin quinquaseptuagin seseptuagin septenseptuagin octoseptuagin novenseptuagin octogin unoctogin duooctogin tresoctogin' _=_ 'quattuoroctogin quinquaoctogin sexoctogin septemoctogin octooctogin novemoctogin nonagin unnonagin duononagin trenonagin quattuornonagin quinquanonagin senonagin septenonagin octononagin novenonagin cen uncen duocen trescen quattuorcen' _=_ 'quinquacen sexcen septencen octocen novencen decicen undecicen duodecicen tredecicen quattuordecicen quinquadecicen sedecicen septendecicen octodecicen novendecicen viginticen unviginticen duoviginticen tresviginticen quattuorviginticen' _=_ 'quinquaviginticen sesviginticen septemviginticen octoviginticen novemviginticen trigintacen untrigintacen duotrigintacen trestrigintacen quattuortrigintacen quinquatrigintacen sestrigintacen septentrigintacen octotrigintacen' _=_ 'noventrigintacen quadragintacen unquadragintacen duoquadragintacen tresquadragintacen quattuorquadragintacen quinquaquadragintacen sesquadragintacen septenquadragintacen octoquadragintacen novenquadragintacen quinquagintacen' _=_ 'unquinquagintacen duoquinquagintacen tresquinquagintacen quattuorquinquagintacen quinquaquinquagintacen sesquinquagintacen septenquinquagintacen octoquinquagintacen novenquinquagintacen sexagintacen unsexagintacen duosexagintacen' _=_ 'tresexagintacen quattuorsexagintacen quinquasexagintacen sesexagintacen septensexagintacen octosexagintacen novensexagintacen septuagintacen unseptuagintacen duoseptuagintacen treseptuagintacen quattuorseptuagintacen quinquaseptuagintacen' _=_ 'seseptuagintacen septenseptuagintacen octoseptuagintacen novenseptuagintacen octogintacen unoctogintacen duooctogintacen tresoctogintacen quattuoroctogintacen quinquaoctogintacen sexoctogintacen septemoctogintacen octooctogintacen' _=_ 'novemoctogintacen nonagintacen unnonagintacen duononagintacen trenonagintacen quattuornonagintacen quinquanonagintacen senonagintacen septenonagintacen octononagintacen novenonagintacen ducen unducen duoducen treducen quattuorducen' _=_ 'quinquaducen seducen septenducen octoducen novenducen deciducen undeciducen duodeciducen tredeciducen quattuordeciducen quinquadeciducen sedeciducen septendeciducen octodeciducen novendeciducen vigintiducen unvigintiducen duovigintiducen' _=_ 'tresvigintiducen quattuorvigintiducen quinquavigintiducen sesvigintiducen septemvigintiducen octovigintiducen novemvigintiducen trigintaducen untrigintaducen duotrigintaducen trestrigintaducen quattuortrigintaducen quinquatrigintaducen' _=_ 'sestrigintaducen septentrigintaducen octotrigintaducen noventrigintaducen quadragintaducen unquadragintaducen duoquadragintaducen tresquadragintaducen quattuorquadragintaducen quinquaquadragintaducen sesquadragintaducen' _=_ 'septenquadragintaducen octoquadragintaducen novenquadragintaducen quinquagintaducen unquinquagintaducen duoquinquagintaducen tresquinquagintaducen quattuorquinquagintaducen quinquaquinquagintaducen sesquinquagintaducen' _=_ 'septenquinquagintaducen octoquinquagintaducen novenquinquagintaducen sexagintaducen unsexagintaducen duosexagintaducen tresexagintaducen quattuorsexagintaducen quinquasexagintaducen sesexagintaducen septensexagintaducen octosexagintaducen' _=_ 'novensexagintaducen septuagintaducen unseptuagintaducen duoseptuagintaducen treseptuagintaducen quattuorseptuagintaducen quinquaseptuagintaducen seseptuagintaducen septenseptuagintaducen octoseptuagintaducen novenseptuagintaducen' _=_ 'octogintaducen unoctogintaducen duooctogintaducen tresoctogintaducen quattuoroctogintaducen quinquaoctogintaducen sexoctogintaducen septemoctogintaducen octooctogintaducen novemoctogintaducen nonagintaducen unnonagintaducen' _=_ 'duononagintaducen trenonagintaducen quattuornonagintaducen quinquanonagintaducen senonagintaducen septenonagintaducen octononagintaducen novenonagintaducen trecen untrecen duotrecen trestrecen quattuortrecen quinquatrecen sestrecen' _=_ 'septentrecen octotrecen noventrecen decitrecen undecitrecen duodecitrecen tredecitrecen quattuordecitrecen quinquadecitrecen sedecitrecen septendecitrecen octodecitrecen novendecitrecen vigintitrecen unvigintitrecen duovigintitrecen' _=_ 'tresvigintitrecen quattuorvigintitrecen quinquavigintitrecen sesvigintitrecen septemvigintitrecen octovigintitrecen novemvigintitrecen trigintatrecen untrigintatrecen duotrigintatrecen trestrigintatrecen quattuortrigintatrecen' _=_ 'quinquatrigintatrecen sestrigintatrecen septentrigintatrecen octotrigintatrecen noventrigintatrecen quadragintatrecen unquadragintatrecen duoquadragintatrecen tresquadragintatrecen quattuorquadragintatrecen quinquaquadragintatrecen' _=_ 'sesquadragintatrecen septenquadragintatrecen octoquadragintatrecen novenquadragintatrecen quinquagintatrecen unquinquagintatrecen duoquinquagintatrecen tresquinquagintatrecen quattuorquinquagintatrecen quinquaquinquagintatrecen' _=_ 'sesquinquagintatrecen septenquinquagintatrecen octoquinquagintatrecen novenquinquagintatrecen sexagintatrecen unsexagintatrecen duosexagintatrecen tresexagintatrecen quattuorsexagintatrecen quinquasexagintatrecen sesexagintatrecen' _=_ 'septensexagintatrecen octosexagintatrecen novensexagintatrecen septuagintatrecen unseptuagintatrecen duoseptuagintatrecen treseptuagintatrecen quattuorseptuagintatrecen quinquaseptuagintatrecen seseptuagintatrecen septenseptuagintatrecen' _=_ 'octoseptuagintatrecen novenseptuagintatrecen octogintatrecen unoctogintatrecen duooctogintatrecen tresoctogintatrecen quattuoroctogintatrecen quinquaoctogintatrecen sexoctogintatrecen septemoctogintatrecen octooctogintatrecen' _=_ 'novemoctogintatrecen nonagintatrecen unnonagintatrecen duononagintatrecen trenonagintatrecen quattuornonagintatrecen quinquanonagintatrecen senonagintatrecen septenonagintatrecen octononagintatrecen novenonagintatrecen quadringen' _=_ 'unquadringen duoquadringen tresquadringen quattuorquadringen quinquaquadringen sesquadringen septenquadringen octoquadringen novenquadringen deciquadringen undeciquadringen duodeciquadringen tredeciquadringen quattuordeciquadringen' _=_ 'quinquadeciquadringen sedeciquadringen septendeciquadringen octodeciquadringen novendeciquadringen vigintiquadringen unvigintiquadringen duovigintiquadringen tresvigintiquadringen quattuorvigintiquadringen quinquavigintiquadringen' _=_ 'sesvigintiquadringen septemvigintiquadringen octovigintiquadringen novemvigintiquadringen trigintaquadringen untrigintaquadringen duotrigintaquadringen trestrigintaquadringen quattuortrigintaquadringen quinquatrigintaquadringen' _=_ 'sestrigintaquadringen septentrigintaquadringen octotrigintaquadringen noventrigintaquadringen quadragintaquadringen unquadragintaquadringen duoquadragintaquadringen tresquadragintaquadringen quattuorquadragintaquadringen' _=_ 'quinquaquadragintaquadringen sesquadragintaquadringen septenquadragintaquadringen octoquadragintaquadringen novenquadragintaquadringen quinquagintaquadringen unquinquagintaquadringen duoquinquagintaquadringen tresquinquagintaquadringen' _=_ 'quattuorquinquagintaquadringen quinquaquinquagintaquadringen sesquinquagintaquadringen septenquinquagintaquadringen octoquinquagintaquadringen novenquinquagintaquadringen sexagintaquadringen unsexagintaquadringen duosexagintaquadringen' _=_ 'tresexagintaquadringen quattuorsexagintaquadringen quinquasexagintaquadringen sesexagintaquadringen septensexagintaquadringen octosexagintaquadringen novensexagintaquadringen septuagintaquadringen unseptuagintaquadringen' _=_ 'duoseptuagintaquadringen treseptuagintaquadringen quattuorseptuagintaquadringen quinquaseptuagintaquadringen seseptuagintaquadringen septenseptuagintaquadringen octoseptuagintaquadringen novenseptuagintaquadringen octogintaquadringen' _=_ 'unoctogintaquadringen duooctogintaquadringen tresoctogintaquadringen quattuoroctogintaquadringen quinquaoctogintaquadringen sexoctogintaquadringen septemoctogintaquadringen octooctogintaquadringen novemoctogintaquadringen' _=_ 'nonagintaquadringen unnonagintaquadringen duononagintaquadringen trenonagintaquadringen quattuornonagintaquadringen quinquanonagintaquadringen senonagintaquadringen septenonagintaquadringen octononagintaquadringen novenonagintaquadringen' _=_ 'quingen unquingen duoquingen tresquingen quattuorquingen quinquaquingen sesquingen septenquingen octoquingen novenquingen deciquingen undeciquingen duodeciquingen tredeciquingen quattuordeciquingen quinquadeciquingen sedeciquingen' _=_ 'septendeciquingen octodeciquingen novendeciquingen vigintiquingen unvigintiquingen duovigintiquingen tresvigintiquingen quattuorvigintiquingen quinquavigintiquingen sesvigintiquingen septemvigintiquingen octovigintiquingen' _=_ 'novemvigintiquingen trigintaquingen untrigintaquingen duotrigintaquingen trestrigintaquingen quattuortrigintaquingen quinquatrigintaquingen sestrigintaquingen septentrigintaquingen octotrigintaquingen noventrigintaquingen quadragintaquinge' _=_ 'unquadragintaquingen duoquadragintaquingen tresquadragintaquingen quattuorquadragintaquingen quinquaquadragintaquingen sesquadragintaquingen septenquadragintaquingen octoquadragintaquingen novenquadragintaquingen quinquagintaquingen' _=_ 'unquinquagintaquingen duoquinquagintaquingen tresquinquagintaquingen quattuorquinquagintaquingen quinquaquinquagintaquingen sesquinquagintaquingen septenquinquagintaquingen octoquinquagintaquingen novenquinquagintaquingen sexagintaquingen' _=_ 'unsexagintaquingen duosexagintaquingen tresexagintaquingen quattuorsexagintaquingen quinquasexagintaquingen sesexagintaquingen septensexagintaquingen octosexagintaquingen novensexagintaquingen septuagintaquingen unseptuagintaquingen' _=_ 'duoseptuagintaquingen treseptuagintaquingen quattuorseptuagintaquingen quinquaseptuagintaquingen seseptuagintaquingen septenseptuagintaquingen octoseptuagintaquingen novenseptuagintaquingen octogintaquingen unoctogintaquingen' _=_ 'duooctogintaquingen tresoctogintaquingen quattuoroctogintaquingen quinquaoctogintaquingen sexoctogintaquingen septemoctogintaquingen octooctogintaquingen novemoctogintaquingen nonagintaquingen unnonagintaquingen duononagintaquingen' _=_ 'trenonagintaquingen quattuornonagintaquingen quinquanonagintaquingen senonagintaquingen septenonagintaquingen octononagintaquingen novenonagintaquingen sescen unsescen duosescen tresescen quattuorsescen quinquasescen sesescen septensescen' _=_ 'octosescen novensescen decisescen undecisescen duodecisescen tredecisescen quattuordecisescen quinquadecisescen sedecisescen septendecisescen octodecisescen novendecisescen vigintisescen unvigintisescen duovigintisescen tresvigintisescen' _=_ 'quattuorvigintisescen quinquavigintisescen sesvigintisescen septemvigintisescen octovigintisescen novemvigintisescen trigintasescen untrigintasescen duotrigintasescen trestrigintasescen quattuortrigintasescen quinquatrigintasescen' _=_ 'sestrigintasescen septentrigintasescen octotrigintasescen noventrigintasescen quadragintasescen unquadragintasescen duoquadragintasescen tresquadragintasescen quattuorquadragintasescen quinquaquadragintasescen sesquadragintasescen' _=_ 'septenquadragintasescen octoquadragintasescen novenquadragintasescen quinquagintasescen unquinquagintasescen duoquinquagintasescen tresquinquagintasescen quattuorquinquagintasescen quinquaquinquagintasescen sesquinquagintasescen' _=_ 'septenquinquagintasescen octoquinquagintasescen novenquinquagintasescen sexagintasescen unsexagintasescen duosexagintasescen tresexagintasescen quattuorsexagintasescen quinquasexagintasescen sesexagintasescen septensexagintasescen' _=_ 'octosexagintasescen novensexagintasescen septuagintasescen unseptuagintasescen duoseptuagintasescen treseptuagintasescen quattuorseptuagintasescen quinquaseptuagintasescen seseptuagintasescen septenseptuagintasescen octoseptuagintasescen' _=_ 'novenseptuagintasescen octogintasescen unoctogintasescen duooctogintasescen tresoctogintasescen quattuoroctogintasescen quinquaoctogintasescen sexoctogintasescen septemoctogintasescen octooctogintasescen novemoctogintasescen nonagintasesce' _=_ 'unnonagintasescen duononagintasescen trenonagintasescen quattuornonagintasescen quinquanonagintasescen senonagintasescen septenonagintasescen octononagintasescen novenonagintasescen septingen unseptingen duoseptingen treseptingen' _=_ 'quattuorseptingen quinquaseptingen seseptingen septenseptingen octoseptingen novenseptingen deciseptingen undeciseptingen duodeciseptingen tredeciseptingen quattuordeciseptingen quinquadeciseptingen sedeciseptingen septendeciseptingen' _=_ 'octodeciseptingen novendeciseptingen vigintiseptingen unvigintiseptingen duovigintiseptingen tresvigintiseptingen quattuorvigintiseptingen quinquavigintiseptingen sesvigintiseptingen septemvigintiseptingen octovigintiseptingen' _=_ 'novemvigintiseptingen trigintaseptingen untrigintaseptingen duotrigintaseptingen trestrigintaseptingen quattuortrigintaseptingen quinquatrigintaseptingen sestrigintaseptingen septentrigintaseptingen octotrigintaseptingen' _=_ 'noventrigintaseptingen quadragintaseptingen unquadragintaseptingen duoquadragintaseptingen tresquadragintaseptingen quattuorquadragintaseptingen quinquaquadragintaseptingen sesquadragintaseptingen septenquadragintaseptingen' _=_ 'octoquadragintaseptingen novenquadragintaseptingen quinquagintaseptingen unquinquagintaseptingen duoquinquagintaseptingen tresquinquagintaseptingen quattuorquinquagintaseptingen quinquaquinquagintaseptingen sesquinquagintaseptingen' _=_ 'septenquinquagintaseptingen octoquinquagintaseptingen novenquinquagintaseptingen sexagintaseptingen unsexagintaseptingen duosexagintaseptingen tresexagintaseptingen quattuorsexagintaseptingen quinquasexagintaseptingen sesexagintaseptingen' _=_ 'septensexagintaseptingen octosexagintaseptingen novensexagintaseptingen septuagintaseptingen unseptuagintaseptingen duoseptuagintaseptingen treseptuagintaseptingen quattuorseptuagintaseptingen quinquaseptuagintaseptingen' _=_ 'seseptuagintaseptingen septenseptuagintaseptingen octoseptuagintaseptingen novenseptuagintaseptingen octogintaseptingen unoctogintaseptingen duooctogintaseptingen tresoctogintaseptingen quattuoroctogintaseptingen quinquaoctogintaseptingen' _=_ 'sexoctogintaseptingen septemoctogintaseptingen octooctogintaseptingen novemoctogintaseptingen nonagintaseptingen unnonagintaseptingen duononagintaseptingen trenonagintaseptingen quattuornonagintaseptingen quinquanonagintaseptingen' _=_ 'senonagintaseptingen septenonagintaseptingen octononagintaseptingen novenonagintaseptingen octingen unoctingen duooctingen tresoctingen quattuoroctingen quinquaoctingen sexoctingen septemoctingen octooctingen novemoctingen decioctingen' _=_ 'undecioctingen duodecioctingen tredecioctingen quattuordecioctingen quinquadecioctingen sedecioctingen septendecioctingen octodecioctingen novendecioctingen vigintioctingen unvigintioctingen duovigintioctingen tresvigintioctingen' _=_ 'quattuorvigintioctingen quinquavigintioctingen sesvigintioctingen septemvigintioctingen octovigintioctingen novemvigintioctingen trigintaoctingen untrigintaoctingen duotrigintaoctingen trestrigintaoctingen quattuortrigintaoctingen' _=_ 'quinquatrigintaoctingen sestrigintaoctingen septentrigintaoctingen octotrigintaoctingen noventrigintaoctingen quadragintaoctingen unquadragintaoctingen duoquadragintaoctingen tresquadragintaoctingen quattuorquadragintaoctingen' _=_ 'quinquaquadragintaoctingen sesquadragintaoctingen septenquadragintaoctingen octoquadragintaoctingen novenquadragintaoctingen quinquagintaoctingen unquinquagintaoctingen duoquinquagintaoctingen tresquinquagintaoctingen' _=_ 'quattuorquinquagintaoctingen quinquaquinquagintaoctingen sesquinquagintaoctingen septenquinquagintaoctingen octoquinquagintaoctingen novenquinquagintaoctingen sexagintaoctingen unsexagintaoctingen duosexagintaoctingen tresexagintaoctingen' _=_ 'quattuorsexagintaoctingen quinquasexagintaoctingen sesexagintaoctingen septensexagintaoctingen octosexagintaoctingen novensexagintaoctingen septuagintaoctingen unseptuagintaoctingen duoseptuagintaoctingen treseptuagintaoctingen' _=_ 'quattuorseptuagintaoctingen quinquaseptuagintaoctingen seseptuagintaoctingen septenseptuagintaoctingen octoseptuagintaoctingen novenseptuagintaoctingen octogintaoctingen unoctogintaoctingen duooctogintaoctingen tresoctogintaoctingen' _=_ 'quattuoroctogintaoctingen quinquaoctogintaoctingen sexoctogintaoctingen septemoctogintaoctingen octooctogintaoctingen novemoctogintaoctingen nonagintaoctingen unnonagintaoctingen duononagintaoctingen trenonagintaoctingen' _=_ 'quattuornonagintaoctingen quinquanonagintaoctingen senonagintaoctingen septenonagintaoctingen octononagintaoctingen novenonagintaoctingen nongen unnongen duonongen trenongen quattuornongen quinquanongen senongen septenongen octonongen' _=_ 'novenongen decinongen undecinongen duodecinongen tredecinongen quattuordecinongen quinquadecinongen sedecinongen septendecinongen octodecinongen novendecinongen vigintinongen unvigintinongen duovigintinongen tresvigintinongen' _=_ 'quattuorvigintinongen quinquavigintinongen sesvigintinongen septemvigintinongen octovigintinongen novemvigintinongen trigintanongen untrigintanongen duotrigintanongen trestrigintanongen quattuortrigintanongen quinquatrigintanongen' _=_ 'sestrigintanongen septentrigintanongen octotrigintanongen noventrigintanongen quadragintanongen unquadragintanongen duoquadragintanongen tresquadragintanongen quattuorquadragintanongen quinquaquadragintanongen sesquadragintanongen' _=_ 'septenquadragintanongen octoquadragintanongen novenquadragintanongen quinquagintanongen unquinquagintanongen duoquinquagintanongen tresquinquagintanongen quattuorquinquagintanongen quinquaquinquagintanongen sesquinquagintanongen' _=_ 'septenquinquagintanongen octoquinquagintanongen novenquinquagintanongen sexagintanongen unsexagintanongen duosexagintanongen tresexagintanongen quattuorsexagintanongen quinquasexagintanongen sesexagintanongen septensexagintanongen' _=_ 'octosexagintanongen novensexagintanongen septuagintanongen unseptuagintanongen duoseptuagintanongen treseptuagintanongen quattuorseptuagintanongen quinquaseptuagintanongen seseptuagintanongen septenseptuagintanongen octoseptuagintanongen' _=_ 'novenseptuagintanongen octogintanongen unoctogintanongen duooctogintanongen tresoctogintanongen quattuoroctogintanongen quinquaoctogintanongen sexoctogintanongen septemoctogintanongen octooctogintanongen novemoctogintanongen nonagintanonge' _=_ 'unnonagintanongen duononagintanongen trenonagintanongen quattuornonagintanongen quinquanonagintanongen senonagintanongen septenonagintanongen novenonagintanongen octononagintanongen' amers=words(_) do j=1 for amers; a.j=word(_,j); end maxzlen=amers *3 if british then do engs=amers*2-2; maxzlen=engs*3 do k=1 for 2; b.k=a.k; end do j=3 to amers; _=j*2-3; b._=a.j; _n=_+1; b._n=a.j; end drop a. end D:\►type sp2.rex n=space(n); _=left(n,1) sig= if _=='-' | _=="+" then do /*handle leading sign (+ -).*/ if _=='+' then sig=plus else sig=minus n=substr(n,2) /*remove the leading sign. */ end numeric digits 80+maxzlen zpoints =countstr('.',n); zpoint =zpoints \==0; if zpoints >1 then call er 59,'decimal-points(.)' zdollars=countstr('$',n); zdollar=zdollars\==0; if zdollars>1 then call er 59,'dollar-signs($)' zeuros =countstr('ε',n); zeuro =zeuros \==0; if zeuros >1 then call er 59,'euro-signs(ε)' zfrancs =countstr('ƒ',n); zfranc =zfrancs \==0; if zfrancs >1 then call er 59,'franc-signs(ƒ)' zpounds =countstr('£',n); zpound =zpounds \==0; if zpounds >1 then call er 59,'pound-signs(£)' zyens =countstr('¥',n); zyen =zyens \==0; if zyens >1 then call er 59,'yen-signs(¥)' zpisetas=countstr('₧',n); zpiseta=zpisetas\==0; if zpisetas>1 then call er 59,'piseta-signs(₧)' zcents =countstr('¢',n); zcent =zcents \==0; if zcents >1 then call er 59,'cent-signs(¢)' zcurrs=zdollars+zeuros+zpounds+zyens+zpisetas+zfrancs+zcents zcurr=zcurrs\==0 if zcurrs>2 then call er 59,'currency symbols' if zdollar then do; xcurr=dollar; n=changestr("$",n,''); end if zeuro then do; xcurr=euro; n=changestr("ε",n,''); end if zpound then do; xcurr=pound; n=changestr("£",n,''); end if zyen then do; xcurr=yen; n=changestr("¥",n,''); end if zpiseta then do; xcurr=piseta; n=changestr("₧",n,''); end if zfranc then do; xcurr=franc; n=changestr("ƒ",n,''); end if zcent then do; xcurr=cent; n=changestr("¢",n,''); end if zpoint then dot=point /*we have a decimal point. */ _=right(n,1) /*pick off right-most character*/ if ismix(_) | _=='!' then n=num(n) /*if # has a suffix, convert it*/ parse upper var n n 'E' exponent /*parse the exponent, if any. */ parse var n n '.' fraction leadzs=compare(n,copies(0,digits()))-1 /*count leading zeroes.*/ n=changestr(',',n,"") if isnum(n) then do if \asis then n=n/1 end else do 1 if n=='' then leave expression=n interpret 'number='expression n=trunc(number) end if xcurr\=='' then do 1 if xcurr==zyen then leave if n\==1 then xcurr=xcurr's' end max#=10**maxzlen*1000-1 if \asis & isnum(n) then n=n/1 if n\=='' & isnum(n) then if n>max# then call er 81,-max# max# ogn if n\=='' & \isint(n) then call er 53,n if abs(n)>max# then call er 81,-max# max# ogn if leading\=='' then leadingz=copies(leading' ',leadzs) if asayear & right(n,3)\==000 then do #=spnte(left(n,max(0,length(n)-2))) if #==zero then #= _2=right(n,2) _=spnte(_2) if _==zero then _="hundred" if _2<10 & _2>0 then _=zero _ #=sig||# _ end else #=sig||leadingz||spnte(n) if ordinal then do sx=;w=words(#);p=word(#,w);oldp=p;pp= if pos('-',p)\==0 then parse var p pp '-'p if pp\=='' then pp=pp'-' select when p=='one' then p="first" when p=='two' then p="second" when p=='three' then p="third" when p=='five' then p="fifth" when p=='eight' then p="eighth" when p=='nine' then p="ninth" when p=='twelve' then p="twelfth" when right(p,1)=='y' then p=left(p,length(p)-1)"ieth" otherwise sx='th' end if p\==oldp then if w==1 then #=pp||p else #=subword(#,1,w-1) pp||p #=#||sx end lf=length(fraction) if (lf==1 | lf==2) & zdollar then do if fraction\=1 then cent=cent's' fractions=sp(fraction) cent dot=xcurr andcent xcurr= end else do j=1 for lf _=substr(fraction,j,1) fractions=fractions dig._ end if exponent\=='' then do if \isint(exponent) then call er 53,exponent 'exponent' _=sp(exponent "ORDINAL");if _\=='' then exponents=raised _ power end after=space(dot fractions exponents xcurr) if after\=='' then after=" "after #=translate(#||after,,"_");if blanks\=='' then #=translate(#,blanks," ") if \quiet then call $t tops # if !fun=='COMMAND' then return 0 return # /*─────────────────────────────spnte subroutine─────────────────────────*/ spnte: parse arg zz; if zz==0 | zz=' ' then return nothing; en= bzz=reverse(zz) has_t=22 if british then has_t=41 if single then do j=1 for length(zz) _=substr(zz,j,1);en=en dig._ end else do j=1 to maxzlen by 3 _=(j+2)%3 if american then zillion=a._ else zillion=b._ if zillion==0 then zillion= if _>=has_t then zillion=zillion't' if _>2 then do if american then zillion=zillion'illion' else if _//2 then zillion=zillion'illion' else zillion=zillion'illiard' end ttt=reverse(substr(bzz,j,3)); if ttt==' ' then leave ttt=right(strip(ttt),3,0) ; if ttt== 000 then iterate x=sphtu(ttt) zillion if en\=='' then en=sep||en;en=x en end en=strip(translate(en,,"_")) if en=='' then if zcurr then do;if \zcent then en="no";end else en=zero return en /*─────────────────────────────sphtu subroutine─────────────────────────*/ sphtu: procedure; parse arg z @987='nine eight seven six five four three two one' zm=substr(z,2,1) zr=right(z,1) zh=word(@987,10-left(z,1)) if zh\=='' then zh=zh "hundred" zt=word('ninety eighty seventy sixty fifty forty thirty twenty',10-zm) zu=word(@987,10-zr) @teens='ten eleven twelve thir four fif six seven eigh nine' if zm==1 then do zu= zt=word(@teens,zr+1) if zr>2 then zt=zt'teen' end if zt\=='' & zu\=="" then do zt=zt'-'zu zu= end return space(zh zt zu) /*═════════════════════════════general 1-line subs══════════════════════*/ !all:!!=!;!=space(!);upper !;call !fid;!nt=right(!var('OS'),2)=='NT';!cls=word('CLS VMFCLEAR CLRSCREEN',1+!cms+!tso*2);if arg(1)\==1 then return 0;if wordpos(!,'? ?SAMPLES ?AUTHOR ?FLOW')==0 then return 0;!call=']$H';call '$H' !fn !;!call=;return 1 !cal:if symbol('!CALL')\=="VAR" then !call=;return !call !env:!env='ENVIRONMENT';if !sys=='MSDOS'|!brexx|!r4|!roo then !env='SYSTEM';if !os2 then !env='OS2'!env;!ebcdic=1=='f0'x;return !fid:parse upper source !sys !fun !fid . 1 . . !fn !ft !fm .;call !sys;if !dos then do;_=lastpos('\',!fn);!fm=left(!fn,_);!fn=substr(!fn,_+1);parse var !fn !fn '.' !ft;end;return word(0 !fn !ft !fm,1+('0'arg(1))) !rex:parse upper version !ver !vernum !verdate .;!brexx='BY'==!vernum;!kexx='KEXX'==!ver;!pcrexx='REXX/PERSONAL'==!ver|'REXX/PC'==!ver;!r4='REXX-R4'==!ver;!regina='REXX-REGINA'==left(!ver,11);!roo='REXX-ROO'==!ver;call !env;return !sys:!cms=!sys=='CMS';!os2=!sys=='OS2';!tso=!sys=='TSO'|!sys=='MVS';!vse=!sys=='VSE';!dos=pos('DOS',!sys)\==0|pos('WIN',!sys)\==0|!sys=='CMD';call !rex;return !var:call !fid;if !kexx then return space(dosenv(arg(1)));return space(value(arg(1),,!env)) $fact!:procedure;parse arg x _ .;l=length(x);n=l-length(strip(x,'T',"!"));if n==0|_\==''|arg()\==1 then return x;z=left(x,l-n);if z<0|\datatype(z,'W') then return x;return $fact(z,n) $fact:procedure;parse arg x _ .;arg ,n ! .;n=p(n 1);if \isint(n) then n=0;if x<0|\isint(x)|n<1|_||!\==''|arg()>2 then return x||copies("!",max(1,n));!=1;s=x//n;if s==0 then s=n;do j=s to x by n;!=!*j;end;return ! $sfxa:parse arg ,s,m;arg u,c;if pos(left(s,2),u)\==0 then do j=length(s) to compare(s,c)-1 by -1;if right(u,j)\==left(c,j) then iterate;_=left(u,length(u)-j);if datatype(_,'N') then return m*_;leave;end;return arg(1) $sfxf:parse arg y;if right(y,1)=='!' then y=$fact!(y);if \datatype(y,'N') then y=$sfxz();if datatype(y,'N') then return y;return $sfxm(y) $sfxm:parse arg z;arg w;b=1000;if right(w,1)=='I' then do;z=shorten(z);w=z;upper w;b=1024;end;p=pos(right(w,1),'KMGTPEZYXWVU');if p==0 then return arg(1);n=shorten(z);r=num(n,f,1);if datatype(r,'N') then return r*b**p;return arg(1) $sfxz:return $sfxa($sfxa($sfxa($sfxa($sfxa($sfxa(y,'PAIRs',2),'DOZens',12),'SCore',20),'GREATGRoss',1728),'GRoss',144),'GOOGOLs',1e100) $t: say arg(1); return /*this label pre-empts the one below*/ /*$T (below) supports many options: color(s), writing the output to a file, and many others. */ $t:!call=']$T';call "$T" arg(1);!call=;return abb:arg abbu;parse arg abb;return abbrev(abbu,_,abbl(abb)) abbl:return verify(arg(1)'a',@abc,'M')-1 abbn:parse arg abbn;return abb(abbn)|abb('NO'abbn) changestr:procedure;parse arg o,h,n;r=;w=length(o);if w==0 then return n||h;do forever;parse var h y (o) _ +(w) h;if _=='' then return r||y;r=r||y||n;end countstr:procedure;parse arg n,h,s;if s=='' then s=1;w=length(n);do r=0 until _==0;_=pos(n,h,s);s=_+w;end;return r er:parse arg _1,_2;call '$ERR' "14"p(_1) p(word(_1,2) !fid(1)) _2;if _1<0 then return _1;exit result err:call er '-'arg(1),arg(2);return '' erx:call er '-'arg(1),arg(2);exit '' getdtfid:tfid=p(!var("TMP") !var('TEMP') homedrive()"\");if substr(tfid,2,1)==':'&substr(tfid,3,1)\=="\" then tfid=insert('\',t,2);return strip(tfid,'T',"\")'\'arg(1)'.'arg(2) gettfid:if tfid\=='' then return tfid;gfn=word(arg(1) !fn,1);gft=word(arg(2) 'ANS',1);tfid='TEMP';if !tso then tfid=gfn'.'gft;if !cms then tfid=gfn','gft",A4";if !dos then tfid=getdtfid(gfn,gft);return tfid halt:call er .1 homedrive:if symbol('HOMEDRIVE')\=="VAR" then homedrive=p(!var('HOMEDRIVE') 'C:');return homedrive int:int=num(arg(1),arg(2));if \isint(int) then call er 92,arg(1) arg(2);return int/1 ishex:return datatype(arg(1),'X') isint:return datatype(arg(1),'W') ismix:return datatype(arg(1),'M') isnum:return datatype(arg(1),'N') na:if arg(1)\=='' then call er 01,arg(2);parse var ops na ops;if na=='' then call er 35,_o;return na nai:return int(na(),_o) nan:return num(na(),_o) no:if arg(1)\=='' then call er 01,arg(2);return left(_,2)\=='NO' novalue:!sigl=sigl;call er 17,!fid(2) !fid(3) !sigl condition('D') sourceline(!sigl) num:procedure;parse arg x .,f,q;if x=='' then return x;if datatype(x,'N') then return x/1;x=space(translate(x,,','),0);if \datatype(x,'N') then x=$sfxf(x);if datatype(x,'N') then return x/1;return numnot() numnot:if q==1 then return x;if q=='' then call er 53,x f;call erx 53,x f p:return word(arg(1),1) shorten:procedure;parse arg a,n;return left(a,max(0,length(a)-p(n 1))) sp:!call=']'!fn;sp="$SPELL#"(arg(1) 'Q');!call=;return sp syntax:!sigl=sigl;call er 13,!fid(2) !fid(3) !sigl !cal() condition('D') sourceline(!sigl)
output
Output when using the input of: 373 ordinal three hundred seventy-third Output when using the input of: 373 three hundred seventy-three Output when using the input of: +45 plus forty-five Output when using the input of: 1989 asYear nineteen eighty-nine Output when using the input of: -12.79 minus twelve point seven nine Output when using the input of: $119.63 one hundred nineteen dollars and sixty-three cents Output when using the input of: 3456T three quadrillion four hundred fifty-six trillion Output when using the input of: 4Ki four thousand ninety-six Output when using the input of: 6! seven hundred twenty Output when using the input of: 10dozen one hundred twenty Output when using the input of: 70000000000000...(3,000 zeroes total) seven octononagintanongentillion
Ruby
<lang ruby>def spell_integer(n)
tens = [nil, nil, "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"]
small = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"]
def nonzero(c, n) n.zero? ? "" : c + spell_integer(n) end
def big(e, n) bl = [nil, nil, "m", "b", "tr", "quadr", "quint", "sext", "sept", "oct", "non", "dec"]
if e >= bl.length then raise ArgumentError, "value too large to represent" elsif e == 0 then spell_integer(n) elsif e == 1 then spell_integer(n) + " thousand" else spell_integer(n) + " " + bl[e] + "illion" end end
def base1000_rev(n) # returns the value of the digits of n in base 1000 # (i.e. 3-digit chunks), in reverse. chunks = [] while n != 0 n, r = n.divmod(1000) chunks << r end chunks end
if n < 0 then "negative " + spell_integer(n.abs) elsif n < 20 then small[n] elsif n < 100 then a, b = n.divmod(10); tens[a] + nonzero("-", b) elsif n < 1000 then a, b = n.divmod(100); small[a] + " hundred" + nonzero(" ", b) else base1000_rev(n).each_with_index \ .find_all {|val, idx| val.nonzero?} \ .map {|val, idx| big(idx, val)} \ .reverse \ .join(', ') end
end
- example
for test in [0, -0, 5, -5, 25, 90, 100, 101, 999, 1000, 1008, 54321, 1234567890, 0x7F,
123456789012345678901234567890123456, 1234567890123456789012345678901234567] print "#{test} -> " begin puts spell_integer(test) rescue => e puts "Error: #{e}" end
end</lang>
0 -> zero 0 -> zero 5 -> five -5 -> negative five 25 -> twenty-five 90 -> ninety 100 -> one hundred 101 -> one hundred one 999 -> nine hundred ninety-nine 1000 -> one thousand 1008 -> one thousand, eight 54321 -> fifty-four thousand, three hundred twenty-one 1234567890 -> one billion, two hundred thirty-four million, five hundred sixty-seven thousand, eight hundred ninety 127 -> one hundred twenty-seven 123456789012345678901234567890123456 -> one hundred twenty-three decillion, four hundred fifty-six nonillion, seven hundred eighty-nine octillion, twelve septillion, three hundred forty-five sextillion, six hundred seventy-eight quintillion, nine hundred one quadrillion, two hundred thirty-four trillion, five hundred sixty-seven billion, eight hundred ninety million, one hundred twenty-three thousand, four hundred fifty-six 1234567890123456789012345678901234567 -> Error: value too large to represent
Tcl
<lang tcl>proc int2words {n} {
if { ! [regexp -- {^(-?\d+)$} $n -> n]} { error "not a decimal integer" } if {$n == 0} { return zero } if {$n < 0} { return "negative [int2words [expr {abs($n)}]]" } if {[string length $n] > 36} { error "value too large to represent" } set groups [get_groups $n] set l [llength $groups] foreach group $groups { incr l -1 # ensure any group with a leading zero is not treated as octal set val [scan $group %d] if {$val > 0} { lappend result [group2words $val $l] } } return [join $result ", "]
}
set small {"" one two three four five six seven eight nine ten eleven twelve
thirteen fourteen fifteen sixteen seventeen eighteen nineteen}
set tens {"" "" twenty thirty forty fifty sixty seventy eighty ninety} set powers {"" thousand} foreach p {m b tr quadr quint sext sept oct non dec} {lappend powers ${p}illion}
proc group2words {n level} {
global small tens powers if {$n < 20} { lappend result [lindex $small $n] } elseif {$n < 100} { lassign [divmod $n 10] a b set result [lindex $tens $a] if {$b > 0} { append result - [lindex $small $b] } } else { lassign [divmod $n 100] a b lappend result [lindex $small $a] hundred if {$b > 0} { lappend result and [group2words $b 0] } } return [join [concat $result [lindex $powers $level]]]
}
proc divmod {n d} {
return [list [expr {$n / $d}] [expr {$n % $d}]]
}
proc get_groups {num} {
# from http://wiki.tcl.tk/5000 while {[regsub {^([-+]?\d+)(\d\d\d)} $num {\1 \2} num]} {} return [split $num]
}
foreach test {
0 -0 5 -5 10 25 99 100 101 999 1000 1008 1010 54321 1234567890 0x7F 123456789012345678901234567890123456 1234567890123456789012345678901234567
} {
catch {int2words $test} result puts "$test -> $result"
}</lang> produces
0 -> zero -0 -> zero 5 -> five -5 -> negative five 10 -> ten 25 -> twenty-five 99 -> ninety-nine 100 -> one hundred 101 -> one hundred and one 999 -> nine hundred and ninety-nine 1000 -> one thousand 1008 -> one thousand, eight 1010 -> one thousand, ten 54321 -> fifty-four thousand, three hundred and twenty-one 1234567890 -> one billion, two hundred and thirty-four million, five hundred and sixty-seven thousand, eight hundred and ninety 0x7F -> not a decimal integer 123456789012345678901234567890123456 -> one hundred and twenty-three decillion, four hundred and fifty-six nonillion, seven hundred and eighty-nine octillion, twelve septillion, three hundred and forty-five sextillion, six hundred and seventy-eight quintillion, nine hundred and one quadrillion, two hundred and thirty-four trillion, five hundred and sixty-seven billion, eight hundred and ninety million, one hundred and twenty-three thousand, four hundred and fifty-six 1234567890123456789012345678901234567 -> value too large to represent
Visual Basic
If one were to use variants further and get them to play nice as Decimal
, this could theoretically be extended up to the octillion range.
<lang vb>Option Explicit
Private small As Variant, tens As Variant, big As Variant
Sub Main()
small = Array("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", _ "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", _ "eighteen", "nineteen") tens = Array("twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety") big = Array("thousand", "million", "billion")
Dim tmpInt As Long tmpInt = Val(InputBox("Gimme a number!", "NOW!", Trim$(Year(Now)) & IIf(Month(Now) < 10, "0", "") & _ Trim$(Month(Now)) & IIf(Day(Now) < 10, "0", "") & Trim$(Day(Now)))) MsgBox int2Text$(tmpInt)
End Sub
Function int2Text$(number As Long)
Dim num As Long, outP As String, unit As Integer Dim tmpLng1 As Long
If 0 = number Then int2Text$ = "zero" Exit Function End If
num = Abs(number)
Do tmpLng1 = num Mod 100 Select Case tmpLng1 Case 1 To 19 outP = small(tmpLng1 - 1) + " " + outP Case 20 To 99 Select Case tmpLng1 Mod 10 Case 0 outP = tens((tmpLng1 \ 10) - 2) + " " + outP Case Else outP = tens((tmpLng1 \ 10) - 2) + "-" + small(tmpLng1 Mod 10) + " " + outP End Select End Select
tmpLng1 = (num Mod 1000) \ 100 If tmpLng1 Then outP = small(tmpLng1 - 1) + " hundred " + outP End If
num = num \ 1000 If num < 1 Then Exit Do
tmpLng1 = num Mod 1000 If tmpLng1 Then outP = big(unit) + " " + outP
unit = unit + 1 Loop
If number < 0 Then outP = "negative " & outP
int2Text$ = Trim$(outP)
End Function</lang>
Example output (in a msgbox) is identical to the BASIC output.
Visual Basic .NET
Platform: .NET
This solution works for integers up to 1000. It should be fairly ovbious how it works, and so can be extended if needed.
<lang vbnet>Module Module1
Sub Main() Dim i As Integer Console.WriteLine("Enter a number") i = Console.ReadLine() Console.WriteLine(words(i)) Console.ReadLine() End Sub Function words(ByVal Number As Integer) As String Dim small() As String = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"} Dim tens() As String = {"", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"} Select Case Number Case Is < 20 words = small(Number) Case 20 To 99 words = tens(Number \ 10) + " " + small(Number Mod 10) Case 100 To 999 words = small(Number \ 100) + " hundred " + IIf(((Number Mod 100) <> 0), "and ", "") + words(Number Mod 100) Case 1000 words = "one thousand" End Select End Function
End Module</lang>