Pourquoi définir PI = 4 * atan (1.d0)
Question
Quelle est la motivation pour définir PI comme
PI=4.D0*DATAN(1.D0)
du code Fortran 77? Je comprends comment cela fonctionne, mais quel est le raisonnement?
La solution
Ce style garantit que la précision maximale disponible sur toute architecture est utilisée lors de l'attribution d'une valeur à PI.
Autres conseils
Parce que Fortran ne dispose pas d'une constante intégrée pour PI
. Mais plutôt que de taper le numéro manuellement et faisant potentiellement une erreur ou ne pas obtenir la précision maximale possible sur la mise en œuvre donnée, laissant la bibliothèque calculer le résultat pour vous garantit qu'aucun de ces inconvénients se produisent.
Ce sont équivalentes et vous verrez parfois les voir aussi:
PI=DACOS(-1.D0)
PI=2.D0*DASIN(1.D0)
Je crois qu'il est parce que c'est la série la plus courte sur pi. Cela signifie aussi qu'il est le plus précis.
La série Gregory-Leibniz (04.01 à 04.03 + 04.05 au 04.07 ...). Pi est égal à
atan (x) = x ^ 1/1 - x ^ 3/3 + x ^ 5/5 - x ^ 7/7 ...
Alors, atan (1) = 01/01 au 01/03 + 01/05 au 01/07 + 1/9 ... 4 * atan (1) = 4.1 à 4.3 + 4/5 à 4/7 + 4/9 ...
Cela correspond à la série Gregory-Leibniz, et est donc égale à pi, environ 3,1415926535 8979323846 2643383279 5028841971 69399373510.
Une autre façon d'utiliser atan et trouver pi est:
pi = 16 * atan (1/5) - 4 * atan (1/239), mais je pense que c'est plus compliqué
.J'espère que cela aide!
(Pour être honnête, je pense que la série Gregory-Leibniz était basée sur atan, pas 4 * atan (1) basé sur la série Gregory-Leibniz En d'autres termes, la preuve est REAL:.
sin ^ 2 x + cos ^ 2 = x 1 [Théorème] Si x = pi / 4 radians, sin ^ cos 2 x = ^ 2 X ou sin ^ 2 = x cos ^ 2 x = 1/2.
Ensuite, sin x = cos x = 1 / (racine de 2). tan x (sin x / cos x) = 1, x atan (1 / tan x) = 1.
Si atan (x) = 1, x = pi / 4, et atan (1) = pi / 4. Enfin, 4 * atan (1) = pi.)
S'il vous plaît ne me charge pas avec des commentaires, je suis encore un pré-ado.
Il est parce que c'est une façon exacte de calculer pi
à la précision arbitraire. Vous pouvez simplement continuer à exécuter la fonction pour obtenir une plus grande et une plus grande précision et arrêter à tout moment d'avoir une approximation.
Par contre, en spécifiant pi
comme une constante vous fournit exactement autant de précision que l'origine donné, ce qui peut ne pas être approprié pour les applications hautement scientifiques ou mathématiques (comme Fortran est souvent utilisé avec).
Il y a plus à cette question que rencontre l'oeil. Pourquoi 4 arctan(1)
? Pourquoi aucune autre représentation, comme 3 arccos(1/2)
?
va essayer de trouver une réponse par l'exclusion.
introduction mathématique: Lorsque vous utilisez inverses des fonctions trigonométriques comme arccos, arcsin et arctan , on peut facilement calculer π de diverses manières:
π = 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) = ...
Il existe beaucoup d'autres expressions algébriques exactes pour les valeurs trigonométriques qui pourrait être utilisé ici.
argument en virgule flottante 1: il est bien entendu que représentation binaire en virgule flottante finie ne peut pas représenter tous les nombres réels . Quelques exemples de ces chiffres sont 1/3, 0.97, π, sqrt(2), ...
. À cette fin, nous devrions exclure tout calcul mathématique de π où l'argument des fonctions trigonométriques inverses ne peut pas être représentée numériquement. Cela nous laisse les arguments -1,-1/2,0,1/2
et 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)
argument à virgule flottante 2: dans la représentation binaire, un numéro est représenté par 0.b n b n-1 ... b 0 x 2 m . Si la fonction trigonométrique inverse est arrivé avec la meilleure approximation binaire numérique pour son argument, nous ne voulons pas perdre la précision par multiplication. À cette fin, nous ne devons multiplier avec des puissances de 2.
π = 4 arctan(1) = 2 arcsin(1)
= 2 arccos(0)
= -4 arctan(-1) = arccos(-1) = -2 arcsin(-1)
Note: Ceci est visible dans le IEEE-754 la représentation des binary64 (la forme la plus commune de DOUBLE PRECISION
ou kind=REAL64
). Nous avons là
write(*,'(F26.20)') 4.0d0*atan(1.0d0) -> " 3.14159265358979311600"
write(*,'(F26.20)') 3.0d0*acos(0.5d0) -> " 3.14159265358979356009"
Cette différence n'est pas là dans IEEE-754 binary32 (le plus forme commune de REAL
ou kind=REAL32
) et IEEE-754 binary128 (le plus courant sous forme de kind=REAL128
)
l'argument de mise en œuvre floue: à partir de ce point, tout dépend un peu sur la mise en œuvre des fonctions trigonométriques inverses. Parfois, arccos
et arcsin
proviennent de atan2
et atan2
comme
ACOS(x) = ATAN2(SQRT(1-x*x),1)
ASIN(x) = ATAN2(1,SQRT(1-x*x))
ou plus précisément d'un point de vue numérique:
ACOS(x) = ATAN2(SQRT((1+x)*(1-x)),1)
ASIN(x) = ATAN2(1,SQRT((1+x)*(1-x)))
En outre, atan2
fait partie du x86 Jeu d'instructions comme FPATAN
tandis que les autres ne sont pas. À cette fin, je dirais l'utilisation de:
π = 4 arctan(1)
sur tous les autres.
Note: c'est un argument floue. Je suis certain qu'il ya des gens avec de meilleures opinions sur ce sujet.
L'argument Fortran: pourquoi devrions-nous π
approximative:
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)
et non:
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
La réponse réside dans le Fortran norme . La norme jamais indique qu'un REAL
de quelque nature que devrait représenter un IEEE-754 numéro virgule flottante . La représentation de REAL
dépend processeur. Cela implique que je pouvais demander selected_real_kind(33, 4931)
et espérer obtenir un binary128 nombre à virgule flottante , mais je pourrais obtenir un kind
revenu qui représente un point flottant avec une précision beaucoup plus élevée. Peut-être 100 chiffres, qui sait. Dans ce cas, ma chaîne au-dessus des chiffres est à court! On ne peut pas utiliser cette juste pour être sûr? Même ce fichier pourrait être trop court!
fait intéressant: 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"
qui est compris comme:
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
Cela semble beaucoup comme un travail autour d'un bug du compilateur. Ou il se pourrait que ce programme dépend de cette identité étant exacte, et que le programmeur fait garanti.