计算圆周率是一个复杂的问题,维基百科讨论了对其进行的近似并表示计算准确的圆周率很困难。
C语言如何计算圆周率?它每次都计算还是使用不太准确的固定值?
#define M_PI 3.14159265358979323846
。<math.h>
中定义 PI
常量,甚至 POSIX 规定的 M_PI
常量也不一定被定义。这是因为 POSIX 的一些要求与 C 标准有所冲突。但你可以在自己的程序中定义这样一个常量。 - Keith ThompsonC语言中最接近“计算π”的方式可能就是直接使用acos(-1)
或类似函数。这通常会通过多项式/有理逼近来计算被计算的函数(无论是在C中还是由FPU微码实现)。
然而,一个有趣的问题是计算三角函数(sin
, cos
, 和 tan
)需要将它们的参数对2π取模。由于2π不是二进制有理数(甚至不是有理数),所以它不能用任何浮点类型表示,因此对于大参数使用任何精度逼近的值都会导致灾难性的误差积累(例如,如果x
是1e12
,并且2*M_PI
和2π之间相差ε,那么fmod(x,2*M_PI)
与2π的正确值相差多达1e12*ε/π倍x mod 2π
的正确值。也就是说,这是完全没有意义的。
C标准数学库的正确实现只需在其源代码中硬编码一个巨大的高精度π表示来解决正确的参数约减问题(并使用一些花哨的技巧使其不那么巨大)。这就是大多数/全部C版本的sin
/cos
/tan
函数的工作原理。然而,某些实现(如glibc)在某些cpu上(如x86)上使用汇编实现,并且不执行正确的参数约减,导致完全无意义的输出。(顺便说一句,不正确的汇编通常对于小参数的速度与正确的C代码差不多。)
x
的正弦几乎没有意义,并且很可能是使用正弦函数的代码中的错误。如果x
太大以至于成为整数,那么每个正弦周期只能表示大约6个x
的值。当然可以找到满足条件的y
,这很好,但我怀疑计算整数的正弦是否有任何有用的应用。 - Fritzx
的极端情况更有趣的是分析这个“epsilon误差”随着x
增加的速度。如果在1000*M_PI
处存在显著误差,那么我理解这个问题,并且会完全同意您的观点。 - Fritzfmod(x,2*M_PI)
的误差与正确的参数缩减值在x
的数量级上呈线性增长。因此,假设x
在单位圆外部仅有1ulp的误差,那么在1000*M_PI
处就会出现大约1000ulp的误差。在零点附近,sin
接近于斜率为1的线性函数,因此参数中的ulp数量直接转化为结果中的ulp数量。 - R.. GitHub STOP HELPING ICEsin(2^n)
有一些有趣的应用;虽然我现在不记得它们是什么了。 - R.. GitHub STOP HELPING ICE定义如下:
#define M_PI acos(-1.0)
它应该给出您正在使用的数学函数精确的PI值。 因此,如果他们在正切、余弦或正弦中更改了他们正在使用的PI值,则您的程序应始终保持最新状态 ;)
acos
函数是C语言的一部分。 - Kaz无论如何,您都没有无限的准确性,因此C以这种方式定义常量:
#define PI 3.14159265358979323846
导入math.h即可使用此功能
M_PI
不是 C 语言的一部分。它是 POSIX 中 XSI 扩展选项的一部分。 - R.. GitHub STOP HELPING ICEM_*
常量都带有 [XSI>
标签。 - R.. GitHub STOP HELPING ICE根据您使用的库,标准GNU C预定义数学常量在此处... https://www.gnu.org/software/libc/manual/html_node/Mathematical-Constants.html
您已经拥有它们,为什么要重新定义呢? 您的系统桌面计算器可能已经拥有它们,并且更加精确,因此您可以使用它们,但请确保不会与现有定义的常量冲突,以避免编译警告,因为它们往往会对此类事情进行默认设置。 享受吧!
double caculate_pi(int accuracy){
double result = 1;
int a = 2;
int b = 1;
for(i = 0;i < accuracy; i ++){
result = a/b * result;
if(a < b){
a = a + 2;
}
else if(b < a){
b = b + 2;
}
}
return result * 2;
}
我不确定 C
如何直接计算 PI
,因为我比较熟悉 C++
而不是 C
。但是,你可以使用预定义的 C
宏或常量,例如:
#define PI 3.14159265359.....
const float PI = 3.14159265359.....
const double PI = 3.14159265359.....
/* If your machine,os & compiler supports the long double */
const long double PI = 3.14159265359.....
或者你可以使用以下两个公式之一来计算:
#define M_PI acos(-1.0);
#define M_PI (4.0 * atan(1.0)); // tan(pi/4) = 1 or acos(-1)
个人认为,我不是100%确定,但我认为atan()
比acos()
更便宜。
#define CONSTANT numberHere
? - Francis CuglerC
已经非常生疏了,因为我已经有近20年没有使用它了,而且我主要使用的是 C++
。我最初回答这个问题时是从 C++
的角度出发的... 我已经更新了答案以适应这一点... - Francis Cugler
double
可以得到的精度)即可计算出太阳系的直径,误差不超过一根头发宽度。 - pmg