将PI定义为
的动机是什么?PI=4.D0*DATAN(1.D0)
在Fortran 77代码中?我理解它是如何工作的,但是,理由是什么?
答案 0 :(得分:63)
此样式确保在为PI分配值时使用ANY体系结构上可用的最大精度。
答案 1 :(得分:14)
因为Fortran没有PI
的内置常量。但是,不是手动输入数字并且可能犯错误或者没有在给定的实现上获得最大可能的精度,而是让库为您计算结果,保证不会发生这些缺点。
这些是等效的,你有时也会看到它们:
PI=DACOS(-1.D0)
PI=2.D0*DASIN(1.D0)
答案 2 :(得分:13)
我相信这是因为这是关于pi的最短系列。这也意味着它是最准确的。
Gregory-Leibniz系列赛(4/1 - 4/3 + 4/5 - 4/7 ......)等于pi。
atan(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 ......
这等于格雷戈里 - 莱布尼兹系列,因此约等于pi 3.1415926535 8979323846 2643383279 5028841971 69399373510。
另一种使用atan并找到pi的方法是:
pi = 16 * atan(1/5) - 4 * atan(1/239),但我认为这更复杂。
我希望这有帮助!
(老实说,我认为Gregory-Leibniz系列是基于atan而不是基于Gregory-Leibniz系列的4 * atan(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。
然后,sin x = cos x = 1 /(根2)。 tan x(sin x / cos x)= 1,atan x(1 / tan x)= 1。
因此,如果atan(x)= 1,则x = pi / 4,并且atan(1)= pi / 4。 最后,4 * atan(1)= pi。)
请不要加载我的评论 - 我还是一个青少年。
答案 3 :(得分:9)
这是因为这是将pi
计算为任意精度的精确方法。您可以简单地继续执行该函数以获得更高和更高的精度,并在任何点停止以获得近似值。
相比之下,将pi
指定为常量会为您提供与最初给定的精确度相同的精度,这可能不适合高度科学或数学应用(因为Fortran经常使用)。
答案 4 :(得分:4)
这个问题还有很多,而不是眼睛。为什么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) = ...
此处可以使用许多其他exact algebraic expressions for trigonometric values。
浮点参数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.b n b n-1 ... b 0 x 2 m 。如果反三角函数为其参数提供了最佳数值二进制近似,我们不希望通过乘法丢失精度。为此,我们应该只乘以2的幂。
π = 4 arctan(1) = 2 arcsin(1)
= 2 arccos(0)
= -4 arctan(-1) = arccos(-1) = -2 arcsin(-1)
注意:这在IEEE-754 binary64表示(DOUBLE PRECISION
或kind=REAL64
的最常见形式)中可见。我们有
write(*,'(F26.20)') 4.0d0*atan(1.0d0) -> " 3.14159265358979311600"
write(*,'(F26.20)') 3.0d0*acos(0.5d0) -> " 3.14159265358979356009"
IEEE-754 binary32(最常见的REAL
或kind=REAL32
)和IEEE-754 binary128(最常见的kind=REAL128
形式)不存在这种差异
模糊实现参数:从这一点来说,一切都取决于反三角函数的实现。有时arccos
和arcsin
来自atan2
和atan2
ACOS(x) = ATAN2(SQRT(1-x*x),1)
ASIN(x) = ATAN2(1,SQRT(1-x*x))
或更具体地从数字角度来看:
ACOS(x) = ATAN2(SQRT((1+x)*(1-x)),1)
ASIN(x) = ATAN2(1,SQRT((1+x)*(1-x)))
此外,atan2
是x86 Instruction set as FPATAN
的一部分,而其他则不是。为此我会争论使用:
π = 4 arctan(1)
超过所有其他人。
注意:这是一个模糊的论点。我确信有人对此有更好的意见。
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
答案在Fortran standard中。标准从不声明任何类型的REAL
应代表IEEE-754 floating point number。 REAL
的表示取决于处理器。这意味着我可以查询selected_real_kind(33, 4931)
并期望获得binary128 floating point number,但我可能会返回kind
,表示具有更高精度的浮点数。也许100位数,谁知道。在这种情况下,我上面的数字串是短的!一个人不能只使用this来确定吗?即便是那个档案也可能太短了!
有趣的事实:sin(pi) is never zero
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(δ) ≈ δ
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
答案 5 :(得分:-5)
对于编译器错误而言,这听起来很糟糕。或者可能是这个特定程序依赖于该身份的确切性,因此程序员保证了这一点。