Modify a given number to find the required sum? - c

A friend of mine sent me this question. I haven't really been able to come up with any kind of algorithm to solve this problem.
You are provided with a no. say 123456789 and two operators * and +. Now without changing the sequence of the provided no. and using these operators as many times as you wish, evaluate the given value:
eg: given value 2097
Solution: 1+2+345*6+7+8+9
Any ideas on how to approach problems like these?

One of the easiest ways to do it is using shell expansion in BASH:
#!/bin/sh
for i in 1{,+,*}2{,+,*}3{,+,*}4{,+,*}5{,+,*}6{,+,*}7{,+,*}8{,+,*}9; do
if [ $(( $i )) == 2097 ]; then
echo $i = 2097
fi
done
which gives:
$ sh -c '. ./testequation.sh'
12*34+5*6*7*8+9 = 2097
12*3*45+6*78+9 = 2097
1+2+345*6+7+8+9 = 2097

There are not that many solutions - this python program takes under a second to bruteforce them all
from itertools import product
for q in product(("","+","*"), repeat=8):
e = ''.join(i+j for i,j in zip('12345678',q))+'9'
print e,'=',eval(e)
Here is a sample run through grep
$ python sums.py | grep 2097
12*34+5*6*7*8+9 = 2097
12*3*45+6*78+9 = 2097
1+2+345*6+7+8+9 = 2097
General solution is a simple modification
from itertools import product
def f(seq):
for q in product(("","+","*"), repeat=len(seq)-1):
e = ''.join(i+j for i,j in zip(seq[:-1],q))+seq[-1]
print e,'=',eval(e)

This isn't the easiest way, but I tried to write "optimized" code : genereting all the 3^(n-1) strings is expensive, and you've to evaluate a lot of them; I still used bruteforce, but cutting unproductive "subtrees" ( and the source is C, as requested in the title)
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "math.h"
#define B 10
void rec_solve(char *, char *, int, char, int, char, int, char *);
int main(int argc, char** argv) {
char *n, *si = malloc(0);
if (argc < 2) {
printf("Use : %s num sum", argv[0]);
} else {
n = calloc(strlen(argv[1]), sizeof (char));
strncpy(n, argv[1], strlen(argv[1]));
rec_solve(n, si, 0, '+', 0, '+', atoi(argv[2]), n);
}
return 0;
}
void rec_solve(char *str, char *sig, int p, char ps, int l, char ls, int max, char *or) {
int i, len = strlen(str), t = 0, siglen = strlen(sig), j, k;
char *mul;
char *add;
char *sub;
if (p + l <= max) {
if (len == 0) {
k = (ls == '+') ? p + l : p*l;
if ((k == max) && (sig[strlen(sig) - 1] == '+')) {
for (i = 0; i < strlen(or) - 1; i++) {
printf("%c", or[i]);
if (sig[i] && (sig[i] != ' '))
printf("%c", sig[i]);
}
printf("%c\n", or[i]);
}
} else {
for (i = 0; i < len; i++) {
t = B * t + (str[i] - '0');
if (t > max)
break;
sub = calloc(len - i - 1, sizeof (char));
strncpy(sub, str + i + 1, len - i - 1);
mul = calloc(siglen + i + 1, sizeof (char));
strncpy(mul, sig, siglen);
add = calloc(strlen(sig) + i + 1, sizeof (char));
strncpy(add, sig, siglen);
for (j = 0; j < i; j++) {
add[siglen + j] = ' ';
mul[siglen + j] = ' ';
}
add[siglen + i] = '+';
mul[siglen + i] = '*';
switch (ps) {
case '*':
switch (ls) {
case '*':
rec_solve(sub, add, p*l, '*', t, '+',max, or);
rec_solve(sub, mul, p*l, '*', t, '*',max, or);
break;
case '+':
rec_solve(sub, add, p*l, '+', t, '+',max, or);
rec_solve(sub, mul, p*l, '+', t, '*',max, or);
break;
}
case '+':
switch (ls) {
case '*':
rec_solve(sub,add,p, '+',l*t,'+',max, or);
rec_solve(sub,mul,p, '+',l*t,'*',max, or);
break;
case '+':
rec_solve(sub,add,p + l,'+',t,'+',max, or);
rec_solve(sub,mul,p + l,'+',t,'*',max, or);
break;
}
break;
}
}
}
}
}

Here's an implementation of a non-recursive C bruteforce version that will work for any set of digits (with reasonable values in the 32-bit range and not just for the example above). Now complete. :)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* simple integer pow() function */
int pow(int base, int pow)
{
int i, res = 1;
for (i = 0; i < pow; i++)
res *= base;
return res;
}
/* prints a value in base3 zeropadded */
void zeropad_base3(int value, char *buf, int width)
{
int length, dif;
_itoa(value, buf, 3);
length = strlen(buf);
dif = width - length;
/* zeropad the rest */
memmove(buf + dif, buf, length+1);
if (dif)
memset(buf, '0', dif);
}
int parse_factors(char **expr)
{
int num = strtol(*expr, expr, 10);
for ( ; ; )
{
if (**expr != '*')
return num;
(*expr)++;
num *= strtol(*expr, expr, 10);
}
}
/* evaluating using recursive descent parser */
int evaluate_expr(char* expr)
{
int num = parse_factors(&expr);
for ( ; ; )
{
if (*expr != '+')
return num;
expr++;
num += parse_factors(&expr);
}
}
void do_puzzle(const char *digitsString, int target)
{
int i, iteration, result;
int n = strlen(digitsString);
int iterCount = pow(3, n-1);
char *exprBuf = (char *)malloc(2*n*sizeof(char));
char *opBuf = (char *)malloc(n*sizeof(char));
/* try all combinations of possible expressions */
for (iteration = 0; iteration < iterCount; iteration++)
{
char *write = exprBuf;
/* generate the operation "opcodes" */
zeropad_base3(iteration, opBuf, n-1);
/* generate the expression */
*write++ = digitsString[0];
for (i = 1; i < n; i++)
{
switch(opBuf[i-1])
{
/* case '0' no op */
case '1': *write++ = '+'; break;
case '2': *write++ = '*'; break;
}
*write++ = digitsString[i];
}
*write = '\0';
result = evaluate_expr(exprBuf);
if (result == target)
printf("%s = %d\n", exprBuf, result);
}
free(opBuf);
free(exprBuf);
}
int main(void)
{
const char *digits = "123456789";
int target = 2097;
do_puzzle(digits, target);
return 0;
}
12*34+5*6*7*8+9 = 2097
12*3*45+6*78+9 = 2097
1+2+345*6+7+8+9 = 2097

You could work backwards and try to test for all possibilities that could give solution;
e.g:
1 (something) 9 = 10
1*9=10 - false
1/9=10 - false
1-9=10 - false
1+9=10 - True
So, basically brute force - but it is re-usable code given that the input could be different.

Related

why can't my program recognize similar words in a string?

I want to write a program that will take an input T. In the next T lines, each line will take a string as an input. The output would be how many ways the string can be reordered.
#include <stdio.h>
#include <stdlib.h>
int main() {
int T, i, l, count = 1, test = 0, word = 0, ans;
char line[200];
scanf("%d", &T);
for (i = 0; i < T; i++) {
scanf(" %[^\n]", line);
l = strlen(line);
for (int q = 0; q < l; q++) {
if (line[q] == ' ') {
word++;
}
}
ans = fact(word + 1);
word = 0;
for (int j = 0; j < l; j++) {
for (int k = j + 1; k < l; k++) {
if (line[k] == ' ' && line[k + 1] == line[j]) {
int m = j;
int n = k + 1;
for (;;) {
if (line[m] != line[n]) {
break;
} else
if (line[m] == ' ' && line[n] == ' ') {
test = 1;
break;
} else {
m++;
n++;
}
}
if (test == 1) {
count++;
ans = ans / fact(count);
count = 0;
test = 0;
}
}
}
}
printf("%d\n", ans);
}
}
int fact(int n) {
if (n == 1) {
return 1;
} else {
return n * fact(n - 1);
}
}
Now, in my program,
my output is like this:
2
no way no good
12
yes no yes yes no
120
if T = 2 and the 1st string is no way no good, it gives the right output that is 12 (4!/2!). That means, it has identified that there are two similar words.
But in the 2nd input, the string is yes no yes yes no. that means 3 yes and 2 nos. So the and should be 5!/(3!2!) = 10. But why is the answer 120? and why can't it recognize the similar words?
The main problem in your duplicate detector is you test the end of word with if (line[m] == ' ' && line[n] == ' ') but this test fails to identify a duplicate that occurs with the last word because line[n] is '\0', not ' '.
Note these further problems:
you do not handle words that occur more than twice correctly: you should perform ans = ans / fact(count); only after the outer loop finishes. For example, if a word is present 3 times, it will be detected as 3 pairs of duplicates, effectively causing ans to be divided by 23 = 8, instead of 3! = 6.
you should protect against buffer overflow and detect invalid input with:
if (scanf(" %199[^\n]", line) != 1)
break;
the range of type int for ans is too small for a moderately large number of words: 13! is 6227020800, larger than INT_MAX on most systems.
The code is difficult to follow. You should consider parsing the line into an array of words and using a more conventional way of counting duplicates.
Here is a modified version using this approach:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
static int cmpstr(const void *p1, const void *p2) {
char * const *pp1 = p1;
char * const *pp2 = p2;
return strcmp(*pp1, *pp2);
}
unsigned long long factorial(int n) {
unsigned long long res = 1;
while (n > 1)
res *= n--;
return res;
}
int main() {
int T, i, n, begin, count;
unsigned long long ans;
char line[200];
char *words[100];
if (!fgets(line, sizeof line, stdin) || sscanf(line, "%d", &T) != 1)
return 1;
while (T --> 0) {
if (!fgets(line, sizeof line, stdin))
break;
n = 0;
begin = 1;
for (char *p = line; *p; p++) {
if (isspace((unsigned char)*p)) {
*p = '\0';
begin = 1;
} else {
if (begin) {
words[n++] = p;
begin = 0;
}
}
}
qsort(words, n, sizeof(*words), cmpstr);
ans = factorial(n);
for (i = 0; i < n; i += count) {
for (count = 1; i + count < n && !strcmp(words[i], words[i + count]); count++)
continue;
ans /= factorial(count);
}
printf("%llu\n", ans);
}
return 0;
}

