Is there a standard function?
Hello everybody,
I recently started studying C, and so far I didn't find a function to format
integer numbers with thousand comma separators:
30000000 value to format
30,000,000 formatted value.
Do you know if there is a standard function to do this kind of formatting?
Thank you
Formatting integer numbers
After a little experimentation, I came out with this 0.3 release that
is a major step towards the definitive version, next co come :-)
In this version the code for formatting is inside a function, and it is tested
for performance as well.
On my pc Core duo Intel it takes about 12 seconds to perform 100 million
formatting of a long integer, with sign and thousand separator.
I'd like some comment on possible improvement both in style, and in performance
if anybody would be so kind to point out some deficiency or better coding.
Thanks
Code:
// ----------------------------------------------------------------------------------------------
// Prog_name: comma_sep.c / ver 0.3
// A routine for separating integer numbers with thousands separator.
// Created with Pelles C for Windows 6.00.4
//-----------------------------------------------------------------------------------------------
// This version takes into account the sign and the possibility to have different
// separator like space, comma, point, and so on.
// Moveover this version creates a function that can be tested for performance.
//-----------------------------------------------------------------------------------------------
// Date: 03 july 2010
// Author: frktons @ cprogramming forum.
//-----------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#undef getchar
#pragma comment(lib, "\\masm32\\lib\\msvcrt.lib")
//-----------------------------------------------------------------------------------------------
// Global variables. In future versions will go into an header file
//-----------------------------------------------------------------------------------------------
bool sign = true; // if the number has to be displayed with sign
bool neg = false; // if the number is negative this flag will be set
// from the function to reflect the state
bool zero = false; // if the number is zero the function sets this
// flag for its decisions
char sep = ','; // here I choose the separator
char buffer[15] = {' '}; // string array for the formatted number
//-----------------------------------------------------------------------------------------------
// Function prototype for int_format(). Takes the number to format
// and the address of the string to fill. Returns nothing.
//-----------------------------------------------------------------------------------------------
void int_format(int num);
//-----------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
int num = -1234567153; // test number to format
int cycles = 0;
int x; // generic integer counter
time_t init_time = 0; // initial time
time_t end_time = 0; // end time
int times = 100000000; // for testing performance set this number for repetitions
printf("\n The value of num is: %d\n",num);
time(&init_time);
printf("\n init_time =%d\n",init_time);
for (cycles = 0; cycles < times; cycles++) {
int_format(num);
for (x=0; x < 15; x++)
buffer[x] = ' ';
} // end for
int_format(num);
printf("\n The formatted value of result is: ");
for (x = 0; x < 15; x++)
{
if (buffer[x] == '+' || buffer[x] == '-' || buffer[x] == sep || buffer[x] >= '0' && buffer[x] <= '9')
printf("%c",buffer[x]);
}
printf("\n");
time(&end_time);
printf(" end_time =%d\n",end_time);
printf("\n\n The routine has taken about %d seconds\n", end_time - init_time);
getchar();
return 0;
}
//--------------------------------------------------------------------------------------------------------------------
// Function int_format()
//--------------------------------------------------------------------------------------------------------------------
void int_format(int num){
int x = 0;
int remain = 0; // integer variable to store the remainder
int count = 0; // integer counter for positioning the separator
char digit[10] = {'0','1','2','3','4','5','6','7','8','9'}; // the digits to display in char shape
int len_str = 14; // string lenght less the terminator NULL
if (num != 0)
{
if (num < 0)
{
neg = true;
num = num * -1 ; // transform number to positive if negative
}
for (x = len_str; x >= 0; x--)
{
if (num == 0)
break;
if (count == 3)
{
count = 0;
buffer[x] = sep;
x--;
}
remain = num % 10;
num = num / 10;
buffer[x] = digit[remain];
count++;
}
}
else
{
buffer[len_str] = '0';
zero = true;
}
if (sign == true && neg == true)
buffer[x] = '-';
else if (sign == true && zero == false)
buffer[x] = '+';
return;
}
Formatting integer numbers
I added the possibility of choice between Right-alignment and Left-alignment
of the formatted number. We are at version 0.4 so far.
The new version:
Code:
// ----------------------------------------------------------------------------------------------
// Prog_name: comma_sep.c / ver 0.4
// A routine for formatting integer numbers with thousand separators.
// Created with Pelles C for Windows 6.00.4
//-----------------------------------------------------------------------------------------------
// This version takes into account the sign and the possibility to have different
// separator like space, comma, point, and so on.
// Moveover this version creates a function that can be tested for performance.
// Added the choice for right and left alignment.
//-----------------------------------------------------------------------------------------------
// Date: 03 july 2010
// Author: frktons @ cprogramming forum.
//-----------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#undef getchar
#pragma comment(lib, "\\masm32\\lib\\msvcrt.lib")
//-----------------------------------------------------------------------------------------------
// Global variables. In future versions will go into an header file
//-----------------------------------------------------------------------------------------------
bool sign = true; // if the number has to be displayed with sign
bool neg = false; // if the number is negative this flag will be set
// from the function to reflect the state
bool zero = false; // if the number is zero the function sets this
// flag for its decisions
char sep = ','; // here I choose the separator
char buffer[15] = {' '}; // string array for the formatted number
char alignment = 'R'; // choice to [R]ight-align or [L]eft-align the number
//-----------------------------------------------------------------------------------------------
// Function prototype for int_format(). Takes the number to format
// and the address of the string to fill. Returns nothing.
//-----------------------------------------------------------------------------------------------
void int_format(int num);
//-----------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
int num = -123456; // test number
int cycles = 0;
int x; // generic integer counter
time_t init_time = 0; // initial time
time_t end_time = 0; // end time
alignment = 'L'; // the formatted number will be Left-aligned
int times = 50000000; // for testing performance set this number for repetitions
printf("\n The value of num is: %d\n",num);
time(&init_time);
printf("\n init_time = %d \n",init_time);
for (cycles = 0; cycles < times; cycles++) {
for (x=0; x < 14; x++)
buffer[x] = ' ';
int_format(num);
} // end for
printf("\n The formatted value of num is: ");
for (x = 0; x < 14; x++)
{
if (buffer[x] == '+' || buffer[x] == '-' || buffer[x] == sep || buffer[x] >= '0' && buffer[x] <= '9')
printf("%c",buffer[x]);
}
printf("\n\n");
time(&end_time);
printf(" end_time = %d \n",end_time);
printf("\n\n The routine test has taken about %d seconds\n", end_time - init_time);
for (x=0; x < 14; x++)
buffer[x] = ' ';
// buffer[14] = '\0';
neg = false;
sign = false;
int_format(times);
printf("\n to perform ");
for (x = 0; x < 14; x++)
{
if (buffer[x] == '+' || buffer[x] == '-' || buffer[x] == sep || buffer[x] >= '0' && buffer[x] <= '9')
printf("%c",buffer[x]);
}
printf(" cycles of the formatting function");
getchar();
return 0;
}
//------------------------------------------------------------------------------------------------
// Function int_format()
//------------------------------------------------------------------------------------------------
void int_format(int num){
int x = 0;
int y = 0;
int remain = 0; // integer variable to store the remainder
int count = 0; // integer counter for positioning the separator
char digit[10] = {'0','1','2','3','4','5','6','7','8','9'}; // the digits to display in char shape
int len_str = 14; // string lenght less the terminator NULL
if (num != 0)
{
if (num < 0)
{
neg = true;
num = num * -1 ; // transform number to positive if negative
}
for (x = len_str; x >= 0; x--)
{
if (num == 0)
break;
if (count == 3)
{
count = 0;
buffer[x] = sep;
x--;
}
remain = num % 10;
num = num / 10;
buffer[x] = digit[remain];
count++;
}
}
else
{
buffer[len_str] = '0';
zero = true;
}
if (sign == true && neg == true)
buffer[x] = '-';
else if (sign == true && zero == false)
buffer[x] = '+';
if (alignment == 'L') {
if (x == 0)
return;
for (y = 0; y < 15; y++, x++) {
buffer[y] = buffer[x];
if (buffer[y] == '\0')
return;
} // end for
}
return;
}
The actual performance, before optimization, is:
Code:
The value of num is: -123456
init_time = 1278177849
The formatted value of num is: -123,456
end_time = 1278177853
The routine test has taken about 4 seconds
to perform 50,000,000 cycles of the formatting function
Looking forward for version 0.5 :-)
Formatting integer numbers
And now we are about half-way: 0.5 version.
I've implemented the suggestions given by some of you
about global and local variables, and replaced the lookup array
with the 'trick of the tale' Elysia pointed to.
The performances are different, but only with CPU cycles
counting I'll be sure about that.
Code:
// ----------------------------------------------------------------------------------------------
// Prog_name: comma_sep.c / ver 0.5
// A routine for formatting integer numbers with thousand separators.
// Created with Pelles C for Windows 6.00.4
//-----------------------------------------------------------------------------------------------
// This version takes into account the sign and the possibility to have different
// separator like space, comma, point, and so on.
// Moveover this version creates a function that can be tested for performance.
// Added the choice for right and left alignment.
// In this version Global variables have been removed.
//-----------------------------------------------------------------------------------------------
// Date: 04 july 2010
// Author: frktons @ cprogramming forum.
//-----------------------------------------------------------------------------------------------
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#undef getchar
#pragma comment(lib, "\\masm32\\lib\\msvcrt.lib")
//-----------------------------------------------------------------------------------------------
// Function prototype for int_format(). Takes the number to format,
// the address of the string to fill, some switches and thousand separator.
// Returns nothing.
//-----------------------------------------------------------------------------------------------
void int_format(int num, char *, bool sign, bool neg, char sep, char alignment);
//-----------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
//-----------------------------------------------------------------------------------------------
// Local variables.
//-----------------------------------------------------------------------------------------------
bool sign = true; // if the number has to be displayed with sign
bool neg = false; // if the number is negative this flag will be set
// from the function to reflect the state
char sep = ','; // here I choose the separator
char buffer[15] = {' '}; // string array for the formatted number
char alignment = ' '; // choice to [R]ight-align or [L]eft-align the number
int num = -123456; // test number
int cycles = 0;
int x; // generic integer counter
time_t init_time = 0; // initial time
time_t end_time = 0; // end time
alignment = 'L'; // the formatted number will be Left-aligned
int times = 50000000; // for testing performance set this number for repetitions
printf("\n The value of num is: %d\n",num);
time(&init_time);
printf("\n init_time = %d \n",init_time);
for (cycles = 0; cycles < times; cycles++) {
for (x=0; x < 14; x++)
buffer[x] = ' ';
int_format(num, buffer, sign, neg, sep, alignment);
} // end for
printf("\n The formatted value of num is: ");
for (x = 0; x < 14; x++)
{
if (buffer[x] == '+' || buffer[x] == '-' || buffer[x] == sep || buffer[x] >= '0' && buffer[x] <= '9')
printf("%c",buffer[x]);
if (buffer[x] == '\0')
break;
}
printf("\n\n");
time(&end_time);
printf(" end_time = %d \n",end_time);
printf("\n\n The routine test has taken about %d seconds\n", end_time - init_time);
for (x=0; x < 14; x++)
buffer[x] = ' ';
// buffer[14] = '\0';
neg = false;
sign = false;
int_format(times, buffer, sign, neg, sep, alignment);
printf("\n to perform ");
for (x = 0; x < 14; x++)
{
if (buffer[x] == '+' || buffer[x] == '-' || buffer[x] == sep || buffer[x] >= '0' && buffer[x] <= '9')
printf("%c",buffer[x]);
if (buffer[x] == '\0')
break;
}
printf(" cycles of the formatting function");
getchar();
return 0;
}
//--------------------------------------------------------------------------------------------------------------------
// Function int_format()
//--------------------------------------------------------------------------------------------------------------------
void int_format(int num, char *buffer, bool sign, bool neg, char sep, char alignment){
int x = 0;
int y = 0;
int remain = 0; // integer variable to store the remainder
int count = 0; // integer counter for positioning the separator
bool zero = false; // if the number is zero the function sets this
// flag for its decisions
// char digit[10] = {'0','1','2','3','4','5','6','7','8','9'}; // the digits to display in char shape
int len_str = 14; // string lenght less the terminator NULL
if (num != 0)
{
if (num < 0)
{
neg = true;
num = num * -1 ; // transform number to positive if negative
}
for (x = len_str; x >= 0; x--)
{
if (num == 0)
break;
if (count == 3)
{
count = 0;
buffer[x] = sep;
x--;
}
remain = num % 10;
num = num / 10;
// buffer[x] = digit[remain];
buffer[x] = '0' + remain;
count++;
}
}
else
{
buffer[len_str] = '0';
zero = true;
}
if (sign == true && neg == true)
buffer[x] = '-';
else if (sign == true && zero == false)
buffer[x] = '+';
if (alignment == 'L') {
if (x == 0)
return;
for (y = 0; y < 15; y++, x++) {
buffer[y] = buffer[x];
if (buffer[y] == '\0')
return;
} // end for
}
return;
}
The performance gap:
Code:
Testing version : 0.40
----------------------
The value of num is: -1234567890
init_time = 1278231197
The formatted value of num is: -1,234,567,890
end_time = 1278231263
The routine test has taken about 66 seconds
to perform 500,000,000 cycles of the formatting function
versus:
Code:
Testing version : 0.50
----------------------
The value of num is: -1234567890
init_time = 1278231354
The formatted value of num is: -1,234,567,890
end_time = 1278231447
The routine test has taken about 93 seconds
to perform 500,000,000 cycles of the formatting function
It looks like version 0.4 is about 35% faster than version 0.5.
Formatting integer numbers
Quote:
Originally Posted by
Adak
Your best version is still to come. It will feature the result of several keypresses on that big key with the left facing arrow on it. (Yes, on the upper right hand side of the keyboard).
Not only will it improve the performance, and make your program smaller, but it will remove redundancies like alignment, that are already a part of the printf() format specifiers.
Ah! Ah! I really like your sense of humour. :-)
I think I've already heard that. Aren't you, by any chance, reinventing the joke? ;-)
You are a very experienced C coder, and I'd appreciate some more constructive
suggestions for my learning path, if you don't bother.
Quote:
Originally Posted by Elysia
You're still missing the sizeof_buffer argument. That is a no-no. You MUST have it or you must not use C.
Sorry about that, but if I MUST than I WILL :-)
Let me study the matter, I'm still a very beginner in C syntax, I don't know yet.
By the way, except from deleting the program as Adak suggested, what kind
of performance improvement could you suggest to make the function faster?
My actual objective is to reduce the elapsed time from 66'' to 32'' or less.