Click here to Skip to main content
15,883,883 members
Articles / Programming Languages / C

Convert Integers to Their Textual Description

Rate me:
Please Sign up or sign in to vote.
3.34/5 (13 votes)
6 May 2014Apache2 min read 158.4K   1.3K   27   52
Convert an integer to its textual description

Sample Image

Preface

Ever wanted a friendlier way to display any given amount to a user? Or, perhaps you're coding a grammatically correct English application, racing game, tracking visitors, or creating an accounting solution. Whatever the case, there are some times when a programmer needs to represent a number as a written word (i.e., 4 becomes "four"). And, that's the goal of this routine.

The original version (as most typical implementations of this) used strings for calculations and conversions and while it worked, it was slower. However, I updated the algorithm to not do this anymore. As a result, I noticed an average 310% speed increase (on a Pentium IV) despite the fact I also added support for much larger numbers as well.

Usage

Using this routine is straightforward. It does make use of C-style strings as they are fast and extremely portable with most environments. The sole routine that does the grunt work is named GetNumWord() and is prototyped as follows...

C++
// prototype/signature
char *GetNumWord (long long llNumber, char *szDest, 
                  unsigned int unLen, bool bOrdinal, bool bUseAnd);

Parameter Descriptions:

llNumber = This is the 64-bit number to convert.
szDest = Pointer to the output buffer (char array).
unLen = Size in bytes of the output buffer (not string length).
bOrdinal = Setting this to true will return the ordinal version of the number (e.g., first); otherwise, the cardinal version is returned (e.g., one).
bUseAnd = This will determine if the and conjunction is used in the output or not (e.g., One Hundred And One).

Example

C++
char szBuffer[100] = {0};
GetNumWord(5001, szBuffer, sizeof(szBuffer), false, false);
GetNumWord(-10, szBuffer, sizeof(szBuffer), false, false);
GetNumWord(123, szBuffer, sizeof(szBuffer), true, true);

Will return...

"Five Thousand One"
"Negative Ten"
"One Hundred And Twenty-Third"

Limitations

The function takes a long long as the number parameter. On most 32-bit and 64-bit systems, this means the lowest number you can pass is <nobr>-9,223,372,036,854,775,808 and the highest number is 9,223,372,036,854,775,807.

Also, 64-bit arithmetic on a 32-bit CPU is a bit slower. However, the difference is negligible for most applications, and 64-bit CPUs are becoming more and more mainstream, so this consideration will soon be obsolete.

Credits & History

<nobr>Article's Author<nobr> - Jeremy Falcon
<nobr>The "and" Conjunction Suggestion<nobr> - benjymous
<nobr>Memory Leak Tip<nobr> - James Curran
  • <nobr>2007-01-13 - Ver. 2.0 released.
  • <nobr>2002-04-12 - Ver. 1.1 released.
  • <nobr>2002-04-01 - Ver. 1.0 released.

License

Permission is granted to anyone to use this software for any purpose on any computer system, and to alter it and redistribute it freely, subject to the following restrictions found in NumWord.c. It's nothing big. Essentially, it states that if your computer blows up then it's not my fault, and if you use this code then give credit where it's due.

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0


Written By
Team Leader
United States United States
I've been in software development since 1994. Over the years I've learned quite a lot in what it takes to complete the process of pushing out a quality product to customers in a timely fashion. As most of my colleagues could attest, there have been many challenges in our new and growing field in the past couple of decades as the industry matures rapidly. Much more so than most others historically speaking.

As such, I've learned one of the best aspects of software engineering is embracing the change that inherently comes along with it as new technologies constantly emerge to help us improve our world one application at a time as we make sense of the overwhelming amount of data now prevalent in the Information Age.

We truly live in a time unlike that ever known to mankind in recorded history, and it is my hope to do my part to help it along to face the challenges and demands of tomorrow.

Comments and Discussions

 
QuestionComments on the code. Pin
Bill_Hallahan14-May-14 15:40
Bill_Hallahan14-May-14 15:40 
AnswerRe: Comments on the code. Pin
Jeremy Falcon14-May-14 16:05
professionalJeremy Falcon14-May-14 16:05 
GeneralRe: Comments on the code. Pin
Bill_Hallahan15-May-14 16:24
Bill_Hallahan15-May-14 16:24 
Jeremy Falcon wrote:
Bill_Hallahan wrote:
he largest positive signed value is +2^63 - 1


You are correct.

That wasn't my point. The point was that the code outputs a wrong string value for the value 0x8000000000000000. This is a bug.
The full text of what I wrote is:

For a signed 64-bit value, because you use make negative numbers positive, there is a single negative value that the code will not convert properly, and that is -2^63. The largest positive signed value is +2^63 - 1. That issue is not difficult to fix by making a special case for that one negative value. Your code currently does not handle that case.


Jeremy Falcon wrote:
Bill_Hallahan wrote:
The routine cannot fail, therefore it should return type void. There is no need to pass back the same buffer address that is passed in.


Nope. It returns the string so it can be called inline. It's a C trick us old farts like to do on occasion to pretend we're in C++.

Ah, that makes sense. Most of the C-runtime calls that take a buffer do that too, including the strtoull function, which could be used in the code, albeit I gather you measured it and it's slower.

