Number Formatting in C
I was in a need to format numbers in human readable presentation one day, so I spent a while on coming with a way to make a function for number formatting in the C Programming Language. I’ve based it off PHP’s number_format.
Here is my prototype:
For use of the parameter “n”, must be a long double, the number of decimals can be 0 or n (n = number of decimal places), dec_point can be set to NULL or a string decimal point identifier (i.e. “.”) and thousands_sep can be an empty string “” or a thousandths place identifier “,”. All depends on what notation you use for example the French decimal presentation looks different from a United States presentation reference.
Now here is the code I wrote for the function prototype:
/* declare/initialize a place holder text */
char *text = (char *) calloc(256, sizeof(char));
if (text == NULL) return NULL;
if (decimals > 0) {
sprintf(text, "%.10Lf", n);
} else {
sprintf(text, "%ld", (long int)n);
}
/*
* find the "." decimcal placement position
* from there its the string length
*/
int dot = strpos(".", text, 0);
/* check to see if its even there */
if (dot == -1) { dot = strlen(text); }
int num_thousands = 0;
if (thousands_sep != NULL && strcmp(thousands_sep, "") != 0) {
if (dot > 3) {
/* get the number of thousands seperators */
if (!(n < 0 && dot < 5)) num_thousands = (thousands_sep != NULL) ? ((int)ceil(((float)dot / 3))) - 1 : 0;
if (n < 0 && dot > 5 && (int)strlen(substr(text, 1, dot)) % 3 == 0) num_thousands--;
}
}
/* start new string */
int new_s_size = dot + num_thousands;
char *new_s = (char *) calloc(new_s_size + 1, sizeof(char));
int i, c, k;
for (i = new_s_size - 1, c = 0, k = dot - 1; i >= 0; i--) {
if (c == 3 && num_thousands > 0) {
/* add the thousands seperator if is set */
new_s[i] = *(thousands_sep);
num_thousands--;
c = 0;
} else {
new_s[i] = text[k];
k--, c++;
}
}
/* now add on the decimal points */
if (decimals > 0) {
char *decimals_s = substr(text, dot + 1, decimals);
if (dec_point != NULL) {
strcat(new_s, dec_point);
} else {
strcat(new_s, " ");
}
strcat(new_s, decimals_s);
}
free(text);
return new_s;
}
NOTE: You see functions used in that code such as substr() and strpos() which are apart of Maris Labs’ “mess around” eXtended C Standard Library “xstdlib”.
Here is the full code in test:
* Name: test.c
* Author: rashaud
* Date: 05/05/2010
* License: GNU GPL <http://www.gnu.org/licenses/>
* Description: <description>
********************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <xstdlib.h>
char * number_format(long double n, int decimals, char *dec_point, char *thousands_sep) {
/* declare/initialize a place holder text */
char *text = (char *) calloc(256, sizeof(char));
if (text == NULL) return NULL;
if (decimals > 0) {
sprintf(text, "%.10Lf", n);
} else {
sprintf(text, "%ld", (long int)n);
}
/*
* find the "." decimcal placement position
* from there its the string length
*/
int dot = strpos(".", text, 0);
/* check to see if its even there */
if (dot == -1) { dot = strlen(text); }
int num_thousands = 0;
if (thousands_sep != NULL && strcmp(thousands_sep, "") != 0) {
if (dot > 3) {
/* get the number of thousands seperators */
if (!(n < 0 && dot < 5)) num_thousands = (thousands_sep != NULL) ? ((int)ceil(((float)dot / 3))) - 1 : 0;
if (n < 0 && dot > 5 && (int)strlen(substr(text, 1, dot)) % 3 == 0) num_thousands--;
}
}
/* start new string */
int new_s_size = dot + num_thousands;
char *new_s = (char *) calloc(new_s_size + 1, sizeof(char));
int i, c, k;
for (i = new_s_size - 1, c = 0, k = dot - 1; i >= 0; i--) {
if (c == 3 && num_thousands > 0) {
/* add the thousands seperator if is set */
new_s[i] = *(thousands_sep);
num_thousands--;
c = 0;
} else {
new_s[i] = text[k];
k--, c++;
}
}
/* now add on the decimal points */
if (decimals > 0) {
char *decimals_s = substr(text, dot + 1, decimals);
if (dec_point != NULL) {
strcat(new_s, dec_point);
} else {
strcat(new_s, " ");
}
strcat(new_s, decimals_s);
}
free(text);
return new_s;
}
int main(void) {
printf("%s\n", number_format(-5.1223, 0, NULL, ","));
printf("%s\n", number_format(-50.1223, 0, NULL, ","));
printf("%s\n", number_format(-500.1223, 0, NULL, ","));
printf("%s\n", number_format(-5000.1223, 0, NULL, ","));
printf("%s\n", number_format(-50000.1223, 0, NULL, ","));
printf("%s\n", number_format(-500000.1223, 0, NULL, ","));
printf("%s\n", number_format(-5000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-50000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-500000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-5000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-50000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-500000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-5000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-50000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-500000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-5000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-50000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-500000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(-5000000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(5000000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(500000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(50000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(5000000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(500000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(50000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(5000000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(500000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(50000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(5000000000.1223, 0, NULL, ","));
printf("%s\n", number_format(500000000.1223, 0, NULL, ","));
printf("%s\n", number_format(50000000.1223, 0, NULL, ","));
printf("%s\n", number_format(5000000.1223, 0, NULL, ","));
printf("%s\n", number_format(500000.1223, 0, NULL, ","));
printf("%s\n", number_format(50000.1223, 0, NULL, ","));
printf("%s\n", number_format(5000.1223, 0, NULL, ","));
printf("%s\n", number_format(500.1223, 0, NULL, ","));
printf("%s\n", number_format(50.1223, 0, NULL, ","));
printf("%s\n", number_format(5.1223, 0, NULL, ","));
/* different tests */
printf("\n\n%s\n", number_format(5000.1223, 4, ".", ","));
printf("\n\n%s\n", number_format(5000.1223, 2, ".", ","));
printf("\n\n%s\n", number_format(5000.1223, 4, NULL, ","));
printf("\n\n%s\n", number_format(5000.1223, 2, ",", " "));
return 0;
}
This is just a simple way to show thousandths place when printing a number to the screen. The bottom half of the full code snippet are tests with the number format function. This example is intended for a beginner trying to figure this out.
Enjoy,
-Rashaud
Next up: char ** split(const char *delimeter, const char *str); and char * join(const char *delimiter, const char **e); Revisited