Number Namer
Having learned the Lisp-like language Clojure I decided to revisit my Number Namer project I did in Lua and improve it with the magical abilities of nested parentheses.
This project would take a number and return the English name for it.
For example, 8'675'309 would return the string eight million, six hundred seventy-five thousand, three hundred nine.
Then, using the ClojureScript compiler, I made the script executable in web browsers everywhere; thus anybody can enjoy naming their favorite numbers, big or small.
The Rectangles
The following two input boxes return the group-name for a given group-number, and the number's full name.
These input fields take positive integers only (for right now, at least) meaning you cannot put decimals, negatives, or non-number characters like letters or punctuation.
If you choose to put one or more of those, the rectangle will complain.
Because of the way JavaScript handles numbers, these scripts work primarily with string representations of numbers.
By using strings instead of the built-in primitive numbers there is no theoretical limit to the size of the numbers; the only limit is the memory limit of JavaScript and your browser.
Number to String
In this rectangle put the number you would like to know the full name of.
number_to_string
io.harriknox.NumberNamer.number_to_string(value)
Parameters:
value
is either an int or string representation of a non-negative integer
Returns:
the number's full name in English as a string
Throws:
assertion exceptions if input is invalid
Group Name
In this rectangle put the group number you want to know the Latin name of.
Strictly speaking, a group-number is one less than the number of three-digit groups following the group in question: in 1'000'000'000'000 (a trillion) the group with 1 is followed by four three-digit groups, four minus one is three, thus
trillion.
Group-numbers and group-names are explained in more depth on my
Big Numbers page, so have a look there if you would like to enlighten yourself.
illion_group_name
io.harriknox.NumberNamer.illion_group_name(group)
Parameters:
group
is either an int or string representation of a positive integer
Returns:
the corresponding Latin group-name for the group number as a string
Throws:
assertion exceptions if input is invalid
Powers of Ten
In this rectangle put the quantity of digits in the number you want to know the Latin name of.
For example, if you wanted to know what a googol was (10100) put 100.
power_of_10_to_string
io.harriknox.NumberNamer.power_of_10_to_string(exp)
Parameters:
exp
is either an int or string representation of a non-negative integer
Returns:
the full name in English of the number 10
exp as a string
Throws:
assertion exceptions if input is invalid
The Method
The Language
I first built the project in Lua when its purpose was much more simple than it is now.
In the Lua project I had no intention of exceding numbers greater than 999.
When I did need to extend into the thousands, I just had a second function to split the six-digit number into two groups, get the names of each group, and concatenate the names together with "thousand" added between the groups.
Those were the days.
Then, I learned a cool new programming language called Clojure.
Clojure (and other Lisp-like languages) are fantastic for succinct recursion.
Though at a high level iteration and recursion are both looping, the recursion in the Clojure version makes the control flow and variable assignment more comprehensive than the iterative Lua version.
The Process
The following is an overview of how the Number Namer function works.
Before entering the parsing loop it checks the integrity of the number passed in: if it is not an int or an integer disguised as a string, it errors; if the value is effectively equal to zero, it simply returns "zero".
If it passes all tests, it continues to decode the number.
In the initialization step of the loop it pads the number (as a string) with extra zeros in the front to make the number of digits divisible by three, then splits the digits into a long sequence, reverses their order, and converts each to an int value.
The loop sets the variables ones
, tens
, and hundreds
to the first three digits of the split-and-reversed sequence (which end up being the last three digits of the input number) while the remaining digits are assigned as a sequence to the variable remaining
.
It initializes two more variables before starting: group
starts at zero and represents the adjusted number of the group being parsed and number-strings
is a list of all the digit-group-names.
In the loop body it checks if the current digit values are nil
(indicating whether all digit groups have been traversed).
If the values are nil
, then all digits were traversed and it returns a nicely formatted string of the number's name.
Otherwise it loops back, setting ones
, tens
, and hundreds
to the next three values of remaining
, setting remaining
to the remaining digits, incrementing group
, and appending the digit-names and group-name to number-strings
.
In getting the digit-names of a group, it performs the following checks to determine what to write in.
First it checks hundreds
to see if it is positive, if so it adds "X hundred" to the digit-name, otherwise it adds nothing.
Next it checks tens
to see if it is equal to 1
: this is because all the numbers 10 to 19 use a different naming system than the other numbers.
If tens
is 1
, then it uses a switch-case based on ones
to determine what name to add to the digit-name.
If tens
is not 1
, then it slaps together the string versions of tens
and ones
(if any) with a hyphen between (if needed).
To get the group-name, it checks
group
.
If
group
is
1
(meaning the digit group is the thousands) it adds "thousand"; otherwise it decrements the value and determines the group-name using the process described on my
Big Numbers page.
The loop traverses group by group appending the digit-names and the group-names together into one long string.
The source code for Number Namer is located
here on GitHub.