Jeremy Falcon wrote:
I'd have to see it. Not that my routine is heavily optimized, but I seriously doubt it's faster going the route you mentioned. Every decent CPU in the world has a math co-processor. And while division is slower than multiplication and bit shifting hacks, it can't be as slow as converting string data (internally) to a different base (externally). That's actually a misnomer since the computer doesn't care about that away, base representations are for human convenience. The CPU does not process octal, etc.

The code is doing a conversion to base 10 digits now. Each index you calculate to look up the appropriate string is a base 10 digit. Knuth's algorithm was designed to avoid the repeated divide by powers of 10. The octal conversion is trivial because a binary number is an octal number - groups of three bits form a digit from 0 to 7. I see you wrote a basic article on binary, so I am sure you realize that. The shifting and masking is extremely fast.

Also, you state that all decent processors have a divide. If you define a decent processor as one that has a divide, you are right, but the Knuth code will be fast on ARM, MIPs, Z80s, and other processors that are inexpensive and very useful, particularly in embedded work.

With a fast divide instruction, I'm not sure if Knuth's algorithm is worth it. I already have python code that converts a number to a text string. (I have this because I once worked with text-to-speech). That also uses the simple divide by 10 method. I'm going to code that in C and time it.

I am really surprised that using strtoull and then subtracting '0' (48) from each ASCII digit and using that as an index isn't faster than the code you wrote. Again, the code is now calculating each base10 digit, it just uses the digit as an index and then throws it away. I would expect the C routine to use optimal algorithms and take advantage of Intel parallel instructions (SSE1 and SSE2 instructions) that a C compiler does not generate.

Update:

I just noticed that Windows doesn't implement the C99 functions for 64-bit integers, at least not with Visual Studio 2008's standard installation. The Microsoft functions are:
C++
_strtoi64, _wcstoi64, _strtoi64_l, _wcstoi64_l

The unsigned versions are:
C++
_strtoui64, _wcstoui64, _strtoui64_l, _wcstoui64_l

GeneralRe: Comments on the code. Pin
Jeremy Falcon16-May-14 3:56
professionalJeremy Falcon16-May-14 3:56 
GeneralRe: Comments on the code. Pin
Bill_Hallahan16-May-14 22:34
Bill_Hallahan16-May-14 22:34 
GeneralRe: Comments on the code. Pin
Jeremy Falcon16-May-14 4:01
professionalJeremy Falcon16-May-14 4:01 
GeneralRe: Comments on the code. Pin
Bill_Hallahan16-May-14 22:21
Bill_Hallahan16-May-14 22:21 
GeneralRe: Comments on the code. Pin
Jeremy Falcon16-May-14 5:31
professionalJeremy Falcon16-May-14 5:31 
GeneralRe: Comments on the code. Pin
Bill_Hallahan16-May-14 23:17
Bill_Hallahan16-May-14 23:17 
GeneralRe: Comments on the code. Pin
Jeremy Falcon17-May-14 3:53
professionalJeremy Falcon17-May-14 3:53 
GeneralRe: Comments on the code. Pin
Bill_Hallahan17-May-14 9:23
Bill_Hallahan17-May-14 9:23 
GeneralRe: Comments on the code. Pin
Jeremy Falcon18-May-14 4:15
professionalJeremy Falcon18-May-14 4:15 
GeneralRe: Comments on the code. Pin
Bill_Hallahan25-May-14 19:31
Bill_Hallahan25-May-14 19:31 
QuestionAn Actor that write code? Pin
Member 761463224-Nov-13 19:00
Member 761463224-Nov-13 19:00 
AnswerRe: An Actor that write code? Pin
Jeremy Falcon17-Apr-14 7:57
professionalJeremy Falcon17-Apr-14 7:57 
GeneralFavor for a favor... some good alternatives. Pin
Shaun Harrington11-Aug-06 2:59
Shaun Harrington11-Aug-06 2:59 
GeneralRe: Favor for a favor... some good alternatives. Pin
Jeremy Falcon13-Jan-07 8:29
professionalJeremy Falcon13-Jan-07 8:29 
Questionhow to represent 1000.25 ???? Pin
Renjith Ramachandran10-Jan-05 18:20
Renjith Ramachandran10-Jan-05 18:20 
AnswerRe: how to represent 1000.25 ???? Pin
Jeremy Falcon13-Jan-07 7:29
professionalJeremy Falcon13-Jan-07 7:29 
QuestionCan we have the PHP? Pin
ChinaHorse18-Mar-04 17:19
ChinaHorse18-Mar-04 17:19 
AnswerRe: Can we have the PHP? Pin
Jeremy Falcon19-Mar-04 9:49
professionalJeremy Falcon19-Mar-04 9:49 
GeneralRe: Can we have the PHP? Pin
ChinaHorse21-Mar-04 0:28
ChinaHorse21-Mar-04 0:28 
GeneralRe: Can we have the PHP? Pin
Jeremy Falcon21-Mar-04 3:25
professionalJeremy Falcon21-Mar-04 3:25 
GeneralYes, SSH Pin
ChinaHorse21-Mar-04 22:17
ChinaHorse21-Mar-04 22:17 
GeneralRe: Yes, SSH Pin
Jeremy Falcon23-Jun-04 8:07
professionalJeremy Falcon23-Jun-04 8:07 

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.