printf - implementation in C

This may be a silly question, but... I tried to implement printf, but for some reason the output I get is not exactly what I expected. any idea what it could be? I would appreciate some help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
static int print(const char *restrict fmt, ...);
static int getfloat(float *);
static char *itoa(int, char *, int);
static void _strrev(char *);
int
main(void)
{
float i1 = 0.0, i2 = 0.0, noi1 = 0.0, noi2 = 0.0, res = 0.0;
print("weight - item 1: ");
getfloat(&i1);
print("no. of item 1: ");
getfloat(&noi1);
print("weight - item 2: ");
getfloat(&i2);
print("no. of item 2: ");
getfloat(&noi2);
res = ((i1 * noi1) + (i2 * noi2)) / (noi1 + noi2);
print("%f\n", res);
exit(EXIT_SUCCESS);
}
static int
print(const char *restrict fmt, ...)
{
va_list ap;
char buf[BUFSIZ] = {0}, tmp[20] = {0};
char *str_arg;
int i = 0, j = 0;
va_start(ap, fmt);
while (fmt[i] != '\0') {
if (fmt[i] == '%') {
i++;
switch (fmt[i]) {
case 'c':
buf[j] = (char)va_arg(ap, int);
j++;
break;
case 'd':
itoa(va_arg(ap, int), tmp, 10);
strcpy(&buf[j], tmp);
j += strlen(tmp);
break;
case 'f':
gcvt(va_arg(ap, double), 10, tmp);
strcpy(&buf[j], tmp);
j += strlen(tmp);
break;
case 's':
str_arg = va_arg(ap, char *);
strcpy(&buf[j], str_arg);
j += strlen(str_arg);
break;
default:
break;
}
} else { buf[j++ ] = fmt[i]; }
++i;
}
fwrite(buf, j, 1, stdout);
va_end(ap);
return (j);
}
static int
getfloat(float *p)
{
int c, sign = 0;
float pwr = 0.0;
while (c = getc(stdin), c == ' ' || c == '\t' || c == '\n')
; /* ignore white spaces */
sign = 1; /* record sign */
if (c == '+' || c == '-') {
sign = (c == '+') ? 1 : -1;
c = getc(stdin);
}
for (*p = 0.0; isdigit(c); c = getc(stdin))
*p = 10.0 * *p + c - '0';
if (c == '.') { c = getc(stdin); }
for (pwr = 1.0; isdigit(c); c = getc(stdin)) {
*p = 10.0 * *p + c - '0';
pwr *= 10.0;
}
*p *= sign / pwr;
if (c != EOF)
ungetc(c, stdout);
return (float)c;
}
static char *
itoa(int n, char *strout, int base)
{
int i, sign;
if ((sign = n) < 0)
n -= n;
i = 0;
do {
strout[i++] = n % base + '0';
} while ((n /= base) != 0);
if (sign < 0) { strout[i++] = '-'; }
strout[i] = '\0';
_strrev(strout);
return (strout);
}
static void
_strrev(char *str)
{
int i = 0, j = strlen(str) - 1;
for ( ; i < j; ++i, --j) {
int tmp = str[i];
str[i] = str[j];
str[j] = tmp;
}
}
here is the output I get:
19.44444466
and this is the output that I expect: (or the one that I would at least like to receive, which is the one in itself that I get when I use printf)
19.444445
f, F The double argument is rounded and converted to decimal
notation in the style [-]ddd.ddd, where the number of
digits after the decimal-point character is equal to the
precision specification. If the precision is missing, it
is taken as 6;
https://man7.org/linux/man-pages/man3/printf.3.html
The default precision for %f is six so printf() is rounding the result to six decimal places.
You'd need to play with the ndigit argument to gcvt() which is the total number of significant digits (both before and after the decimal point). You are passing in 10 so your answer has two digits before the decimal and eight after for this particular number.
Seems that gcvt() don't do exactly what printf() do, at least with your compiler. Check it with a "real" printf with the same value.
Since you didn't gave the numbers you used for the test (avoid getfloat() and initialize directly i1, i2, noi1 and noi2 with required constants in your question), I can't run it and tell you why exactly - or if it even happens with my own compiler.
Usually, the source code for printf is at least two times bigger than yours, so you may have missed some vicious subcases. If I remember well, printf has code to decode an IEEE-754 directly and don't rely on gcvt.

How to format number adding points between each 3 numbers [duplicate]

