【问题标题】:What is the purpose of max_digits10 and how is it different from digits10?max_digits10 的用途是什么,它与 digits10 有何不同?
【发布时间】:2014-04-22 21:26:58
【问题描述】:

我对@9​​87654323@ 代表什么感到困惑。根据its documentation,所有整型都为0。 max_digits10 的浮点类型公式类似于 intdigits10 的。

【问题讨论】:

标签: c++ c++11 precision floating-point-precision numeric-limits


【解决方案1】:

在我看来,在链接的站点(以及digits10的站点)已经充分解释了:

digits10 是“十进制”数字的(最大)数量
在任何情况下都可以用类型表示,与它们的实际值无关。
以一个常见的 4 字节无符号整数为例:众所周知,它正好有 32 位,
即 32 位二进制数。
但就十进制数而言呢?
大概 9.
因为,它可以存储 100000000 以及 999999999。
但是如果取 10 位数字:可以存储 4000000000,但不能存储 5000000000。
所以,如果我们需要保证最小十进制数字容量,那就是 9。
这就是digits10的结果。

max_digits10 仅对 float/double 感兴趣...并给出十进制数字计数
我们需要输出/保存/处理...以获取整个精度
浮点类型可以提供。
理论示例:内容为 123.112233445566 的变量
如果您将 123.11223344 显示给用户,则它可能不够精确。
如果您向用户显示 123.1122334455660000000 ,这是没有意义的,因为
您可以省略尾随零(因为您的变量无论如何都不能容纳那么多)
因此,max_digits10 表示您在一个类型中可用的位数精度。

【讨论】:

    【解决方案2】:

    简单来说,

    • digits10 是保证文本→浮点→文本往返的十进制位数。
    • max_digits10 是保证正确浮点→文本→浮点往返所需的小数位数。

    两者都有例外,但这些值提供了最低限度的保证。阅读max_digits10 上的original proposal 了解一个明确的例子,W. Kahan 教授的话和更多细节。大多数 C++ 实现的浮点数据类型都遵循 IEEE 754。对于 IEEE 754,floatdigits106max_digits109;对于double,它是1517。请注意,这两个数字should not be confused 都具有浮点数的实际十进制精度。

    示例digits10

    char const *s1 = "8.589973e9";
    char const *s2 = "0.100000001490116119384765625";
    float const f1 = strtof(s1, nullptr);
    float const f2 = strtof(s2, nullptr);
    std::cout << "'" << s1 << "'" << '\t' << std::scientific << f1 << '\n';
    std::cout << "'" << s2 << "'" << '\t' << std::fixed << std::setprecision(27) << f2 << '\n';
    

    打印

    '8.589973e9'      8.589974e+009
    '0.100000001490116119384765625'   0.100000001490116119384765625
    

    直到第 6th 个有效数字的所有数字都被保留,而第 7th 数字对于第一个数字没有保留。但是,秒的所有 27 位数字都幸存下来; this 是一个例外。但是,大多数数字在 7 位之后会变得不同,并且所有数字在 6 位之内都会相同。

    总之,digits10 给出了在给定的float 中您可以指望的有效数字的数量与创建它的十进制形式的原始实数相同,即在转换成float

    示例max_digits10

    void f_s_f(float &f, int p) {
        std::ostringstream oss;
        oss << std::fixed << std::setprecision(p) << f;
        f = strtof(oss.str().c_str(), nullptr);
    }
    
    float f3 = 3.145900f;
    float f4 = std::nextafter(f3, 3.2f);
    std::cout << std::hexfloat << std::showbase << f3 << '\t' << f4 << '\n';
    f_s_f(f3, std::numeric_limits<float>::max_digits10);
    f_s_f(f4, std::numeric_limits<float>::max_digits10);
    std::cout << f3 << '\t' << f4 << '\n';
    f_s_f(f3, 6);
    f_s_f(f4, 6);
    std::cout << f3 << '\t' << f4 << '\n';
    

    打印

    0x1.92acdap+1   0x1.92acdcp+1
    0x1.92acdap+1   0x1.92acdcp+1
    0x1.92acdap+1   0x1.92acdap+1
    

    这里有两个不同的floats,当以max_digits10 精度数字打印时,它们给出不同的字符串,这些字符串在读回时会返回它们来自的原始floats。当以较低精度打印时,由于舍入,它们会给出相同的输出,因此当回读时会导致相同的float,而实际上它们来自不同的值。

    总而言之,max_digits10 至少需要以十进制形式消除两个浮点数的歧义,因此当转换回二进制浮点数时,我们会再次获得原始位,而不是稍微之前或之后的位,因为舍入误差。

    【讨论】:

    • 你使用十进制数字为:“base10 digit”或“right of .”
    • @NoSenseEtAl 在有效数字中以 10 位为基数。从 digits10 示例中:8.589973e9 有 7 个十进制数字并且不能在 text->float->text 往返中存活。
    • @legends2k 如果您想调用某人的代码 UB,您最好先了解您链接到的答案。不是oss.str().c_str()的所有用法都是UB,原代码写的没问题。
    • 好吧,我可能错了。但我想学习,请告诉我返回的临时字符串如何超出表达式? c_str 现在不是指向解构的 string 对象吗?
    • @legends2k 它仅在创建它的完整表达式中使用。在销毁任何临时对象后不会执行对strtof 的调用。
    猜你喜欢
    • 2012-05-31
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 2010-09-27
    • 2011-12-17
    • 2010-11-21
    • 1970-01-01
    相关资源
    最近更新 更多