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

余生长醉 提交于 2019-12-10 14:37:43

问题


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?


回答1:


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.




回答2:


GetNumberFormatEx will take the plain string version of the number and format it with the grouping separators, appropriate decimal point, etc. Pass LOCALE_NAME_USER_DEFAULT as the locale, and it will be in the format that the user prefers.

If you need to override one of the settings (like the precision), you can populate a NUMBERFMT struct with the defaults and then change the fields you need to control.




回答3:


There does not appear to be a formatting directive that can be used.

Here is a quick and dirty way of taking a string containing a floating point number and inserting commas into the appropriate places.

This uses a couple of temp buffers. The thousands separator symbol will depend on locale as does the decimal point symbol. However for this example a comma is hard coded.

This basically just takes the string representation of the floating point number and then steps through copying the digits to another buffer and inserting commas at the appropriate places.

You could also take a look at doing this with fewer buffers as like I said, this is quick and dirty and not terribly efficient.

{
    double dFloat = 123456789012.567890;
    char xBuff[128];
    sprintf (xBuff, "%f", dFloat);

    char xBuff2[128];
    int iLen = strlen(xBuff);
    int iPoint = iLen;
    for (iLen--; iLen >= 0; iLen--) {
        if (xBuff[iLen] == '.' || xBuff[iLen] == ',') {
            // found the decimal point.  depends on locale.
            iPoint = iLen;
            break;
        }
    }
    strcpy (xBuff2, xBuff + iPoint);   // save the decimal portion

    char xBuff3[128], xBuff4[128];
    xBuff3[127] = 0;    // set an end of string
    int  iCount, jLen;
    for (iCount = 1, jLen = 126, iLen--; iLen >= 0; jLen--, iLen--) {
        if ((iCount % 4) == 0) {
            xBuff3[jLen] = ',';
            jLen--;
            iCount = 1;
        }
        xBuff3[jLen] = xBuff[iLen];
        iCount++;
    }
    strcpy (xBuff4, xBuff3 + jLen + 1);
    strcat (xBuff4, xBuff2);
}


来源:https://stackoverflow.com/questions/12460738/how-can-i-add-a-thousands-separator-to-a-double-in-c-on-windows

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!