Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I add a thousands separator to a double in C on Windows?

I use the MPFR library to do calculations on big numbers, but also return a double with 8 digits after the decimal point.

I mpfr_sprintf the number to a char array so precision or anything isn't lost. Everything is fine except that I didn't find any thousand separator option in the documentation(or I missed it).

Given a number such as 20043.95381376 I would like to represent it like 20,043.95381376 for better readability.

Or the number 164992818.48075795 as 164,992,818.48075795

I read about an apostrophe that should be added to printf/sprintf, but that seems to be a UNIX/POSIX thing and I am a Windows user.

Since internally I print the number as a string, I thought what I could do is write a custom implementation that would automatically add the comma depending on the number(>1000>10000>100000 and so forth) but then I realized that functions like strncpy or strcpy will essentially replace, not add the comma to the desired position. And here is how I am back to square one on how to do it.

How can I do it?

like image 590
farmdve Avatar asked Sep 17 '12 13:09

farmdve


1 Answers

You need your implementation to convert the double value to string and examine each character of that string, then copy it to an output string along with the separators.

Something like this:

#include <stdio.h>
#include <string.h>

int thousandsep(double in, char* out_str, size_t out_len, unsigned int precision) {
    char in_str[128], int_str[128], format[32];
    size_t dlen, mod, i, j;
    int c;

    snprintf(format, sizeof format, "%%.%df", precision);
    snprintf(in_str, sizeof in_str, format, in);
    snprintf(int_str, sizeof int_str, "%d", (int)in);

    dlen = strlen(in_str);
    mod = strlen(int_str) % 3;
    c = (mod == 0) ? 3 : mod;

    for (i=0, j=0; i<dlen; i++, j++, c--) {
        if (j >= out_len - 1) {
            /* out_str is too small */
            return -1;
        }

        if (in_str[i] == '.') {
            c = -1;
        } else if (c == 0) {
            out_str[j++] = ',';
            c = 3;
        }

        out_str[j] = in_str[i];
    }
    out_str[j] = '\0';

    return 0;
}

Then use it like so:

char out_str[64];

if (thousandsep(20043.95381376, out_str, sizeof out_str, 8) == 0)
    printf("%s\n", out_str);       /* 20,043.95381376 */

if (thousandsep(164992818.48075795, out_str, sizeof out_str, 8) == 0)
    printf("%s\n", out_str);       /* 164,992,818.48075795 */

if (thousandsep(1234567.0, out_str, sizeof out_str, 0) == 0)
    printf("%s\n", out_str);       /* 1,234,567 */

Note: I assumed that if you're on Windows, you may be using MSVC so this solution should be working on C89 compilers.

like image 128
netcoder Avatar answered Oct 10 '22 08:10

netcoder