【发布时间】:2010-10-05 04:51:25
【问题描述】:
Pi 的单/双/扩展精度浮点表示精确到小数位数?
【问题讨论】:
-
如果不告诉您您使用的是哪种语言以及您从哪里获得 PI,就无法回答这个问题?您使用的是常量还是库函数?
-
或者你的意思是时间序列数据库PI
标签: floating-point precision floating-accuracy
Pi 的单/双/扩展精度浮点表示精确到小数位数?
【问题讨论】:
标签: floating-point precision floating-accuracy
#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
【讨论】:
E_PI 必须有 L 后缀才能获得 long 双精度,否则会卡在双精度
当我检查 Quassnoi 的答案时,我似乎怀疑 long double 和 double 最终会具有相同的准确性,所以我挖了一点。如果我运行他用 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
^
【讨论】:
6位和14位。1位对3位大于0,最后一位虽然存储,但不能算精度点。
抱歉,如果没有更多上下文,我不知道扩展意味着什么。你是指 C# 的小数点吗?
【讨论】:
打印和计数,宝贝,打印和计数。 (或阅读specs。)
【讨论】:
浮点类型的准确性与 PI 或任何特定数字无关。它只取决于内存中存储了多少位特定类型。
在 IEEE-754 的情况下,float 使用 23 位尾数,因此它可以精确到 23+1 位精度,或十进制约 7 位精度。不管 π, e, 1.1, 9.87e9... 都以 24 位的形式存储在一个浮点数中。同样double(53位尾数)可以存储15~17位精度的十进制数字。
【讨论】:
double 中,它将精确到小数点后 15 位(至少对于 Ubuntu 18 附带的 gcc,在英特尔核心 i5 上运行 --- 我相信它已映射IEEE-754)。你存储 1000*pi,它会精确到小数点后 12 位。
1000*pi 并得到稍微不太准确的结果,这并不意味着精度降低了。你弄错了,因为你不明白什么是“有效位”,它不在小数点之后计算。事实上 1000*pi 只损失 1 位精度,仍然是 correct to the 15th digit of significand, not 12。你也混淆了'precision' and 'accuracy'?
在 x86 浮点单元 (x87) 中有用于加载某些浮点常量的指令。例如,“fldz”和“fld1”将 0.0 和 1.0 加载到堆栈顶部“st”(又名“st(0)”)。另一个是“fldpi”。
所有这些值都有一个 64 位长的尾数,可以转换为接近 20 个十进制数字。通过 x87 内部使用的 80 位临时浮点格式可以实现 64 位。 x87 也可以从 10 字节内存位置加载临时变量并将其存储到。
【讨论】:
World of PI 的 PI 为 100,000,000,000 位,您可以打印和比较。对于更易于阅读的版本,Joy of PI 有 10,000 位数字。如果你想自己记住数字,你可以尝试学习Cadaeic Cadenza这首诗。
【讨论】:
对于 C 代码,请查看 <float.h> 中的定义。这包括 float (FLT_*)、double (DBL_*) 和 long double (LDBL_*) 定义。
【讨论】:
由于存在用于 pi 的二进制表示的筛方程,因此可以组合变量来存储值的片段以提高精度。此方法对精度的唯一限制是从二进制转换为十进制,但即使是有理数也会遇到问题。
【讨论】:
* 编辑:查看此帖子了解最新讨论: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);
【讨论】:
__sinpi() 和 __cospi() 绝对不是标准函数。很容易看到,因为它们有 __ 前缀。搜索它们主要返回 macOS 和 iOS 的结果。这个问题说它是苹果Implementation of sinpi() and cospi() using standard C math library添加的,man page也说它在OSX中