Click here to Skip to main content
15,867,308 members
Articles / General Programming / String
Reference

Number to english text in C++11

Rate me:
Please Sign up or sign in to vote.
4.83/5 (9 votes)
17 Aug 2015CPOL1 min read 16.1K   9   1
Convert integer numbers to english text representation

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:

C++
#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: 

C++
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>
#include <string>

using namespace std;  // never use this in a header file

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: 

C++
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):

C++
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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionVERY INTERESTING ARTICLE Pin
learner198821-Aug-15 6:19
learner198821-Aug-15 6:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.