Skip to content

Instantly share code, notes, and snippets.

@heathermiller
Created June 9, 2020 17:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save heathermiller/b0438443351ff0caeea9e2f818bbc9ff to your computer and use it in GitHub Desktop.
Save heathermiller/b0438443351ff0caeea9e2f818bbc9ff to your computer and use it in GitHub Desktop.
Say large numbers in text, in Unison

Given a number from 0 to 999,999,999,999, spell out that number in English.

Step 1

Handle the basic case of 0 through 99.

If the input to the program is 22, then the output should be 'twenty-two'.

Your program should complain loudly if given a number outside the blessed range.

Some good test cases for this program are:

  • 0
  • 14
  • 50
  • 98
  • 100

Step 2

Implement breaking a number up into chunks of thousands.

So 1234567890 should yield a list like 1, 234, 567, and 890, while the far simpler 1000 should yield just 1 and 0.

The program must also report any values that are out of range.

Step 3

Now handle inserting the appropriate scale word between those chunks.

So 1234567890 should yield '1 billion 234 million 567 thousand 890'

The program must also report any values that are out of range. It's fine to stop at "trillion".

Step 4

Put it all together to get nothing but plain English.

12345 should give twelve thousand three hundred forty-five.

The program must also report any values that are out of range.

smallNumberNames : Nat -> Text
smallNumberNames n =
match n with 0 -> "zero"
1 -> "one"
2 -> "two"
3 -> "three"
4 -> "four"
5 -> "five"
6 -> "six"
7 -> "seven"
8 -> "eight"
9 -> "nine"
10 -> "ten"
11 -> "eleven"
12 -> "twelve"
13 -> "thirteen"
14 -> "fourteen"
15 -> "fifteen"
16 -> "sixteen"
17 -> "seventeen"
18 -> "eighteen"
19 -> "nineteen"
20 -> "twenty"
30 -> "thirty"
40 -> "forty"
50 -> "fifty"
60 -> "sixty"
70 -> "seventy"
80 -> "eighty"
90 -> "ninety"
rest : Text -> Nat -> Text
rest sep m =
if m == 0 then "" else sep ++ inEnglish m
forBase : Nat -> Nat -> Text -> Text
forBase n b name =
inEnglish (n/b) ++ " " ++ name ++ if (mod n b) != 0 then " " ++ inEnglish (mod n b) else ""
inEnglish : Nat -> Text
inEnglish n =
match n with
n | n <= 19 -> smallNumberNames n
n | n <= 99 -> smallNumberNames (10*(n /10)) ++ rest "-" (mod n 10)
n | n <= 999 -> forBase n 100 "hundred"
n | n <= 999999 -> forBase n 1000 "thousand"
n | n <= 999999999 -> forBase n 1000000 "million"
n | n < 1000000000000 -> forBase n 1000000000 "billion"
otherwise -> "number outside of allowed range"
> inEnglish 100
test> say.tests.ex1 =
check ( inEnglish 0 == "zero" )
test> say.tests.ex2 =
check ( inEnglish 1 == "one" )
test> say.tests.ex3 =
check ( inEnglish 14 == "fourteen" )
test> say.tests.ex4 =
check ( inEnglish 20 == "twenty" )
test> say.tests.ex5 =
check ( inEnglish 22 == "twenty-two" )
test> say.tests.ex6 =
check ( inEnglish 100 == "one hundred" )
test> say.tests.ex7 =
check ( inEnglish 123 == "one hundred twenty-three" )
test> say.tests.ex8 =
check ( inEnglish 1000 == "one thousand" )
test> say.tests.ex9 =
check ( inEnglish 1234 == "one thousand two hundred thirty-four" )
test> say.tests.ex10 =
check ( inEnglish 1000000 == "one million" )
test> say.tests.ex11 =
check ( inEnglish 1000002 == "one million two" )
test> say.tests.ex12 =
check ( inEnglish 1002345 == "one million two thousand three hundred forty-five" )
test> say.tests.ex13 =
check ( inEnglish 1000000000 == "one billion" )
test> say.tests.ex14 =
check ( inEnglish 987654321123 == "nine hundred eighty-seven billion six hundred fifty-four million three hundred twenty-one thousand one hundred twenty-three" )
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment