【问题标题】:PI and accuracy of a floating-point number浮点数的 PI 和精度
【发布时间】:2010-10-05 04:51:25
【问题描述】:

Pi 的单/双/扩展精度浮点表示精确到小数位数?

【问题讨论】:

  • 如果不告诉您您使用的是哪种语言以及您从哪里获得 PI,就无法回答这个问题?您使用的是常量还是库函数?
  • 或者你的意思是时间序列数据库PI

标签: floating-point precision floating-accuracy


【解决方案1】:
#include <stdio.h>

#define E_PI 3.1415926535897932384626433832795028841971693993751058209749445923078164062

int main(int argc, char** argv)
{
    long double pild = E_PI;
    double pid = pild;
    float pif = pid;
    printf("%s\n%1.80f\n%1.80f\n%1.80Lf\n",
    "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899",
    pif, pid, pild);
    return 0;
}

结果:

[quassnoi #] gcc --version
gcc (GCC) 4.3.2 20081105 (Red Hat 4.3.2-7)

[quassnoi #] ./test

3.14159265358979323846264338327950288419716939937510582097494459230781640628620899

3.14159274101257324218750000000000000000000000000000000000000000000000000000000000
        ^
3.14159265358979311599796346854418516159057617187500000000000000000000000000000000
                 ^
3.14159265358979311599796346854418516159057617187500000000000000000000000000000000
                 ^
  0000000001111111
  1234567890123456

【讨论】:

  • 有趣的测试......不幸的是,我敢打赌它依赖于各种系统:P
  • 其实我说的是依赖math.h库。
  • 当然,这就是我把 gcc --version 放在那里的原因
  • 此测试对扩展精度结果无效,因为您的 pi 的#define 文字是双精度的。你需要它是一个扩展的精度文字。见this
  • E_PI 必须有 L 后缀才能获得 long 双精度,否则会卡在双精度
【解决方案2】:

当我检查 Quassnoi 的答案时,我似乎怀疑 long doubledouble 最终会具有相同的准确性,所以我挖了一点。如果我运行他用 clang 编译的代码,我会得到与他相同的结果。但是我发现如果我指定 long double 后缀并使用文字来初始化 long double 它提供了更高的精度。这是我的他的代码版本:

#include <stdio.h>

int main(int argc, char** argv)
{
    long double pild = 3.14159265358979323846264338327950288419716939937510582097494459230781640628620899L;
    double pid = pild;
    float pif = pid;
    printf("%s\n%1.80f\n%1.80f\n%1.80Lf\n",
        "3.14159265358979323846264338327950288419716939937510582097494459230781640628620899",
        pif, pid, pild);
    return 0;
}

结果:

3.14159265358979323846264338327950288419716939937510582097494459230781640628620899

3.14159274101257324218750000000000000000000000000000000000000000000000000000000000
        ^
3.14159265358979311599796346854418516159057617187500000000000000000000000000000000
                 ^
3.14159265358979323851280895940618620443274267017841339111328125000000000000000000
                    ^

【讨论】:

【解决方案3】:

6位和14位。1位对3位大于0,最后一位虽然存储,但不能算精度点。

抱歉,如果没有更多上下文,我不知道扩展意味着什么。你是指 C# 的小数点吗?

【讨论】:

【解决方案4】:

打印和计数,宝贝,打印和计数。 (或阅读specs。)

【讨论】:

    【解决方案5】:

    浮点类型的准确性与 PI 或任何特定数字无关。它只取决于内存中存储了多少位特定类型。

    在 IEEE-754 的情况下,float 使用 23 位尾数,因此它可以精确到 23+1 位精度,或十进制约 7 位精度。不管 π, e, 1.1, 9.87e9... 都以 24 位的形式存储在一个浮点数中。同样double(53位尾数)可以存储15~17位精度的十进制数字。

    【讨论】:

    • 你的逻辑/结论其实是不正确的。它与特定值相关;浮点的二进制表示具有固定数量的尾数位,但根据指数,其中一些位将用于表示整数部分或小数部分。一个有助于可视化这一点的示例:您将 pi 存储在 double 中,它将精确到小数点后 15 位(至少对于 Ubuntu 18 附带的 gcc,在英特尔核心 i5 上运行 --- 我相信它已映射IEEE-754)。你存储 1000*pi,它会精确到小数点后 12 位。
    • @Cal-linux 您误认为类型的精度与 执行操作后的错误。如果您执行1000*pi 并得到稍微不太准确的结果,这并不意味着精度降低了。你弄错了,因为你不明白什么是“有效位”,它不在小数点之后计算。事实上 1000*pi 只损失 1 位精度,仍然是 correct to the 15th digit of significand, not 12。你也混淆了'precision' and 'accuracy'?
    • 如果你有精确的 1000pi 常数,而不是在运行时通过乘法来做,你仍然会得到 53 位的精度
    • 你还是搞错了。浮点数的一个众所周知的方面是表示中的准确性/误差在整个范围内分布不均;您可以区分 0.1 和 0.1000001,但不能区分 10^50 和 (0.0000001 + 10^50)。 FP 将值存储为 x 乘以 2^_y_,其中 x 使用给定位数来表示 1 和 2 之间的值(或者是 0 和 1 之间的值? ? 我现在忘记了),并且 y 的范围由分配给它的位数给出。如果y很大,则x的准确率大部分被整数部分消耗。
    • 至于精确的 1000pi 作为常数 --- 你可能会得到相同的 53 位精度,但这不是线程的目的:你在开头得到相同的 16 个正确的十进制数字;但是现在这 16 个中的三个用于整数部分,3141 --- 小数位正确到 89793,与 pi 完全相同;除了在 pi 中,89793 中的 3 是小数点后第 15 位,而在 1000pi 中,它是小数点后第 12 位!
    【解决方案6】:

    在 x86 浮点单元 (x87) 中有用于加载某些浮点常量的指令。例如,“fldz”和“fld1”将 0.0 和 1.0 加载到堆栈顶部“st”(又名“st(0)”)。另一个是“fldpi”。

    所有这些值都有一个 64 位长的尾数,可以转换为接近 20 个十进制数字。通过 x87 内部使用的 80 位临时浮点格式可以实现 64 位。 x87 也可以从 10 字节内存位置加载临时变量并将其存储到。

    【讨论】:

      【解决方案7】:

      World of PI 的 PI 为 100,000,000,000 位,您可以打印和比较。对于更易于阅读的版本,Joy of PI 有 10,000 位数字。如果你想自己记住数字,你可以尝试学习Cadaeic Cadenza这首诗。

      【讨论】:

        【解决方案8】:

        对于 C 代码,请查看 &lt;float.h&gt; 中的定义。这包括 float (FLT_*)、double (DBL_*) 和 long double (LDBL_*) 定义。

        【讨论】:

          【解决方案9】:

          由于存在用于 pi 的二进制表示的筛方程,因此可以组合变量来存储值的片段以提高精度。此方法对精度的唯一限制是从二进制转换为十进制,但即使是有理数也会遇到问题。

          【讨论】:

            【解决方案10】:

            * 编辑:查看此帖子了解最新讨论:Implementation of sinpi() and cospi() using standard C math library *

            新的 math.h 函数 __sinpi()__cospi() 为我解决了 90 度等直角的问题。

            cos(M_PI * -90.0 / 180.0) returns 0.00000000000000006123233995736766
            __cospi( -90.0 / 180.0 )      returns 0.0, as it should
            
            /*  __sinpi(x) returns the sine of pi times x; __cospi(x) and __tanpi(x) return
            the cosine and tangent, respectively.  These functions can produce a more
            accurate answer than expressions of the form sin(M_PI * x) because they
            avoid any loss of precision that results from rounding the result of the
            multiplication M_PI * x.  They may also be significantly more efficient in
            some cases because the argument reduction for these functions is easier
            to compute.  Consult the man pages for edge case details.                 */
            extern float __cospif(float) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
            extern double __cospi(double) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
            extern float __sinpif(float) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
            extern double __sinpi(double) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
            extern float __tanpif(float) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
            extern double __tanpi(double) __OSX_AVAILABLE_STARTING(__MAC_10_9, __IPHONE_NA);
            

            【讨论】:

            猜你喜欢
            • 2018-02-23
            • 2010-12-26
            • 2015-07-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-02-03
            • 2012-06-25
            • 1970-01-01
            相关资源
            最近更新 更多