Here's a version that can take 64 bit numbers:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int opt_d;
int opt_f;
typedef long long val_t;
#define ARRAY_SIZE(_arr) \
sizeof(_arr) / sizeof(_arr[0])
char *ones[] = {
NULL,
"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"
};
char *tens[] = {
NULL,
"ten", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty",
"ninety"
};
char *teens[] = {
NULL,
#if 0
"ten",
#endif
"eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
"seventeen", "eighteen", "nineteen"
};
const char *places[] = {
//NULL,
//NULL,
#if 0
"hundred",
#else
NULL,
#endif
"thousand",
"million",
"trillion",
"quadrillion",
#if 0
"quintillion",
#endif
#if 0
"sextillion", "septillion", "octillion", "nonillion", "decillion",
"undecillion", "duodecillion", "tredecillion", "quatttuor-decillion",
"quindecillion", "sexdecillion", "septen-decillion", "octodecillion"
#endif
};
#define BUFWID 1000
char *odst;
char obuf[BUFWID];
const char *curplace;
#if defined(DEBUG) || defined(_USE_ZPRT_)
#define dbgprt(_fmt...) \
do { \
if (opt_d) \
printf(_fmt); \
} while (0)
#else
#define dbgprt(_fmt...) \
do { } while (0)
#endif
val_t
ipow(int pow)
{
val_t acc = 1;
for (; pow > 0; --pow)
acc *= 1000;
return acc;
}
#define BUFMAX 20
char *
strbuf(void)
{
static int bufidx = 0;
static char bufpool[BUFMAX][BUFWID];
char *buf = bufpool[bufidx];
bufidx += 1;
bufidx %= BUFMAX;
*buf = 0;
return buf;
}
const char *
show(val_t val)
{
char *buf = strbuf();
char tmp[100];
int len = sprintf(tmp,"%lld",val);
int off = len % 3;
char *bp = buf;
for (char *src = tmp; *src != 0; ++src, --off) {
if (off == 0) {
if (src > tmp)
*bp++ = ',';
off = 3;
}
*bp++ = *src;
}
*bp = 0;
return buf;
}
void
append(const char *str)
{
if (str != NULL) {
if (odst > obuf)
*odst++ = ' ';
odst += sprintf(odst,"%s",str);
}
}
val_t
digout(val_t bigval,int div,char **str,char *midplace)
{
val_t cur = bigval / div;
dbgprt("digout: ENTER bigval=%s div=%d cur=%s str='%s' midplace='%s'\n",
show(bigval),div,show(cur),str[cur],midplace);
if (cur != 0) {
append(str[cur]);
append(midplace);
}
bigval %= div;
dbgprt("digout: EXIT bigval=%s\n",show(bigval));
return bigval;
}
void
group(val_t bigval,int plidx)
{
val_t cur;
dbgprt("group: ENTER bigval=%s plidx=%d curplace='%s'\n",
show(bigval),plidx,curplace);
bigval = digout(bigval,100,ones,"hundred");
if ((bigval > 10) && (bigval < 20))
bigval = digout(bigval - 10,1,teens,NULL);
else {
bigval = digout(bigval,10,tens,NULL);
bigval = digout(bigval,1,ones,NULL);
}
append(curplace);
dbgprt("group: EXIT\n");
}
void
pretty(val_t origval)
{
char tokbuf[BUFWID];
char *cp;
char *bp;
int totlen = 0;
sprintf(tokbuf,"%s -- %s",show(origval),obuf);
bp = tokbuf;
while (1) {
cp = strtok(bp," ");
if (cp == NULL)
break;
int toklen = strlen(cp);
if ((totlen + 1 + toklen) >= 72) {
printf("\n");
totlen = 0;
printf("+");
totlen += 1;
}
if (bp == NULL) {
printf(" ");
totlen += 1;
}
printf("%s",cp);
totlen += toklen;
bp = NULL;
}
if (totlen > 0)
printf("\n");
}
const char *
convert(val_t origval)
{
val_t bigval = origval;
odst = obuf;
*odst = 0;
int plidx = ARRAY_SIZE(places) - 1;
dbgprt("convert: ENTER bigval=%s plidx=%d\n",show(bigval),plidx);
while (bigval != 0) {
val_t div = ipow(plidx);
val_t cur = bigval / div;
val_t dig = cur / 1000;
curplace = places[plidx];
dbgprt("convert: LOOP bigval=%s plidx=%d div=%s cur=%s dig=%s curplace='%s'\n",
show(bigval),plidx,show(div),show(cur),show(dig),curplace);
if (cur != 0) {
group(cur,plidx);
dbgprt("convert: OBUF obuf='%s'\n",obuf);
}
bigval %= div;
plidx -= 1;
}
pretty(origval);
dbgprt("convert: EXIT obuf='%s'\n",obuf);
return obuf;
}
int
main(int argc,char **argv)
{
char *cp;
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = ! opt_d;
break;
case 'f':
opt_f = ! opt_f;
break;
}
}
int dodiag = 1;
for (; argc > 0; --argc, ++argv) {
dodiag = 0;
val_t val = strtoll(*argv,&cp,10);
convert(val);
}
if (dodiag) {
convert(1234);
convert(117);
convert(311);
convert(412);
convert(1234567);
convert(12319678);
convert(123456789);
convert(12345678927594);
}
return 0;
}
Here's the program's default output:
1,234 -- one thousand two hundred thirty four
117 -- one hundred seventeen
311 -- three hundred eleven
412 -- four hundred twelve
1,234,567 -- one million two hundred thirty four thousand five hundred
+ sixty seven
12,319,678 -- twelve million three hundred nineteen thousand six
+ hundred seventy eight
123,456,789 -- one hundred twenty three million four hundred fifty six
+ thousand seven hundred eighty nine
12,345,678,927,594 -- twelve quadrillion three hundred forty five
+ trillion six hundred seventy eight million nine hundred twenty seven
+ thousand five hundred ninety four