Facebook Tweet Google+

RSS

Breaking the World Record Typing Numbers to Words

Aug 2010


The other day I read a news article about a man named Les Stewart who typed out the words "one" to "one million".

http://www.recordholders.org/en/records/typing.html
It took him 16 years to do this. It must have been an fantastically laborious task for him. Granted, there are much worse things a man could do with his time, but I was curious to see how much time could've been saved if Mr. Stewart instead wrote a computer program to help him.

1
2
3
4
//recreating world record...
//http://www.recordholders.org/en/records/typing.html

void digitToWord(char * storeString, unsigned long number);

The fact he wrote it out in words instead of just numbers made this tricky. People say numbers as words a little differently. I am going to stray from his method by not using the word "and". For example, 983 = nine hundred eighty-three. Some people say "nine hundred AND eighty-three". I was always taught that the word "and" is reserved to note when crossing the decimal point. That is how I am writing the code. And as a final example, here is a large mixed number so you can can infer my general method of stating numbers as words.

880986 = eight hundred eighty thousand nine hundred eighty-six

Time to build the function. First writing out the numbers 1 to 99:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
    switch(thecountholder){
        case 0:
            //zero is never written.
            //strcat(returnString, "zero");
            break;
        case 1:
            strcat(returnString, "one");
            break;
        case 2:
            strcat(returnString, "two");
            break;
        case 3:
            strcat(returnString, "three");
            break;
        case 4:
            strcat(returnString, "four");
            break;
        case 5:
            strcat(returnString, "five");
            break;
        case 6:
            strcat(returnString, "six");
            break;
        case 7:
            strcat(returnString, "seven");
            break;
        case 8:
            strcat(returnString, "eight");
            break;
        case 9:
            strcat(returnString, "nine");
            break;

        case 10:
            strcat(returnString, "ten");
            break;

        case 11:
            strcat(returnString, "eleven");
            break;
        case 12:
            strcat(returnString, "twelve");
            break;
        case 13:
            strcat(returnString, "thirteen");
            break;
        case 14:
            strcat(returnString, "fourteen");
            break;
        case 15:
            strcat(returnString, "fifteen");
            break;
        case 16:
            strcat(returnString, "sixteen");
            break;
        case 17:
            strcat(returnString, "seventeen");
            break;
        case 18:
            strcat(returnString, "eighteen");
            break;
        case 19:
            strcat(returnString, "nineteen");
            break;
       case 20:
            strcat(returnString, "twenty");
            break;
        case 30:
            strcat(returnString, "thirty");
            break;
        case 40:
            strcat(returnString, "forty");
            break;
        case 50:
            strcat(returnString, "fifty");
            break;
        case 60:
            strcat(returnString, "sixty");
            break;
        case 70:
            strcat(returnString, "seventy");
            break;
        case 80:
            strcat(returnString, "eighty");
            break;
        case 90:
            strcat(returnString, "ninety");
            break;

        default:
            if(thecountholder > 20)
            {
                    //recursion
                digitToWord(buildString, thecountholder - (thecountholder % 10));
                digitToWord(tempstring, thecountholder % 10);
                strcat(returnString, buildString);
                strcat(returnString, "-");
                strcat(returnString, tempstring);
            }
            break;
    }

    sprintf(storeString, "%s", returnString);

In the entirety of my code, I only type out the word for each number once. I then use recursion to get to the other numbers. For example, after the word "twenty", I start to repeat myself. I just subtract off the parts I have already said and recursively get the lower numbers. This is also why I use strcat instead of sprintf. I want to keep appending to my final string when the recursion ends.
Now that I have 1 through 99, time to add the hundreds...
1
2
3
4
5
6
7
8
9
10
11
12
13
    if(thecountholder >= 100) //X hundred
    {
        digitToWord(tempstring, thecountholder / 100);
        strcat(returnString, tempstring);
        strcat(returnString, " hundred");
        thecountholder = thecountholder % 100; //carry the remainder
        if(thecountholder != 0)
        {
            strcat(returnString, " ");
        }


    }

I divide by hundred and use the top part to dive in and get what that number would be. After I find that out, I use modulus to get the remaining digits and let the function fall to get the rest of my words. Here is thousands and millions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
    if(thecountholder >= 1000000)  // X million
    {

        digitToWord(tempstring, thecountholder / 1000000);
        strcat(returnString, tempstring);
        strcat(returnString, " million");
        thecountholder = thecountholder % 1000000;  //carry the remainder
        if(thecountholder != 0)
        {
            strcat(returnString, " ");
        }
    }

    if(thecountholder >= 1000) // X thousand
    {


        digitToWord(tempstring, thecountholder / 1000);
        strcat(returnString, tempstring);
        thecountholder = thecountholder % 1000;  //carry the remainder
        strcat(returnString, " thousand");
        if(thecountholder != 0)
        {
            strcat(returnString, " ");
        }
    }

