Introduction
Convert numbers in the range -2^31
to 2^31
into english text, such as "one hundred twenty three" for 123.
Using the code
The funciton that does the conversion is str_rep()
. I wrote two versions of the num_to_english_words()
function: one simple (the first one I created), which has duplicate code structures and therefore would be tedious to extend to support 128 bit integers; and one without duplication, more generic but also a bit harder to understand, would be easily extended to cover 128 bit integers. Yes, the second version is of dubious practical value: who would ever need to write such large numbers in English words -- but it was fun to write :)
Copy one of the two versions into your utility source file, and call as desired as per examples in main().
Simple , less generic version:
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
string
num_to_english_words(int num)
{
static const vector<string> digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
static const vector<string> teens = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
static const vector<string> tens = { "skip", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
if (num < 0)
return "minus " + str_rep(-num);
if (num < 10)
return digits[num];
if (num < 20)
return teens[num - 10];
if (num < 100)
{
if (num % 10 == 0)
return tens[num/10];
else
return tens[num/10] + ' ' + digits[num % 10];
}
if (num < 1000)
{
if (num % 100 == 0)
return digits[num / 100] + " hundred";
else
return digits[num / 100] + " hundred " + num_to_english_words(num % 100);
}
static const int one_million = 1000000;
if (num < one_million)
{
const int thousands = int(num/1000);
if (num % 1000 == 0)
return str_rep(thousands) + " thousand";
else
return str_rep(thousands) + " thousand " + num_to_english_words(num % 1000);
}
static const int one_billion = 1000000000;
if (num < one_billion)
{
const int millions = int(num/one_million);
if (num % one_million == 0)
return str_rep(millions) + " million";
else
return str_rep(millions) + " million " + num_to_english_words(num % one_million);
}
const int billions = int(num/one_billion);
if (num % one_billion == 0)
return str_rep(billions) + " billion";
else
return str_rep(billions) + " billion " + num_to_english_words(num % one_billion);
}
More generic, 64-bit capabie (but more complex) version:
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string
str_rep_0_to_999(int num)
{
static const vector<string> digits = { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" };
static const vector<string> teens = { "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen" };
static const vector<string> tens = { "skip", "ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety" };
if (num < 10)
return digits[num];
if (num < 20)
return teens[num - 10];
if (num < 100)
{
if (num % 10 == 0)
return tens[num / 10];
else
return tens[num / 10] + ' ' + digits[num % 10];
}
if (num % 100 == 0)
return digits[num / 100] + " hundred";
else
return digits[num / 100] + " hundred " + str_rep_0_to_999(num % 100);
}
short count_segments(int64_t num)
{
int count_segs = 0;
while ((num /= 1000) != 0)
count_segs++;
return count_segs;
}
string
num_to_english_words(int64_t num, short num_segments = -1)
{
if (num < 0)
return "negative " + num_to_english_words(-num);
if (num < 1000)
return str_rep_0_to_999(short(num));
static const vector<string> segments = { "skip", "thousand", "million", "billion", "trillion", "quatrillion", "quintillion"};
if (num_segments < 0)
num_segments = count_segments(num);
assert(num_segments > 0);
const string factor_name = segments[num_segments];
const int64_t factor = pow(1000, num_segments);
const int groups = int(num / factor);
const string rep = str_rep_0_to_999(groups) + " " + factor_name;
if (num % factor == 0)
return rep;
else
return rep + " " + num_to_english_words(num % factor, num_segments - 1);
}
An example main() that uses it:
int main()
{
vector<int> v = {0, 1, 12, 20, 23, 34, 50, 99, 123, 199, 256, 300, 591, 999, 1000, 8765, 23456, 99999};
for (auto x: v)
cout << x << " " << str_rep(x) << endl;
vector<int> v2 = { 1000000, 5000000, 9876543, 999999999, 1000000000, 1234567890 };
for (auto x : v2)
cout << x << " " << str_rep(x) << endl;
vector<int> v3 = { -1, -12, -199, -1000, -99999, -5000000, -1234567890 };
for (auto x : v3)
cout << x << " " << str_rep(x) << endl;
const auto large = int64_t(1234567890) * 1234567890;
cout << large << " " << num_to_english_words(large) << endl;
}
Output: when example run (same for both versions):
0 zero
1 one
12 twelve
20 twenty
23 twenty three
34 thirty four
50 fifty
99 ninety nine
123 one hundred twenty three
199 one hundred ninety nine
256 two hundred fifty six
300 three hundred
591 five hundred ninety one
999 nine hundred ninety nine
1000 one thousand
8765 eight thousand seven hundred sixty five
23456 twenty three thousand four hundred fifty six
99999 ninety nine thousand nine hundred ninety nine
1000000 one million
5000000 five million
9876543 nine million eight hundred seventy six thousand five hundred forty three
999999999 nine hundred ninety nine million nine hundred ninety nine thousand nine hundred ninety nine
1000000000 one billion
1234567890 one billion two hundred thirty four million five hundred sixty seven thousand eight hundred ninety
-1 negative one
-12 negative twelve
-199 negative one hundred ninety nine
-1000 negative one thousand
-99999 negative ninety nine thousand nine hundred ninety nine
-5000000 negative five million
-1234567890 negative one billion two hundred thirty four million five hundred sixty seven thousand eight hundred ninety
1524157875019052100 one quintillion five hundred twenty four quatrillion one hun
dred fifty seven trillion eight hundred seventy five billion nineteen million fi
fty two thousand one hundred
Points of Interest
This uses recursion in order to maximize re-use. Uses C++11 range for-loop and initialization list. The more generic version is sigificantly more difficult to understand: blocks converted to loops,
History
- Aug 20, 2015: first version
- Aug 23, 2015: second version