printf double 在可用宽度中具有最大精度

printf double with maximum precision in available width

我需要在 C 中打印双精度,宽度为 20,但使用 20 个字符中可以打印的最大精度

例如:

-123.123456789123456789 

应该打印:

-123.1234567891234568

到目前为止,我有以下代码可以工作,但是很丑并且有问题:

double num = .......;
int pr = 0;
char temp[32] = { 0 };
char *point = NULL;
sprintf(temp, "%.20f", num);
point = strchr(temp, '.');
if (point) {
    pr = 20 - (1 + point - temp);
}
printf("%20.*f", pr, num);

问题是这不适用于 %g 而不是 %f,它有时会打印超过 20 个字符,即使不存在指数部分。 当给出像 0.000123456789123456789 这样的数字时,就会出现问题。小数点后多出来的零好像不算(!).

根据 chux and this answer 的一些提示,我实施了以下似乎有效的解决方案。 我不再尝试预先计算要使用的正确精度,而是以足够的精度打印,然后我裁剪掉多余的数字。

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

static void printDouble(double val, int width)
{
    char *temp = malloc((width + 32) * sizeof(char));
    int len = 0;
    sprintf(temp, "%*.*g", width, width, val);
    len =strlen(temp);
    if (len > width) {
        char *dropped = temp + width;
        char *last = dropped - 1;
        char *expon = strchr(temp, 'E');
        if (!expon)
            expon = strchr(temp, 'e');
        if (expon) {
            last = temp + width - 1 - strlen(expon);
            dropped = last + 1 < expon ? last + 1 : NULL;
        }
        if (strchr(temp, '.')) {
            /* Round */
            if (dropped && *dropped >= '5' && *dropped <= '9') {
                while (*last == '9')
                    last--;
                (*last)++;
            }
            /* Remove trailing zeroes */
            while (*last == '0')
                last--;
        }
        if (expon) {
            while (*expon != '[=10=]')
                *(++last) = *(expon++);
        }
        *(++last) = '[=10=]';
    }
    printf("%*s\n", width, temp);
    free(temp);
}