Home > C/C++ > Number Formatting in C

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:

char * number_format(long double n, int decimals, char *dec_point, char *thousands_sep);

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:

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;
}

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

Categories: C/C++ Tags:
  1. No comments yet.
  1. No trackbacks yet.