Fortran 为什么定义PI=4*ATAN(1.d0)
将PI定义为Fortran 为什么定义PI=4*ATAN(1.d0),fortran,fortran77,pi,Fortran,Fortran77,Pi,将PI定义为 PI=4.D0*DATAN(1.D0) 在Fortran 77代码中?我理解它是如何工作的,但是,原因是什么呢?这听起来很像是针对编译器错误的一种解决方法。或者可能是这个特定的程序依赖于这个恒等式的精确性,所以程序员保证了它。这是因为这是一种精确计算pi的方法,可以达到任意精度。您可以简单地继续执行函数以获得越来越高的精度,并在任意点停止以获得近似值 相比之下,将pi指定为常数可以提供与最初给定的精度完全相同的精度,这可能不适用于高度科学或数学应用程序(因为Fortran经常用于
PI=4.D0*DATAN(1.D0)
在Fortran 77代码中?我理解它是如何工作的,但是,原因是什么呢?这听起来很像是针对编译器错误的一种解决方法。或者可能是这个特定的程序依赖于这个恒等式的精确性,所以程序员保证了它。这是因为这是一种精确计算pi的方法,可以达到任意精度。您可以简单地继续执行函数以获得越来越高的精度,并在任意点停止以获得近似值
相比之下,将
pi
指定为常数可以提供与最初给定的精度完全相同的精度,这可能不适用于高度科学或数学应用程序(因为Fortran经常用于).此样式确保在为PI赋值时使用任何体系结构上可用的最大精度。因为Fortran没有用于PI的内置常量。但是,让库为您计算结果,而不是手动输入数字并可能出错或无法获得给定实现的最大可能精度,可以保证不会出现上述任何不利情况
这些是等效的,您有时也会看到它们:
PI=DACOS(-1.D0)
PI=2.D0*DASIN(1.D0)
我相信这是因为这是pi上最短的系列。这也意味着它是最准确的 格雷戈里·莱布尼茨级数(4/1-4/3+4/5-4/7…)等于π 阿坦(x)=x^1/1-x^3/3+x^5/5-x^7/7 所以,atan(1)=1/1-1/3+1/5-1/7+1/9。。。 4*atan(1)=4/1-4/3+4/5-4/7+4/9 这等于Gregory Leibniz级数,因此大约等于π 3.1415926535 8979323846 2643383279 5028841971 69399373510 使用atan和查找pi的另一种方法是: pi=16*atan(1/5)-4*atan(1/239),但我认为这更复杂 我希望这有帮助 (老实说,我认为格雷戈里·莱布尼茨系列是以阿坦为基础的,而不是以格雷戈里·莱布尼茨系列为基础的4*阿坦(1)。换句话说,真正的证据是: sin^2 x+cos^2 x=1[定理] 如果x=pi/4弧度,则sin^2 x=cos^2 x或sin^2 x=cos^2 x=1/2 然后,sinx=cosx=1/(根2)。tanx(sinx/cosx)=1,atanx(1/tanx)=1 所以如果atan(x)=1,x=pi/4,atan(1)=pi/4。 最后,4*atan(1)=pi。)
请不要给我太多的评论,我还是一个十几岁的孩子。这个问题的内容远远超出了我的想象。为什么
4 arctan(1)
?为什么没有任何其他表示法,例如3 arccos(1/2)
这将试图通过排除找到答案
数学简介:当使用反三角函数如arccos、arcsin和arctan时,可以通过各种方式轻松计算π:
π = 4 arctan(1) = arccos(-1) = 2 arcsin(1) = 3 arccos(1/2) = 6 arcsin(1/2)
= 3 arcsin(sqrt(3)/2) = 4 arcsin(sqrt(2)/2) = ...
这里还有许多其他的方法可以使用
浮点参数1:众所周知,有限二进制浮点表示不能表示所有实数。这些数字的一些例子是1/3,0.97,π,sqrt(2),…
。为此,我们应该排除任何π的数学计算,因为逆三角函数的参数不能用数字表示。这就剩下了参数-1、-1/2,0,1/2
和1
π = 4 arctan(1) = 2 arcsin(1)
= 3 arccos(1/2) = 6 arcsin(1/2)
= 2 arccos(0)
= 3/2 arccos(-1/2) = -6 arcsin(-1/2)
= -4 arctan(-1) = arccos(-1) = -2 arcsin(-1)
浮点参数2:在二进制表示法中,数字表示为0.bnbn-1…b0 x 2m。如果反三角函数为其参数提供了最佳的数值二元逼近,我们不希望因乘法而失去精度。为此,我们只应乘以2的幂
π = 4 arctan(1) = 2 arcsin(1)
= 2 arccos(0)
= -4 arctan(-1) = arccos(-1) = -2 arcsin(-1)
注意:这在表示中可见(最常见的形式是双精度
或kind=REAL64
)。好了
write(*,'(F26.20)') 4.0d0*atan(1.0d0) -> " 3.14159265358979311600"
write(*,'(F26.20)') 3.0d0*acos(0.5d0) -> " 3.14159265358979356009"
(最常见的REAL
或kind=REAL32
)和(最常见的kind=REAL128
)没有这种区别
实现参数:在英特尔CPU上,atan2
是的一部分,而另一个逆三角函数是从atan2
导出的。一个可能的推导可能是:
mathematically numerically
ACOS(x) = ATAN2(SQRT(1-x*x),1) = ATAN2(SQRT((1+x)*(1-x)),1)
ASIN(x) = ATAN2(1,SQRT(1-x*x)) = ATAN2(1,SQRT((1+x)*(1-x)))
这可以在这些说明的汇编代码中看到(请参阅)。为此,我主张使用:
π = 4 arctan(1)
注意:这是一个模糊参数。我肯定有人对此有更好的看法。关于FPATAN的有趣阅读: Fortran参数:我们为什么要将
π
近似为:
integer, parameter :: sp = selected_real_kind(6, 37)
integer, parameter :: dp = selected_real_kind(15, 307)
integer, parameter :: qp = selected_real_kind(33, 4931)
real(kind=sp), parameter :: pi_sp = 4.0_sp*atan2(1.0_sp,1.0_sp)
real(kind=dp), parameter :: pi_dp = 4.0_dp*atan2(1.0_dp,1.0_dp)
real(kind=qp), parameter :: pi_qp = 4.0_qp*atan2(1.0_qp,1.0_qp)
而不是:
real(kind=sp), parameter :: pi_sp = 3.14159265358979323846264338327950288_sp
real(kind=dp), parameter :: pi_dp = 3.14159265358979323846264338327950288_dp
real(kind=qp), parameter :: pi_qp = 3.14159265358979323846264338327950288_qp
答案就在这里。标准never规定,任何类型的REAL
都应代表。REAL
的表示取决于处理器。这意味着我可以查询selected\u real\u kind(334931)
并期望获得一个,但我可能会得到一个返回的kind
,它表示精度更高的浮点。也许是100位数,谁知道呢。在这种情况下,我上面的数字串很短!不能只是为了确定而使用?甚至那个文件也可能太短了
有趣的事实:sin(pi)从来都不是零
write(*,'(F17.11)') sin(pi_sp) => " -0.00000008742"
write(*,'(F26.20)') sin(pi_dp) => " 0.00000000000000012246"
write(*,'(F44.38)') sin(pi_qp) => " 0.00000000000000000000000000000000008672"
其理解为:
pi = 4 ATAN2(1,1) = π + δ
SIN(pi) = SIN(pi - π) = SIN(δ) ≈ δ
作为替代方案,我几乎希望看到PI=3.1415926535。。。etc Instead在Math Stackoverflow网站上找到了这个方程的最优秀的数学答案,如果你使用PI=3.1415926535。。。必须添加数据类型后缀才能获得除默认实际精度以外的任何值。由于您使用的是f66双精度,因此这将是D0后缀。注意:现代Fortran不需要
DATAN()
:ATAN()
根据参数将别名添加到其各自的单精度和双精度版本。此处提到的功能是在Fortran 77中引入的。在过去的30年里,剩下的情况是
program print_pi
! use iso_fortran_env, sp=>real32, dp=>real64, qp=>real128
integer, parameter :: sp = selected_real_kind(6, 37)
integer, parameter :: dp = selected_real_kind(15, 307)
integer, parameter :: qp = selected_real_kind(33, 4931)
real(kind=sp), parameter :: pi_sp = 3.14159265358979323846264338327950288_sp
real(kind=dp), parameter :: pi_dp = 3.14159265358979323846264338327950288_dp
real(kind=qp), parameter :: pi_qp = 3.14159265358979323846264338327950288_qp
write(*,'("SP "A17)') "3.14159265358..."
write(*,'(F17.11)') pi_sp
write(*,'(F17.11)') acos(-1.0_sp)
write(*,'(F17.11)') 2.0_sp*asin( 1.0_sp)
write(*,'(F17.11)') 4.0_sp*atan2(1.0_sp,1.0_sp)
write(*,'(F17.11)') 3.0_sp*acos(0.5_sp)
write(*,'(F17.11)') 6.0_sp*asin(0.5_sp)
write(*,'("DP "A26)') "3.14159265358979323846..."
write(*,'(F26.20)') pi_dp
write(*,'(F26.20)') acos(-1.0_dp)
write(*,'(F26.20)') 2.0_dp*asin( 1.0_dp)
write(*,'(F26.20)') 4.0_dp*atan2(1.0_dp,1.0_dp)
write(*,'(F26.20)') 3.0_dp*acos(0.5_dp)
write(*,'(F26.20)') 6.0_dp*asin(0.5_dp)
write(*,'("QP "A44)') "3.14159265358979323846264338327950288419..."
write(*,'(F44.38)') pi_qp
write(*,'(F44.38)') acos(-1.0_qp)
write(*,'(F44.38)') 2.0_qp*asin( 1.0_qp)
write(*,'(F44.38)') 4.0_qp*atan2(1.0_qp,1.0_qp)
write(*,'(F44.38)') 3.0_qp*acos(0.5_qp)
write(*,'(F44.38)') 6.0_qp*asin(0.5_qp)
write(*,'(F17.11)') sin(pi_sp)
write(*,'(F26.20)') sin(pi_dp)
write(*,'(F44.38)') sin(pi_qp)
end program print_pi