【问题标题】:printf double with maximum precision in available widthprintf double 在可用宽度中具有最大精度
【发布时间】:2017-05-18 22:33:01
【问题描述】:

我需要在 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 这样的数字时,就会出现问题。小数点后多余的零似乎不算数(!)。

【问题讨论】:

  • “问题是这不适用于 %g 而不是 %f。” 不够好。要精确。怎么不行?
  • 虽然另一篇文章的 OP 并不关心 answer ,但这正是这个 OP 想要的——我想。问题是存在使使用预先计算的格式不是最佳的极端情况。链接的答案尝试了各种"%.*e" 解决方案。
  • 为什么要输出为-123.123456789123456 而不是更精确的-123.123456789123457? (检查最后一位)
  • 1) "print doubles in C, width of 20" --> 你想如何打印doubleDBL_MAX 这样可能需要300+ 位?或者你想跳到指数符号? 2) 正数 +123.123456789123456789 是否应该多打印 1 个小数位为 "123.1234567891234567"
  • "%g" 并不总是满足“使用可以打印的最大精度”的要求,而是通过几乎相似的标准跳到指数级。哪个更重要:最大精度、易于编码、所有double 的正确性?

标签: c printf double precision


【解决方案1】:

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

#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 != '\0')
                *(++last) = *(expon++);
        }
        *(++last) = '\0';
    }
    printf("%*s\n", width, temp);
    free(temp);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-24
    • 1970-01-01
    • 1970-01-01
    • 2015-04-06
    相关资源
    最近更新 更多