Exact same idea. Get the top number. Append to my final string. Use recursion to get the smaller numbers. I add a space if there are more numbers.
One other thing to add to my function. This world record wouldn't be interesting unless I smashed it. The max value of my unsigned long is 2^32 - 1, or 4294967295. Lets add support for billions.
1
2
3
4
5
6
7
8
9
10
11
12
    if(thecountholder >= 1000000000)  // X billion
    {

        digitToWord(tempstring, thecountholder / 1000000000);
        strcat(returnString, tempstring);
        strcat(returnString, " billion");
        thecountholder = thecountholder % 1000000000;  //carry the remainder
        if(thecountholder != 0)
        {
            strcat(returnString, " ");
        }
    }

Now, I am all set to decimate this world record. Lets add the code that calls this function a million times.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    printf("Generating text from %ld to %ld\n", startvalue, stopvalue);
    time(&timestamp);
    file = fopen("1to1000000t.txt","a+");
    for(thecount = startvalue; thecount <= stopvalue; thecount++)
    {
        memset(buildstring, 0, sizeof(buildstring));
        digitToWord(buildstring,thecount);
        fprintf(file,"%s", buildstring);

        if(thecount < stopvalue)  //don't print comma on last element.
        {
            fprintf(file,", ");

        }

        if(thecount % 100 == 0) //new line every hundred numbers.
        {
            fprintf(file,"\n");

        }


    }
    fclose(file);
    printf("Finished. Time: %ld seconds.\n", time(NULL) - timestamp);

During debug, I had opening and closing the file inside the for loop. This was handy in catching where the program seg faults. During real runs, constantly opening and closing that file is just not needed. So how long does it take my computer to type out "one" to "one million" ?


Very nice. I matched the world record in 4 seconds. There is still one task left: printing it. I'll leave that for you. Feel free to add "one million one" to the zip file below and bring it to Kinkos for printing to claim the prize. Note that it is 51 MB uncompressed.
Finally, lets break this record. How long does it take my computer to type "one" to "one billion" ? Assuming 4 seconds, I expect this to take 4000 seconds, or about a little over an hour. How about every 5 million, I get a status update to know it is still running?

1
2
3
4
5
6
        if(thecount % 5000000 == 0) //new line every hundred numbers.
        {
           
            printf("Current count is %ld.  Running time is %ld seconds.\n", thecount, time(NULL) - timestamp);
   
        }


....so I ran this to a billion. How long did it take?
Current count is 985000000.  Running time is 6729 seconds.
Current count is 990000000.  Running time is 6766 seconds.
Current count is 995000000.  Running time is 6802 seconds.
Current count is 1000000000.  Running time is 6839 seconds.
Finished. Time: 6839 seconds.
naglemini:~ dannagle$ 


Just under 2 hours. The file size was 78GB. Looking at the tail shows that it was indeed printing those numbers...
nine hundred ninety-nine million nine hundred ninety-nine thousand nine hundred ninety-nine, one billion
naglemini:~ dannagle$ 
naglemini:~ dannagle$ 

My program started to slow down at the end. The first 5 million took 23 seconds, and the last 5 million took 37 seconds. That's a pretty wide variance, but let's assume Mr. Stewart stays a steady pace. It would've taken him 16000 years to reach 1 billion.

About

Dan Nagle is a SW Developer and the founder of NagleCode. His apps have been downloaded hundreds of thousands of times and have been featured all over the internet. He resides in Huntsville, AL.

More Posts

Jan 2018: Pay Down Calc v2.0 - A Resource For Consumers and Agents
Jul 2015: Unity Publishing Metrics
May 2015: JavaScript is not the answer to everything
Feb 2015: Abandoning Scripts for Static Pages
Apr 2014: Qt is better than Java.
Oct 2013: The government does not need to make a health website.
Sep 2013: Google Reader may by dying but RSS is not
Jun 2013: Stop writing batch scripts. Start writing AutoIt scripts.
Mar 2013: Goodbye XP Hello Linux Mint
Dec 2012: Your Goals Should be SMART
Apr 2011: Happy 40th Birthday FTP and Farewell
Aug 2010: Breaking the World Record Typing Numbers to Words

Copyright © NagleCode 2007 - 2018.