In C, how can I format a large number from e.g. 1123456789 to 1,123,456,789?
I tried using printf("%'10d\n", 1123456789), but that doesn't work.
Could you advise anything? The simpler the solution the better.
If your printf supports the ' flag (as required by POSIX 2008 printf()), you can probably do it just by setting your locale appropriately. Example:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("%'d\n", 1123456789);
return 0;
}
And build & run:
$ ./example
1,123,456,789
Tested on Mac OS X & Linux (Ubuntu 10.10).
You can do it recursively as follows (beware INT_MIN if you're using two's complement, you'll need extra code to manage that):
void printfcomma2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma2 (n/1000);
printf (",%03d", n%1000);
}
void printfcomma (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfcomma2 (n);
}
A summmary:
User calls printfcomma with an integer, the special case of negative numbers is handled by simply printing "-" and making the number positive (this is the bit that won't work with INT_MIN).
When you enter printfcomma2, a number less than 1,000 will just print and return.
Otherwise the recursion will be called on the next level up (so 1,234,567 will be called with 1,234, then 1) until a number less than 1,000 is found.
Then that number will be printed and we'll walk back up the recursion tree, printing a comma and the next number as we go.
There is also the more succinct version though it does unnecessary processing in checking for negative numbers at every level (not that this will matter given the limited number of recursion levels). This one is a complete program for testing:
#include <stdio.h>
void printfcomma (int n) {
if (n < 0) {
printf ("-");
printfcomma (-n);
return;
}
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma (n/1000);
printf (",%03d", n%1000);
}
int main (void) {
int x[] = {-1234567890, -123456, -12345, -1000, -999, -1,
0, 1, 999, 1000, 12345, 123456, 1234567890};
int *px = x;
while (px != &(x[sizeof(x)/sizeof(*x)])) {
printf ("%-15d: ", *px);
printfcomma (*px);
printf ("\n");
px++;
}
return 0;
}
and the output is:
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
An iterative solution for those who don't trust recursion (although the only problem with recursion tends to be stack space which will not be an issue here since it'll only be a few levels deep even for a 64-bit integer):
void printfcomma (int n) {
int n2 = 0;
int scale = 1;
if (n < 0) {
printf ("-");
n = -n;
}
while (n >= 1000) {
n2 = n2 + scale * (n % 1000);
n /= 1000;
scale *= 1000;
}
printf ("%d", n);
while (scale != 1) {
scale /= 1000;
n = n2 / scale;
n2 = n2 % scale;
printf (",%03d", n);
}
}
Both of these generate 2,147,483,647 for INT_MAX.
All the code above is for comma-separating three-digit groups but you can use other characters as well, such as a space:
void printfspace2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfspace2 (n/1000);
printf (" %03d", n%1000);
}
void printfspace (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfspace2 (n);
}
Here's a very simple implementation. This function contains no error checking, buffer sizes must be verified by the caller. It also does not work for negative numbers. Such improvements are left as an exercise for the reader.
void format_commas(int n, char *out)
{
int c;
char buf[20];
char *p;
sprintf(buf, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = ',';
}
c = (c + 1) % 3;
}
*--out = 0;
}
Egads! I do this all the time, using gcc/g++ and glibc on linux and yes, the ' operator may be non-standard, but I like the simplicity of it.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %'d\n",bignum);
return 0;
}
Gives output of:
Big number: 12,345,678
Just have to remember the 'setlocale' call in there, otherwise it won't format anything.
Perhaps a locale-aware version would be interesting.
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
static int next_group(char const **grouping) {
if ((*grouping)[1] == CHAR_MAX)
return 0;
if ((*grouping)[1] != '\0')
++*grouping;
return **grouping;
}
size_t commafmt(char *buf, /* Buffer for formatted string */
int bufsize, /* Size of buffer */
long N) /* Number to convert */
{
int i;
int len = 1;
int posn = 1;
int sign = 1;
char *ptr = buf + bufsize - 1;
struct lconv *fmt_info = localeconv();
char const *tsep = fmt_info->thousands_sep;
char const *group = fmt_info->grouping;
char const *neg = fmt_info->negative_sign;
size_t sep_len = strlen(tsep);
size_t group_len = strlen(group);
size_t neg_len = strlen(neg);
int places = (int)*group;
if (bufsize < 2)
{
ABORT:
*buf = '\0';
return 0;
}
*ptr-- = '\0';
--bufsize;
if (N < 0L)
{
sign = -1;
N = -N;
}
for ( ; len <= bufsize; ++len, ++posn)
{
*ptr-- = (char)((N % 10L) + '0');
if (0L == (N /= 10L))
break;
if (places && (0 == (posn % places)))
{
places = next_group(&group);
for (int i=sep_len; i>0; i--) {
*ptr-- = tsep[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
if (len >= bufsize)
goto ABORT;
}
if (sign < 0)
{
if (len >= bufsize)
goto ABORT;
for (int i=neg_len; i>0; i--) {
*ptr-- = neg[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
memmove(buf, ++ptr, len + 1);
return (size_t)len;
}
#ifdef TEST
#include <stdio.h>
#define elements(x) (sizeof(x)/sizeof(x[0]))
void show(long i) {
char buffer[32];
commafmt(buffer, sizeof(buffer), i);
printf("%s\n", buffer);
commafmt(buffer, sizeof(buffer), -i);
printf("%s\n", buffer);
}
int main() {
long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 };
for (int i=0; i<elements(inputs); i++) {
setlocale(LC_ALL, "");
show(inputs[i]);
}
return 0;
}
#endif
This does have a bug (but one I'd consider fairly minor). On two's complement hardware, it won't convert the most-negative number correctly, because it attempts to convert a negative number to its equivalent positive number with N = -N; In two's complement, the maximally negative number doesn't have a corresponding positive number, unless you promote it to a larger type. One way to get around this is by promoting the number the corresponding unsigned type (but it's is somewhat non-trivial).
Without recursion or string handling, a mathematical approach:
#include <stdio.h>
#include <math.h>
void print_number( int n )
{
int order_of_magnitude = (n == 0) ? 1 : (int)pow( 10, ((int)floor(log10(abs(n))) / 3) * 3 ) ;
printf( "%d", n / order_of_magnitude ) ;
for( n = abs( n ) % order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
printf( ",%03d", abs(n / order_of_magnitude) ) ;
}
}
Similar in principle to Pax's recursive solution, but by calculating the order of magnitude in advance, recursion is avoided (at some considerable expense perhaps).
Note also that the actual character used to separate thousands is locale specific.
Edit:See #Chux's comments below for improvements.
Based on #Greg Hewgill's, but takes negative numbers into account and returns the string size.
size_t str_format_int_grouped(char dst[16], int num)
{
char src[16];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%d", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return (size_t)(p_dst - dst);
}
Needed to do something similar myself but rather than printing directly, needed to go to a buffer. Here's what I came up with. Works backwards.
unsigned int IntegerToCommaString(char *String, unsigned long long Integer)
{
unsigned int Digits = 0, Offset, Loop;
unsigned long long Copy = Integer;
do {
Digits++;
Copy /= 10;
} while (Copy);
Digits = Offset = ((Digits - 1) / 3) + Digits;
String[Offset--] = '\0';
Copy = Integer;
Loop = 0;
do {
String[Offset] = '0' + (Copy % 10);
if (!Offset--)
break;
if (Loop++ % 3 == 2)
String[Offset--] = ',';
Copy /= 10;
} while (1);
return Digits;
}
Be aware that it's only designed for unsigned integers and you must ensure that the buffer is large enough.
There's no real simple way to do this in C. I would just modify an int-to-string function to do it:
void format_number(int n, char * out) {
int i;
int digit;
int out_index = 0;
for (i = n; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
out[out_index] = '\0';
// then you reverse the out string as it was converted backwards (it's easier that way).
// I'll let you figure that one out.
strrev(out);
}
My answer does not format the result exactly like the illustration in the question, but may fulfill the actual need in some cases with a simple one-liner or macro. One can extend it to generate more thousand-groups as necessary.
The result will look for example as follows:
Value: 0'000'012'345
The code:
printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
#include <stdio.h>
void punt(long long n){
char s[28];
int i = 27;
if(n<0){n=-n; putchar('-');}
do{
s[i--] = n%10 + '0';
if(!(i%4) && n>9)s[i--]='.';
n /= 10;
}while(n);
puts(&s[++i]);
}
int main(){
punt(2134567890);
punt(987);
punt(9876);
punt(-987);
punt(-9876);
punt(-654321);
punt(0);
punt(1000000000);
punt(0x7FFFFFFFFFFFFFFF);
punt(0x8000000000000001); // -max + 1 ...
}
My solution uses a . instead of a ,
It is left to the reader to change this.
This is old and there are plenty of answers but the question was not "how can I write a routine to add commas" but "how can it be done in C"? The comments pointed to this direction but on my Linux system with GCC, this works for me:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
unsetenv("LC_ALL");
setlocale(LC_NUMERIC, "");
printf("%'lld\n", 3141592653589);
}
When this is run, I get:
$ cc -g comma.c -o comma && ./comma
3,141,592,653,589
If I unset the LC_ALL variable before running the program the unsetenv is not necessary.
Another solution, by saving the result into an int array, maximum size of 7 because the long long int type can handle numbers in the range 9,223,372,036,854,775,807 to -9,223,372,036,854,775,807. (Note it is not an unsigned value).
Non-recursive printing function
static void printNumber (int numbers[8], int loc, int negative)
{
if (negative)
{
printf("-");
}
if (numbers[1]==-1)//one number
{
printf("%d ", numbers[0]);
}
else
{
printf("%d,", numbers[loc]);
while(loc--)
{
if(loc==0)
{// last number
printf("%03d ", numbers[loc]);
break;
}
else
{ // number in between
printf("%03d,", numbers[loc]);
}
}
}
}
main function call
static void getNumWcommas (long long int n, int numbers[8])
{
int i;
int negative=0;
if (n < 0)
{
negative = 1;
n = -n;
}
for(i = 0; i < 7; i++)
{
if (n < 1000)
{
numbers[i] = n;
numbers[i+1] = -1;
break;
}
numbers[i] = n%1000;
n/=1000;
}
printNumber(numbers, i, negative);// non recursive print
}
testing output
-9223372036854775807: -9,223,372,036,854,775,807
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
9223372036854775807 : 9,223,372,036,854,775,807
In main() function:
int numberSeparated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeparated);
If printing is all that's needed then move int numberSeparated[8]; inside the function getNumWcommas and call it this way getNumWcommas(number).
Another iterative function
int p(int n) {
if(n < 0) {
printf("-");
n = -n;
}
int a[sizeof(int) * CHAR_BIT / 3] = { 0 };
int *pa = a;
while(n > 0) {
*++pa = n % 1000;
n /= 1000;
}
printf("%d", *pa);
while(pa > a + 1) {
printf(",%03d", *--pa);
}
}
Here is the slimiest, size and speed efficient implementation of this kind of decimal digit formating:
const char *formatNumber (
int value,
char *endOfbuffer,
bool plus)
{
int savedValue;
int charCount;
savedValue = value;
if (unlikely (value < 0))
value = - value;
*--endOfbuffer = 0;
charCount = -1;
do
{
if (unlikely (++charCount == 3))
{
charCount = 0;
*--endOfbuffer = ',';
}
*--endOfbuffer = (char) (value % 10 + '0');
}
while ((value /= 10) != 0);
if (unlikely (savedValue < 0))
*--endOfbuffer = '-';
else if (unlikely (plus))
*--endOfbuffer = '+';
return endOfbuffer;
}
Use as following:
char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));
Output:
test : +1,234,567,890.
Some advantages:
Function taking end of string buffer because of reverse ordered formatting. Finally, where is no need in revering generated string (strrev).
This function produces one string that can be used in any algo after. It not depends nor require multiple printf/sprintf calls, which is terrible slow and always context specific.
Minimum number of divide operators (/, %).
Secure format_commas, with negative numbers:
Because VS < 2015 doesn't implement snprintf, you need to do this
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
And then
char* format_commas(int n, char *out)
{
int c;
char buf[100];
char *p;
char* q = out; // Backup pointer for return...
if (n < 0)
{
*out++ = '-';
n = abs(n);
}
snprintf(buf, 100, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = '\'';
}
c = (c + 1) % 3;
}
*--out = 0;
return q;
}
Example usage:
size_t currentSize = getCurrentRSS();
size_t peakSize = getPeakRSS();
printf("Current size: %d\n", currentSize);
printf("Peak size: %d\n\n\n", peakSize);
char* szcurrentSize = (char*)malloc(100 * sizeof(char));
char* szpeakSize = (char*)malloc(100 * sizeof(char));
printf("Current size (f): %s\n", format_commas((int)currentSize, szcurrentSize));
printf("Peak size (f): %s\n", format_commas((int)currentSize, szpeakSize));
free(szcurrentSize);
free(szpeakSize);
A modified version of #paxdiablo solution, but using WCHAR and wsprinf:
static WCHAR buffer[10];
static int pos = 0;
void printfcomma(const int &n) {
if (n < 0) {
wsprintf(buffer + pos, TEXT("-"));
pos = lstrlen(buffer);
printfcomma(-n);
return;
}
if (n < 1000) {
wsprintf(buffer + pos, TEXT("%d"), n);
pos = lstrlen(buffer);
return;
}
printfcomma(n / 1000);
wsprintf(buffer + pos, TEXT(",%03d"), n % 1000);
pos = lstrlen(buffer);
}
void my_sprintf(const int &n)
{
pos = 0;
printfcomma(n);
}
I'm new in C programming. Here is my simple code.
int main()
{
// 1223 => 1,223
int n;
int a[10];
printf(" n: ");
scanf_s("%d", &n);
int i = 0;
while (n > 0)
{
int temp = n % 1000;
a[i] = temp;
n /= 1000;
i++;
}
for (int j = i - 1; j >= 0; j--)
{
if (j == 0)
{
printf("%d.", a[j]);
}
else printf("%d,",a[j]);
}
getch();
return 0;
}
Require: <stdio.h> + <string.h>.
Advantage: short, readable, based on the format of scanf-family. And assume no comma on the right of decimal point.
void add_commas(char *in, char *out) {
int len_in = strlen(in);
int len_int = -1; /* len_int(123.4) = 3 */
for (int i = 0; i < len_in; ++i) if (in[i] == '.') len_int = i;
int pos = 0;
for (int i = 0; i < len_in; ++i) {
if (i>0 && i<len_int && (len_int-i)%3==0)
out[pos++] = ',';
out[pos++] = in[i];
}
out[pos] = 0; /* Append the '\0' */
}
Example, to print a formatted double:
#include <stdio.h>
#include <string.h>
#define COUNT_DIGIT_MAX 100
int main() {
double sum = 30678.7414;
char input[COUNT_DIGIT_MAX+1] = { 0 }, output[COUNT_DIGIT_MAX+1] = { 0 };
snprintf(input, COUNT_DIGIT_MAX, "%.2f", sum/12);
add_commas(input, output);
printf("%s\n", output);
}
Output:
2,556.56
Using C++'s std::string as return value with possibly the least overhead and not using any std library functions (sprintf, to_string, etc.).
string group_digs_c(int num)
{
const unsigned int BUF_SIZE = 128;
char buf[BUF_SIZE] = { 0 }, * pbuf = &buf[BUF_SIZE - 1];
int k = 0, neg = 0;
if (num < 0) { neg = 1; num = num * -1; };
while(num)
{
if (k > 0 && k % 3 == 0)
*pbuf-- = ',';
*pbuf-- = (num % 10) + '0';
num /= 10;
++k;
}
if (neg)
*pbuf = '-';
else
++pbuf;
int cc = buf + BUF_SIZE - pbuf;
memmove(buf, pbuf, cc);
buf[cc] = 0;
string rv = buf;
return rv;
}
Here is a simple portable solution relying on sprintf:
#include <stdio.h>
// assuming out points to an array of sufficient size
char *format_commas(char *out, int n, int min_digits) {
int len = sprintf(out, "%.*d", min_digits, n);
int i = (*out == '-'), j = len, k = (j - i - 1) / 3;
out[j + k] = '\0';
while (k-- > 0) {
j -= 3;
out[j + k + 3] = out[j + 2];
out[j + k + 2] = out[j + 1];
out[j + k + 1] = out[j + 0];
out[j + k + 0] = ',';
}
return out;
}
The code is easy to adapt for other integer types.
There are many interesting contributions here. Some covered all cases, some did not. I picked four of the contributions to test, found some failure cases during testing and then added a solution of my own.
I tested all methods for both accuracy and speed. Even though the OP only requested a solution for one positive number, I upgraded the contributions that didn't cover all possible numbers (so the code below may be slightly different from the original postings). The cases that weren't covered include: 0, negative numbers and the minimum number (INT_MIN).
I changed the declared type from "int" to "long long" since it's more general and all ints will get promoted to long long. I also standardized the call interface to include the number as well as a buffer to contain the formatted string (like some of the contributions) and returned a pointer to the buffer:
char* funcName(long long number_to_format, char* string_buffer);
Including a buffer parameter is considered by some to be "better" than having the function: 1) contain a static buffer (would not be re-entrant) or 2) allocate space for the buffer (would require caller to de-allocate the memory) or 3) print the result directly to stdout (would not be as generally useful since the output may be targeted for a GUI widget, file, pty, pipe, etc.).
I tried to use the same function names as the original contributions to make it easier to refer back to the originals. Contributed functions were modified as needed to pass the accuracy test so that the speed test would be meaningful. The results are included here in case you would like to test more of the contributed techniques for comparison. All code and test code used to generate the results are shown below.
So, here are the results:
Accuracy Test (test cases: LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX):
----------------------------------------------------
print_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtLocale:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtCommas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
format_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
itoa_commas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
Speed Test: (1 million calls, values reflect average time per call)
----------------------------------------------------
print_number: 0.747 us (microsec) per call
fmtLocale: 0.222 us (microsec) per call
fmtCommas: 0.212 us (microsec) per call
format_number: 0.124 us (microsec) per call
itoa_commas: 0.085 us (microsec) per call
Since all contributed techniques are fast (< 1 microsecond on my laptop), unless you need to format millions of numbers, any of the techniques should be acceptable. It's probably best to choose the technique that is most readable to you.
Here is the code:
#line 2 "comma.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <locale.h>
#include <limits.h>
// ----------------------------------------------------------
char* print_number( long long n, char buf[32] ) {
long long order_of_magnitude = (n == 0) ? 1
: (long long)pow( 10, ((long long)floor(log10(fabs(n))) / 3) * 3 ) ;
char *ptr = buf;
sprintf(ptr, "%d", n / order_of_magnitude ) ;
for( n %= order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
ptr += strlen(ptr);
sprintf(ptr, ",%03d", abs(n / order_of_magnitude) );
}
return buf;
}
// ----------------------------------------------------------
char* fmtLocale(long long i, char buf[32]) {
sprintf(buf, "%'lld", i); // requires setLocale in main
return buf;
}
// ----------------------------------------------------------
char* fmtCommas(long long num, char dst[32]) {
char src[27];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%lld", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return dst;
}
// ----------------------------------------------------------
char* format_number(long long n, char out[32]) {
int digit;
int out_index = 0;
long long i = (n < 0) ? -n : n;
if (i == LLONG_MIN) i = LLONG_MAX; // handle MIN, offset by 1
if (i == 0) { out[out_index++] = '0'; } // handle 0
for ( ; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
if (n == LLONG_MIN) { out[0]++; } // correct for offset
if (n < 0) { out[out_index++] = '-'; }
out[out_index] = '\0';
// then you reverse the out string
for (int i=0, j = strlen(out) - 1; i<=j; ++i, --j) {
char tmp = out[i];
out[i] = out[j];
out[j] = tmp;
}
return out;
}
// ----------------------------------------------------------
char* itoa_commas(long long i, char buf[32]) {
char* p = buf + 31;
*p = '\0'; // terminate string
if (i == 0) { *(--p) = '0'; return p; } // handle 0
long long n = (i < 0) ? -i : i;
if (n == LLONG_MIN) n = LLONG_MAX; // handle MIN, offset by 1
for (int j=0; 1; ++j) {
*--p = '0' + n % 10; // insert digit
if ((n /= 10) <= 0) break;
if (j % 3 == 2) *--p = ','; // insert a comma
}
if (i == LLONG_MIN) { p[24]++; } // correct for offset
if (i < 0) { *--p = '-'; }
return p;
}
// ----------------------------------------------------------
// Test Accuracy
// ----------------------------------------------------------
void test_accuracy(char* name, char* (*func)(long long n, char* buf)) {
char sbuf[32]; // string buffer
long long nbuf[] = { LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX };
printf("%s:\n", name);
printf(" %s", func(nbuf[0], sbuf));
for (int i=1; i < sizeof(nbuf) / sizeof(long long int); ++i) {
printf(", %s", func(nbuf[i], sbuf));
}
printf("\n");
}
// ----------------------------------------------------------
// Test Speed
// ----------------------------------------------------------
void test_speed(char* name, char* (*func)(long long n, char* buf)) {
int cycleCount = 1000000;
//int cycleCount = 1;
clock_t start;
double elapsed;
char sbuf[32]; // string buffer
start = clock();
for (int i=0; i < cycleCount; ++i) {
char* s = func(LLONG_MAX, sbuf);
}
elapsed = (double)(clock() - start) / (CLOCKS_PER_SEC / 1000000.0);
printf("%14s: %7.3f us (microsec) per call\n", name, elapsed / cycleCount);
}
// ----------------------------------------------------------
int main(int argc, char* argv[]){
setlocale(LC_ALL, "");
printf("\nAccuracy Test: (LLONG_MIN, -999, 0, 99, LLONG_MAX)\n");
printf("----------------------------------------------------\n");
test_accuracy("print_number", print_number);
test_accuracy("fmtLocale", fmtLocale);
test_accuracy("fmtCommas", fmtCommas);
test_accuracy("format_number", format_number);
test_accuracy("itoa_commas", itoa_commas);
printf("\nSpeed Test: 1 million calls\n\n");
printf("----------------------------------------------------\n");
test_speed("print_number", print_number);
test_speed("fmtLocale", fmtLocale);
test_speed("fmtCommas", fmtCommas);
test_speed("format_number", format_number);
test_speed("itoa_commas", itoa_commas);
return 0;
}
Can be done pretty easily...
//Make sure output buffer is big enough and that input is a valid null terminated string
void pretty_number(const char* input, char * output)
{
int iInputLen = strlen(input);
int iOutputBufferPos = 0;
for(int i = 0; i < iInputLen; i++)
{
if((iInputLen-i) % 3 == 0 && i != 0)
{
output[iOutputBufferPos++] = ',';
}
output[iOutputBufferPos++] = input[i];
}
output[iOutputBufferPos] = '\0';
}
Example call:
char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
void printfcomma ( long long unsigned int n)
{
char nstring[100];
int m;
int ptr;
int i,j;
sprintf(nstring,"%llu",n);
m=strlen(nstring);
ptr=m%3;
if (ptr)
{ for (i=0;i<ptr;i++) // print first digits before comma
printf("%c", nstring[i]);
printf(",");
}
j=0;
for (i=ptr;i<m;i++) // print the rest inserting commas
{
printf("%c",nstring[i]);
j++;
if (j%3==0)
if(i<(m-1)) printf(",");
}
}
// separate thousands
int digit;
int idx = 0;
static char buffer[32];
char* p = &buffer[32];
*--p = '\0';
for (int i = fCounter; i != 0; i /= 10)
{
digit = i % 10;
if ((p - buffer) % 4 == 0)
*--p = ' ';
*--p = digit + '0';
}

Adding two strings made of digits recursively in C

For this problem, I am to first take in two strings using fgets. I then need to check if the string is comprised entirely of digits thus making it a number. I was able to do this part recursively, but the next task is if the strings are numbers, I need to sum them up recursively as well. So for example,
the output of the program may look something like this:
First number > 9023905350290349
Second number > 90283056923840923840239480239480234
Sum is 90283056923840923849263385589770583
Again, I need to do this recursively, so I was thinking I could march along the stream of digits and add them together, but I am not so sure how to write this program recursively. Also since the input is in character form, I would also have to convert it to an integer, which I believe I can do by converting the individual characters to the integer ASCII value then subtracting 48 away from it. Any help would be appreciated. Thanks!
You're on the right track. Your recursive approach to checking if the input is a number looks something like the following, right? Notice that you can go ahead and subtract '0' from a character without bothering to convert it to 48 yourself.
int number_length(char *s, int pos) {
int d;
if (s[pos] == '\0') {
return pos;
}
d = s[pos] - '0';
if (d < 0 || d > 9) {
return -1;
}
return number_length(s, pos+1);
}
The above function returns -1 if the input is invalid, and the length of the number otherwise. We can use the length of the input numbers when we start the recursive addition process.
Where should the recursion begin? When we add a pair of numbers, it is convenient to start from the least significant digits.
If we have a pair of char * variables a and b pointing to the numbers, and if we know that a contains a_length digits and b contains b_length digits, then:
The least significant digit of a is at a_length-1.
The least significant digit of b is at b_length-1.
We don't know in advance how long the result is going to be, so let's build up the digits in an int * array starting from position 0. This means that we'll have the result digits in reverse, so we'll print them out starting from the end and going back to 0.
The core of the computation is this:
Given a position a_pos in a and b_pos in b, as well as a carry digit carry, compute the sum of the digits in a and b together with the carry digit.
Update the carry digit.
Add the result digit to the result array and update the length of the array.
In C, we can express the computation as follows:
d = a[a_pos--] + b[b_pos--] - 2*'0' + carry;
carry = (d >= 10 ? 1 : 0);
result[result_pos++] = d%10;
The expression a[a_pos--] + b[b_pos--] becomes invalid once a_pos or b_pos has become negative. In other words, we must deal with situations where we have run out of digits in one or both numbers. We must take care to:
Handle cases where we've already processed the most significant digit of a but not b, or b but not a.
When we've reached the end of both a and b, remember to check the carry digit: if it's 1, add it to the result and increment the length of the result.
Below is a complete implementation in ANSI C.
#include <stdio.h>
#include <string.h>
#define BUFFER_SIZE 8192
char a[BUFFER_SIZE], b[BUFFER_SIZE];
int result[BUFFER_SIZE];
int number_length(char *s, int pos) {
int d;
if (s[pos] == '\0') {
return pos;
}
d = s[pos] - '0';
if (d < 0 || d > 9) {
return -1;
}
return number_length(s, pos+1);
}
int add(char *a, int a_pos, char *b, int b_pos,
int *result, int result_pos, int carry) {
int d;
if (a_pos < 0 && b_pos < 0) {
if (carry == 1) {
result[result_pos++] = 1;
}
return result_pos;
}
if (a_pos < 0) {
result[result_pos++] = b[b_pos--] - '0' + carry;
carry = 0;
} else if (b_pos < 0) {
result[result_pos++] = a[a_pos--] - '0' + carry;
carry = 0;
} else {
d = a[a_pos--] + b[b_pos--] - 2*'0' + carry;
carry = (d >= 10 ? 1 : 0);
result[result_pos++] = d%10;
}
return add(a, a_pos, b, b_pos, result, result_pos, carry);
}
int main() {
int a_length, b_length, i, result_length;
printf("First number > ");
scanf("%s", a);
if ((a_length = number_length(a, 0)) == -1) {
printf("%s is not a number.\n", a);
return 0;
}
printf("Second number > ");
scanf("%s", b);
if ((b_length = number_length(b, 0)) == -1) {
printf("%s is not a number.\n", b);
return 0;
}
result_length = add(a, a_length-1, b, b_length-1, result, 0, 0);
for (i = result_length-1; i >= 0; --i) {
printf("%d", result[i]);
}
printf("\n");
return 0;
}
UPDATE: the comment below made me realize that I've obviously misunderstood the question. My previous solution of course wouldn't have worked with huge numbers like the ones in the OP's question. I've updated my answer accordingly as "right to left" approach. The only problem is that the resulting string can have a leading zero...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void add_helper(const char *s1, const char *s2, int s1_pos, int s2_pos,
char *result, int pos, int carry) {
int d1 = 0;
int d2 = 0;
if (s1_pos >= 0) {
d1 = s1[s1_pos] - '0';
s1_pos--;
}
if (s2_pos >= 0) {
d2 = s2[s2_pos] - '0';
s2_pos--;
}
int d = d1 + d2 + carry;
carry = d > 9 ? 1 : 0;
result[pos] = '0' + (d % 10);
pos--;
if (s1_pos >= 0 || s2_pos >= 0)
add_helper(s1, s2, s1_pos, s2_pos, result, pos, carry);
else if (pos >= 0)
result[pos] = '0' + carry;
}
char *add_recurse(const char *s1, const char *s2) {
size_t s1_len = strlen(s1);
size_t s2_len = strlen(s2);
size_t result_len = (s1_len > s2_len ? s1_len : s2_len) + 1;
char *result = calloc(result_len, 1);
add_helper(s1, s2, s1_len-1, s2_len-1, result, result_len - 1, 0);
return result;
}
int main(int argc, char **argv)
{
char *num_str1 = "9023905350290349";
char *num_str2 = "90283056923840923840239480239480234";
printf("sum is %s\n", add_recurse(num_str1, num_str2));
}
Note that there is no error handling whatsoever and I assume the preconditions, that the input strings are valid strings consisting of only digits, which you said you have already checked it.
ADDED SINGLE PASS VERSION (for Jean-Baptiste Yunès, who considers the usage of 'strlen' a little bit cheating...):
int add_helper2(const char *s1, const char *s2, int acc1, int acc2,
int *s1_pos, int *s2_pos, int *pos, char **result) {
int carry = 0;
int d1 = 0;
int d2 = 0;
if (s1[acc1] || s2[acc2]) {
int t1 = (s1[acc1] != 0);
int t2 = (s2[acc2] != 0);
carry = add_helper2(s1, s2, acc1+t1, acc2+t2, s1_pos,
s2_pos, pos, result);
} else {
size_t result_len = (acc1 > acc2 ? acc1 : acc2) + 1;
*result = calloc(result_len, 1);
*s1_pos = acc1 - 1;
*s2_pos = acc2 - 1;
*pos = result_len - 1;
return 0;
}
if (*s1_pos >= 0) {
d1 = s1[*s1_pos] - '0';
*s1_pos -= 1;
}
if (*s2_pos >= 0) {
d2 = s2[*s2_pos] - '0';
*s2_pos -= 1;
}
int d = d1 + d2 + carry;
carry = d > 9 ? 1 : 0;
(*result)[*pos] = '0' + (d % 10);
*pos -= 1;
return carry;
}
char *add_recurse2(const char *s1, const char *s2) {
char *result;
int s1_pos, s2_pos, pos;
int carry = add_helper2(s1, s2, 0, 0, &s1_pos, &s2_pos, &pos, &result);
result[0] = '0' + carry;
return result;
}
Make it in a single recursive descent is not so easy, but this can make it :
char n1[] = "9023905350290349";
char n2[] = "90283056923840923840239480239480234";
char n3[1000];
char addchar(char c,char d,int r) {
return ((c-'0')+(d-'0')+r)%10 + '0';
}
int overflow(char c,char d,int r) {
return ((c-'0')+(d-'0')+r)/10;
}
int d;
int add(int i) {
if (d==0 && n1[i]!=0 && n2[i]!=0) {
int r= add(i+1);
if (d<0) {
n3[i+1] = addchar((i+d<0)?'0':n1[i+d],n2[i],r);
r = overflow((i+d<0)?'0':n1[i+d],n2[i],r);
}
if (d>0) {
n3[i+1] = addchar(n1[i],(i-d<0)?'0':n2[i-d],r);
r = overflow(n1[i],(i-d<0)?'0':n2[i-d],r);
}
if (d==0) {
n3[i+1] = addchar(n1[i],n2[i],r);
r = overflow(n1[i],n2[i],r);
}
if (i==0) {
n3[i] = r+'0';
r = 0;
}
return r;
}
if (d>=0 && n1[i]!=0) {
d++;
int r = add(i+1);
n3[i+1] = addchar(n1[i],(i-d<0)?'0':n2[i-d],r);
return overflow(n1[i],(i-d<0)?'0':n2[i-d],r);
}
if (d<=0 && n2[i]!=0) {
d--;
int r = add(i+1);
n3[i+1] = addchar((i+d<0)?'0':n1[i+d],n2[i],r);
return overflow((i+d<0)?'0':n1[i+d],n2[i],r);
}
n3[i+1] = '\0';
return 0;
}
int main() {
add(0);
printf("%s %s %s\n",n1,n2,n3);
}
The basic idea is to calculate the maximal length and the difference between lengths of numbers when descending through recursion, and then adding the right digits when returning from the recursion. The main difficulty is to manage the difference between the lengths.
This algorithm adds a leading zero to the result when there is no overflow on the left.
You could check for error in strings and do the sum at the same time,
#include <stdio.h>
#include <stdlib.h>
#define MAX_RES 1000
char *s1,*s2,*res;
int getcharval(char *s, int i) {
int n = s[i] - '0';
return n<0 || n>9 ? -1 : n;
}
char *recsum(int i1, int i2, int carry, char *pres) {
int n1 = !i1 ? 0 : getcharval(s1, --i1);
int n2 = !i2 ? 0 : getcharval(s2, --i2);
if (n1 < 0 || n2 < 0) return NULL;
int n = n1 + n2 + carry;
*--pres = (n % 10) + '0';
return !i1 && !i2 ? pres : recsum(i1, i2, n/10, pres);
}
with s1 points to string 1, s2 points to string 2, res points to the result area.
The recursive function recsum does the work, taking i1 decreasing index to next char in s1, i2 decreasing index to next char in s2, carry is the result from the previous calculation and pres (p-res) points to the next result char (+1) in res.
The helper function getcharval gets the digit from strings s index i, and returns that number (0 to 9) or -1 if the character is not a digit.
recsum returns a pointer to the result, i.e. a pointer into res where the result starts.
If there was an error in either string, the function returns NULL instead.
An example as how to use recsum, for a result having 1000 chars max (MAX_RES)
int main (int argc, char **argv)
{
s1 = "02313123";
s2 = "92382472699";
res = malloc(MAX_RES+1);
res[MAX_RES] = 0;
char *ret = recsum(strlen(s1), strlen(s2), 0, res+MAX_RES);
if (!ret) printf("There is an error\n");
else printf("%s + %s = %s\n", s1, s2, ret);
return 0;
}
Since If think this is homework, I only show pseudocode.
def str_sum(a,b):
index_a = len(a)
index_b = len(b)
res_len = max(len(a), len(b))
result = calloc(res_len+2, 1)
if not result:
raise OutOfMemory()
index_a -=1
index_b -= 1
acc = 0
res_index = 0
while (index_a >=0) or (index_b >= 0):
chr_a = '0'
chr_b = '0'
if(index_a >=0):
chr_a = a[index_a]
if(index_b >=0):
chr_b = b[index_b]
temp = acc + ord(chr_a) - ord('0') + ord(chr_b) - ord('0')
result[res_index] = chr((temp % 10) + ord('0'))
acc = temp / 10
index_a -=1
index_b -= 1
res_index += 1
inplace_rewind(result)
return ''.join(result)
print str_sum('9023905350290349', '90283056923840923840239480239480234')

How to format a number using comma as thousands separator in C?

In C, how can I format a large number from e.g. 1123456789 to 1,123,456,789?
I tried using printf("%'10d\n", 1123456789), but that doesn't work.
Could you advise anything? The simpler the solution the better.
If your printf supports the ' flag (as required by POSIX 2008 printf()), you can probably do it just by setting your locale appropriately. Example:
#include <stdio.h>
#include <locale.h>
int main(void)
{
setlocale(LC_NUMERIC, "");
printf("%'d\n", 1123456789);
return 0;
}
And build & run:
$ ./example
1,123,456,789
Tested on Mac OS X & Linux (Ubuntu 10.10).
You can do it recursively as follows (beware INT_MIN if you're using two's complement, you'll need extra code to manage that):
void printfcomma2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma2 (n/1000);
printf (",%03d", n%1000);
}
void printfcomma (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfcomma2 (n);
}
A summmary:
User calls printfcomma with an integer, the special case of negative numbers is handled by simply printing "-" and making the number positive (this is the bit that won't work with INT_MIN).
When you enter printfcomma2, a number less than 1,000 will just print and return.
Otherwise the recursion will be called on the next level up (so 1,234,567 will be called with 1,234, then 1) until a number less than 1,000 is found.
Then that number will be printed and we'll walk back up the recursion tree, printing a comma and the next number as we go.
There is also the more succinct version though it does unnecessary processing in checking for negative numbers at every level (not that this will matter given the limited number of recursion levels). This one is a complete program for testing:
#include <stdio.h>
void printfcomma (int n) {
if (n < 0) {
printf ("-");
printfcomma (-n);
return;
}
if (n < 1000) {
printf ("%d", n);
return;
}
printfcomma (n/1000);
printf (",%03d", n%1000);
}
int main (void) {
int x[] = {-1234567890, -123456, -12345, -1000, -999, -1,
0, 1, 999, 1000, 12345, 123456, 1234567890};
int *px = x;
while (px != &(x[sizeof(x)/sizeof(*x)])) {
printf ("%-15d: ", *px);
printfcomma (*px);
printf ("\n");
px++;
}
return 0;
}
and the output is:
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
An iterative solution for those who don't trust recursion (although the only problem with recursion tends to be stack space which will not be an issue here since it'll only be a few levels deep even for a 64-bit integer):
void printfcomma (int n) {
int n2 = 0;
int scale = 1;
if (n < 0) {
printf ("-");
n = -n;
}
while (n >= 1000) {
n2 = n2 + scale * (n % 1000);
n /= 1000;
scale *= 1000;
}
printf ("%d", n);
while (scale != 1) {
scale /= 1000;
n = n2 / scale;
n2 = n2 % scale;
printf (",%03d", n);
}
}
Both of these generate 2,147,483,647 for INT_MAX.
All the code above is for comma-separating three-digit groups but you can use other characters as well, such as a space:
void printfspace2 (int n) {
if (n < 1000) {
printf ("%d", n);
return;
}
printfspace2 (n/1000);
printf (" %03d", n%1000);
}
void printfspace (int n) {
if (n < 0) {
printf ("-");
n = -n;
}
printfspace2 (n);
}
Here's a very simple implementation. This function contains no error checking, buffer sizes must be verified by the caller. It also does not work for negative numbers. Such improvements are left as an exercise for the reader.
void format_commas(int n, char *out)
{
int c;
char buf[20];
char *p;
sprintf(buf, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = ',';
}
c = (c + 1) % 3;
}
*--out = 0;
}
Egads! I do this all the time, using gcc/g++ and glibc on linux and yes, the ' operator may be non-standard, but I like the simplicity of it.
#include <stdio.h>
#include <locale.h>
int main()
{
int bignum=12345678;
setlocale(LC_ALL,"");
printf("Big number: %'d\n",bignum);
return 0;
}
Gives output of:
Big number: 12,345,678
Just have to remember the 'setlocale' call in there, otherwise it won't format anything.
Perhaps a locale-aware version would be interesting.
#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include <limits.h>
static int next_group(char const **grouping) {
if ((*grouping)[1] == CHAR_MAX)
return 0;
if ((*grouping)[1] != '\0')
++*grouping;
return **grouping;
}
size_t commafmt(char *buf, /* Buffer for formatted string */
int bufsize, /* Size of buffer */
long N) /* Number to convert */
{
int i;
int len = 1;
int posn = 1;
int sign = 1;
char *ptr = buf + bufsize - 1;
struct lconv *fmt_info = localeconv();
char const *tsep = fmt_info->thousands_sep;
char const *group = fmt_info->grouping;
char const *neg = fmt_info->negative_sign;
size_t sep_len = strlen(tsep);
size_t group_len = strlen(group);
size_t neg_len = strlen(neg);
int places = (int)*group;
if (bufsize < 2)
{
ABORT:
*buf = '\0';
return 0;
}
*ptr-- = '\0';
--bufsize;
if (N < 0L)
{
sign = -1;
N = -N;
}
for ( ; len <= bufsize; ++len, ++posn)
{
*ptr-- = (char)((N % 10L) + '0');
if (0L == (N /= 10L))
break;
if (places && (0 == (posn % places)))
{
places = next_group(&group);
for (int i=sep_len; i>0; i--) {
*ptr-- = tsep[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
if (len >= bufsize)
goto ABORT;
}
if (sign < 0)
{
if (len >= bufsize)
goto ABORT;
for (int i=neg_len; i>0; i--) {
*ptr-- = neg[i-1];
if (++len >= bufsize)
goto ABORT;
}
}
memmove(buf, ++ptr, len + 1);
return (size_t)len;
}
#ifdef TEST
#include <stdio.h>
#define elements(x) (sizeof(x)/sizeof(x[0]))
void show(long i) {
char buffer[32];
commafmt(buffer, sizeof(buffer), i);
printf("%s\n", buffer);
commafmt(buffer, sizeof(buffer), -i);
printf("%s\n", buffer);
}
int main() {
long inputs[] = {1, 12, 123, 1234, 12345, 123456, 1234567, 12345678 };
for (int i=0; i<elements(inputs); i++) {
setlocale(LC_ALL, "");
show(inputs[i]);
}
return 0;
}
#endif
This does have a bug (but one I'd consider fairly minor). On two's complement hardware, it won't convert the most-negative number correctly, because it attempts to convert a negative number to its equivalent positive number with N = -N; In two's complement, the maximally negative number doesn't have a corresponding positive number, unless you promote it to a larger type. One way to get around this is by promoting the number the corresponding unsigned type (but it's is somewhat non-trivial).
Without recursion or string handling, a mathematical approach:
#include <stdio.h>
#include <math.h>
void print_number( int n )
{
int order_of_magnitude = (n == 0) ? 1 : (int)pow( 10, ((int)floor(log10(abs(n))) / 3) * 3 ) ;
printf( "%d", n / order_of_magnitude ) ;
for( n = abs( n ) % order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
printf( ",%03d", abs(n / order_of_magnitude) ) ;
}
}
Similar in principle to Pax's recursive solution, but by calculating the order of magnitude in advance, recursion is avoided (at some considerable expense perhaps).
Note also that the actual character used to separate thousands is locale specific.
Edit:See #Chux's comments below for improvements.
Based on #Greg Hewgill's, but takes negative numbers into account and returns the string size.
size_t str_format_int_grouped(char dst[16], int num)
{
char src[16];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%d", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return (size_t)(p_dst - dst);
}
Needed to do something similar myself but rather than printing directly, needed to go to a buffer. Here's what I came up with. Works backwards.
unsigned int IntegerToCommaString(char *String, unsigned long long Integer)
{
unsigned int Digits = 0, Offset, Loop;
unsigned long long Copy = Integer;
do {
Digits++;
Copy /= 10;
} while (Copy);
Digits = Offset = ((Digits - 1) / 3) + Digits;
String[Offset--] = '\0';
Copy = Integer;
Loop = 0;
do {
String[Offset] = '0' + (Copy % 10);
if (!Offset--)
break;
if (Loop++ % 3 == 2)
String[Offset--] = ',';
Copy /= 10;
} while (1);
return Digits;
}
Be aware that it's only designed for unsigned integers and you must ensure that the buffer is large enough.
There's no real simple way to do this in C. I would just modify an int-to-string function to do it:
void format_number(int n, char * out) {
int i;
int digit;
int out_index = 0;
for (i = n; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
out[out_index] = '\0';
// then you reverse the out string as it was converted backwards (it's easier that way).
// I'll let you figure that one out.
strrev(out);
}
My answer does not format the result exactly like the illustration in the question, but may fulfill the actual need in some cases with a simple one-liner or macro. One can extend it to generate more thousand-groups as necessary.
The result will look for example as follows:
Value: 0'000'012'345
The code:
printf("Value: %llu'%03lu'%03lu'%03lu\n", (value / 1000 / 1000 / 1000), (value / 1000 / 1000) % 1000, (value / 1000) % 1000, value % 1000);
#include <stdio.h>
void punt(long long n){
char s[28];
int i = 27;
if(n<0){n=-n; putchar('-');}
do{
s[i--] = n%10 + '0';
if(!(i%4) && n>9)s[i--]='.';
n /= 10;
}while(n);
puts(&s[++i]);
}
int main(){
punt(2134567890);
punt(987);
punt(9876);
punt(-987);
punt(-9876);
punt(-654321);
punt(0);
punt(1000000000);
punt(0x7FFFFFFFFFFFFFFF);
punt(0x8000000000000001); // -max + 1 ...
}
My solution uses a . instead of a ,
It is left to the reader to change this.
This is old and there are plenty of answers but the question was not "how can I write a routine to add commas" but "how can it be done in C"? The comments pointed to this direction but on my Linux system with GCC, this works for me:
#include <stdio.h>
#include <stdlib.h>
#include <locale.h>
int main()
{
unsetenv("LC_ALL");
setlocale(LC_NUMERIC, "");
printf("%'lld\n", 3141592653589);
}
When this is run, I get:
$ cc -g comma.c -o comma && ./comma
3,141,592,653,589
If I unset the LC_ALL variable before running the program the unsetenv is not necessary.
Another solution, by saving the result into an int array, maximum size of 7 because the long long int type can handle numbers in the range 9,223,372,036,854,775,807 to -9,223,372,036,854,775,807. (Note it is not an unsigned value).
Non-recursive printing function
static void printNumber (int numbers[8], int loc, int negative)
{
if (negative)
{
printf("-");
}
if (numbers[1]==-1)//one number
{
printf("%d ", numbers[0]);
}
else
{
printf("%d,", numbers[loc]);
while(loc--)
{
if(loc==0)
{// last number
printf("%03d ", numbers[loc]);
break;
}
else
{ // number in between
printf("%03d,", numbers[loc]);
}
}
}
}
main function call
static void getNumWcommas (long long int n, int numbers[8])
{
int i;
int negative=0;
if (n < 0)
{
negative = 1;
n = -n;
}
for(i = 0; i < 7; i++)
{
if (n < 1000)
{
numbers[i] = n;
numbers[i+1] = -1;
break;
}
numbers[i] = n%1000;
n/=1000;
}
printNumber(numbers, i, negative);// non recursive print
}
testing output
-9223372036854775807: -9,223,372,036,854,775,807
-1234567890 : -1,234,567,890
-123456 : -123,456
-12345 : -12,345
-1000 : -1,000
-999 : -999
-1 : -1
0 : 0
1 : 1
999 : 999
1000 : 1,000
12345 : 12,345
123456 : 123,456
1234567890 : 1,234,567,890
9223372036854775807 : 9,223,372,036,854,775,807
In main() function:
int numberSeparated[8];
long long int number = 1234567890LL;
getNumWcommas(number, numberSeparated);
If printing is all that's needed then move int numberSeparated[8]; inside the function getNumWcommas and call it this way getNumWcommas(number).
Another iterative function
int p(int n) {
if(n < 0) {
printf("-");
n = -n;
}
int a[sizeof(int) * CHAR_BIT / 3] = { 0 };
int *pa = a;
while(n > 0) {
*++pa = n % 1000;
n /= 1000;
}
printf("%d", *pa);
while(pa > a + 1) {
printf(",%03d", *--pa);
}
}
Here is the slimiest, size and speed efficient implementation of this kind of decimal digit formating:
const char *formatNumber (
int value,
char *endOfbuffer,
bool plus)
{
int savedValue;
int charCount;
savedValue = value;
if (unlikely (value < 0))
value = - value;
*--endOfbuffer = 0;
charCount = -1;
do
{
if (unlikely (++charCount == 3))
{
charCount = 0;
*--endOfbuffer = ',';
}
*--endOfbuffer = (char) (value % 10 + '0');
}
while ((value /= 10) != 0);
if (unlikely (savedValue < 0))
*--endOfbuffer = '-';
else if (unlikely (plus))
*--endOfbuffer = '+';
return endOfbuffer;
}
Use as following:
char buffer[16];
fprintf (stderr, "test : %s.", formatNumber (1234567890, buffer + 16, true));
Output:
test : +1,234,567,890.
Some advantages:
Function taking end of string buffer because of reverse ordered formatting. Finally, where is no need in revering generated string (strrev).
This function produces one string that can be used in any algo after. It not depends nor require multiple printf/sprintf calls, which is terrible slow and always context specific.
Minimum number of divide operators (/, %).
Secure format_commas, with negative numbers:
Because VS < 2015 doesn't implement snprintf, you need to do this
#if defined(_WIN32)
#define snprintf(buf,len, format,...) _snprintf_s(buf, len,len, format, __VA_ARGS__)
#endif
And then
char* format_commas(int n, char *out)
{
int c;
char buf[100];
char *p;
char* q = out; // Backup pointer for return...
if (n < 0)
{
*out++ = '-';
n = abs(n);
}
snprintf(buf, 100, "%d", n);
c = 2 - strlen(buf) % 3;
for (p = buf; *p != 0; p++) {
*out++ = *p;
if (c == 1) {
*out++ = '\'';
}
c = (c + 1) % 3;
}
*--out = 0;
return q;
}
Example usage:
size_t currentSize = getCurrentRSS();
size_t peakSize = getPeakRSS();
printf("Current size: %d\n", currentSize);
printf("Peak size: %d\n\n\n", peakSize);
char* szcurrentSize = (char*)malloc(100 * sizeof(char));
char* szpeakSize = (char*)malloc(100 * sizeof(char));
printf("Current size (f): %s\n", format_commas((int)currentSize, szcurrentSize));
printf("Peak size (f): %s\n", format_commas((int)currentSize, szpeakSize));
free(szcurrentSize);
free(szpeakSize);
A modified version of #paxdiablo solution, but using WCHAR and wsprinf:
static WCHAR buffer[10];
static int pos = 0;
void printfcomma(const int &n) {
if (n < 0) {
wsprintf(buffer + pos, TEXT("-"));
pos = lstrlen(buffer);
printfcomma(-n);
return;
}
if (n < 1000) {
wsprintf(buffer + pos, TEXT("%d"), n);
pos = lstrlen(buffer);
return;
}
printfcomma(n / 1000);
wsprintf(buffer + pos, TEXT(",%03d"), n % 1000);
pos = lstrlen(buffer);
}
void my_sprintf(const int &n)
{
pos = 0;
printfcomma(n);
}
I'm new in C programming. Here is my simple code.
int main()
{
// 1223 => 1,223
int n;
int a[10];
printf(" n: ");
scanf_s("%d", &n);
int i = 0;
while (n > 0)
{
int temp = n % 1000;
a[i] = temp;
n /= 1000;
i++;
}
for (int j = i - 1; j >= 0; j--)
{
if (j == 0)
{
printf("%d.", a[j]);
}
else printf("%d,",a[j]);
}
getch();
return 0;
}
Require: <stdio.h> + <string.h>.
Advantage: short, readable, based on the format of scanf-family. And assume no comma on the right of decimal point.
void add_commas(char *in, char *out) {
int len_in = strlen(in);
int len_int = -1; /* len_int(123.4) = 3 */
for (int i = 0; i < len_in; ++i) if (in[i] == '.') len_int = i;
int pos = 0;
for (int i = 0; i < len_in; ++i) {
if (i>0 && i<len_int && (len_int-i)%3==0)
out[pos++] = ',';
out[pos++] = in[i];
}
out[pos] = 0; /* Append the '\0' */
}
Example, to print a formatted double:
#include <stdio.h>
#include <string.h>
#define COUNT_DIGIT_MAX 100
int main() {
double sum = 30678.7414;
char input[COUNT_DIGIT_MAX+1] = { 0 }, output[COUNT_DIGIT_MAX+1] = { 0 };
snprintf(input, COUNT_DIGIT_MAX, "%.2f", sum/12);
add_commas(input, output);
printf("%s\n", output);
}
Output:
2,556.56
Using C++'s std::string as return value with possibly the least overhead and not using any std library functions (sprintf, to_string, etc.).
string group_digs_c(int num)
{
const unsigned int BUF_SIZE = 128;
char buf[BUF_SIZE] = { 0 }, * pbuf = &buf[BUF_SIZE - 1];
int k = 0, neg = 0;
if (num < 0) { neg = 1; num = num * -1; };
while(num)
{
if (k > 0 && k % 3 == 0)
*pbuf-- = ',';
*pbuf-- = (num % 10) + '0';
num /= 10;
++k;
}
if (neg)
*pbuf = '-';
else
++pbuf;
int cc = buf + BUF_SIZE - pbuf;
memmove(buf, pbuf, cc);
buf[cc] = 0;
string rv = buf;
return rv;
}
Here is a simple portable solution relying on sprintf:
#include <stdio.h>
// assuming out points to an array of sufficient size
char *format_commas(char *out, int n, int min_digits) {
int len = sprintf(out, "%.*d", min_digits, n);
int i = (*out == '-'), j = len, k = (j - i - 1) / 3;
out[j + k] = '\0';
while (k-- > 0) {
j -= 3;
out[j + k + 3] = out[j + 2];
out[j + k + 2] = out[j + 1];
out[j + k + 1] = out[j + 0];
out[j + k + 0] = ',';
}
return out;
}
The code is easy to adapt for other integer types.
There are many interesting contributions here. Some covered all cases, some did not. I picked four of the contributions to test, found some failure cases during testing and then added a solution of my own.
I tested all methods for both accuracy and speed. Even though the OP only requested a solution for one positive number, I upgraded the contributions that didn't cover all possible numbers (so the code below may be slightly different from the original postings). The cases that weren't covered include: 0, negative numbers and the minimum number (INT_MIN).
I changed the declared type from "int" to "long long" since it's more general and all ints will get promoted to long long. I also standardized the call interface to include the number as well as a buffer to contain the formatted string (like some of the contributions) and returned a pointer to the buffer:
char* funcName(long long number_to_format, char* string_buffer);
Including a buffer parameter is considered by some to be "better" than having the function: 1) contain a static buffer (would not be re-entrant) or 2) allocate space for the buffer (would require caller to de-allocate the memory) or 3) print the result directly to stdout (would not be as generally useful since the output may be targeted for a GUI widget, file, pty, pipe, etc.).
I tried to use the same function names as the original contributions to make it easier to refer back to the originals. Contributed functions were modified as needed to pass the accuracy test so that the speed test would be meaningful. The results are included here in case you would like to test more of the contributed techniques for comparison. All code and test code used to generate the results are shown below.
So, here are the results:
Accuracy Test (test cases: LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX):
----------------------------------------------------
print_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtLocale:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
fmtCommas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
format_number:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
itoa_commas:
-9,223,372,036,854,775,808, -999, -99, 0, 99, 999, 9,223,372,036,854,775,807
Speed Test: (1 million calls, values reflect average time per call)
----------------------------------------------------
print_number: 0.747 us (microsec) per call
fmtLocale: 0.222 us (microsec) per call
fmtCommas: 0.212 us (microsec) per call
format_number: 0.124 us (microsec) per call
itoa_commas: 0.085 us (microsec) per call
Since all contributed techniques are fast (< 1 microsecond on my laptop), unless you need to format millions of numbers, any of the techniques should be acceptable. It's probably best to choose the technique that is most readable to you.
Here is the code:
#line 2 "comma.c"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <locale.h>
#include <limits.h>
// ----------------------------------------------------------
char* print_number( long long n, char buf[32] ) {
long long order_of_magnitude = (n == 0) ? 1
: (long long)pow( 10, ((long long)floor(log10(fabs(n))) / 3) * 3 ) ;
char *ptr = buf;
sprintf(ptr, "%d", n / order_of_magnitude ) ;
for( n %= order_of_magnitude, order_of_magnitude /= 1000;
order_of_magnitude > 0;
n %= order_of_magnitude, order_of_magnitude /= 1000 )
{
ptr += strlen(ptr);
sprintf(ptr, ",%03d", abs(n / order_of_magnitude) );
}
return buf;
}
// ----------------------------------------------------------
char* fmtLocale(long long i, char buf[32]) {
sprintf(buf, "%'lld", i); // requires setLocale in main
return buf;
}
// ----------------------------------------------------------
char* fmtCommas(long long num, char dst[32]) {
char src[27];
char *p_src = src;
char *p_dst = dst;
const char separator = ',';
int num_len, commas;
num_len = sprintf(src, "%lld", num);
if (*p_src == '-') {
*p_dst++ = *p_src++;
num_len--;
}
for (commas = 2 - num_len % 3;
*p_src;
commas = (commas + 1) % 3)
{
*p_dst++ = *p_src++;
if (commas == 1) {
*p_dst++ = separator;
}
}
*--p_dst = '\0';
return dst;
}
// ----------------------------------------------------------
char* format_number(long long n, char out[32]) {
int digit;
int out_index = 0;
long long i = (n < 0) ? -n : n;
if (i == LLONG_MIN) i = LLONG_MAX; // handle MIN, offset by 1
if (i == 0) { out[out_index++] = '0'; } // handle 0
for ( ; i != 0; i /= 10) {
digit = i % 10;
if ((out_index + 1) % 4 == 0) {
out[out_index++] = ',';
}
out[out_index++] = digit + '0';
}
if (n == LLONG_MIN) { out[0]++; } // correct for offset
if (n < 0) { out[out_index++] = '-'; }
out[out_index] = '\0';
// then you reverse the out string
for (int i=0, j = strlen(out) - 1; i<=j; ++i, --j) {
char tmp = out[i];
out[i] = out[j];
out[j] = tmp;
}
return out;
}
// ----------------------------------------------------------
char* itoa_commas(long long i, char buf[32]) {
char* p = buf + 31;
*p = '\0'; // terminate string
if (i == 0) { *(--p) = '0'; return p; } // handle 0
long long n = (i < 0) ? -i : i;
if (n == LLONG_MIN) n = LLONG_MAX; // handle MIN, offset by 1
for (int j=0; 1; ++j) {
*--p = '0' + n % 10; // insert digit
if ((n /= 10) <= 0) break;
if (j % 3 == 2) *--p = ','; // insert a comma
}
if (i == LLONG_MIN) { p[24]++; } // correct for offset
if (i < 0) { *--p = '-'; }
return p;
}
// ----------------------------------------------------------
// Test Accuracy
// ----------------------------------------------------------
void test_accuracy(char* name, char* (*func)(long long n, char* buf)) {
char sbuf[32]; // string buffer
long long nbuf[] = { LLONG_MIN, -999, -99, 0, 99, 999, LLONG_MAX };
printf("%s:\n", name);
printf(" %s", func(nbuf[0], sbuf));
for (int i=1; i < sizeof(nbuf) / sizeof(long long int); ++i) {
printf(", %s", func(nbuf[i], sbuf));
}
printf("\n");
}
// ----------------------------------------------------------
// Test Speed
// ----------------------------------------------------------
void test_speed(char* name, char* (*func)(long long n, char* buf)) {
int cycleCount = 1000000;
//int cycleCount = 1;
clock_t start;
double elapsed;
char sbuf[32]; // string buffer
start = clock();
for (int i=0; i < cycleCount; ++i) {
char* s = func(LLONG_MAX, sbuf);
}
elapsed = (double)(clock() - start) / (CLOCKS_PER_SEC / 1000000.0);
printf("%14s: %7.3f us (microsec) per call\n", name, elapsed / cycleCount);
}
// ----------------------------------------------------------
int main(int argc, char* argv[]){
setlocale(LC_ALL, "");
printf("\nAccuracy Test: (LLONG_MIN, -999, 0, 99, LLONG_MAX)\n");
printf("----------------------------------------------------\n");
test_accuracy("print_number", print_number);
test_accuracy("fmtLocale", fmtLocale);
test_accuracy("fmtCommas", fmtCommas);
test_accuracy("format_number", format_number);
test_accuracy("itoa_commas", itoa_commas);
printf("\nSpeed Test: 1 million calls\n\n");
printf("----------------------------------------------------\n");
test_speed("print_number", print_number);
test_speed("fmtLocale", fmtLocale);
test_speed("fmtCommas", fmtCommas);
test_speed("format_number", format_number);
test_speed("itoa_commas", itoa_commas);
return 0;
}
Can be done pretty easily...
//Make sure output buffer is big enough and that input is a valid null terminated string
void pretty_number(const char* input, char * output)
{
int iInputLen = strlen(input);
int iOutputBufferPos = 0;
for(int i = 0; i < iInputLen; i++)
{
if((iInputLen-i) % 3 == 0 && i != 0)
{
output[iOutputBufferPos++] = ',';
}
output[iOutputBufferPos++] = input[i];
}
output[iOutputBufferPos] = '\0';
}
Example call:
char szBuffer[512];
pretty_number("1234567", szBuffer);
//strcmp(szBuffer, "1,234,567") == 0
void printfcomma ( long long unsigned int n)
{
char nstring[100];
int m;
int ptr;
int i,j;
sprintf(nstring,"%llu",n);
m=strlen(nstring);
ptr=m%3;
if (ptr)
{ for (i=0;i<ptr;i++) // print first digits before comma
printf("%c", nstring[i]);
printf(",");
}
j=0;
for (i=ptr;i<m;i++) // print the rest inserting commas
{
printf("%c",nstring[i]);
j++;
if (j%3==0)
if(i<(m-1)) printf(",");
}
}
// separate thousands
int digit;
int idx = 0;
static char buffer[32];
char* p = &buffer[32];
*--p = '\0';
for (int i = fCounter; i != 0; i /= 10)
{
digit = i % 10;
if ((p - buffer) % 4 == 0)
*--p = ' ';
*--p = digit + '0';
}

Resources