web-dev-qa-db-fra.com

Pourquoi définir PI = 4 * ATAN (1.d0)

Quelle est la motivation pour définir PI comme

PI=4.D0*DATAN(1.D0)

dans le code Fortran 77? Je comprends comment cela fonctionne, mais quel est le raisonnement?

53
ccook

Ce style garantit que la précision maximale disponible sur TOUTES les architectures est utilisée lors de l'attribution d'une valeur à PI.

63
John Gietzen

Parce que Fortran n'a pas de constante intégrée pour PI. Mais plutôt que de taper le nombre manuellement et de faire potentiellement une erreur ou de ne pas obtenir la précision maximale possible sur l'implémentation donnée, laisser la bibliothèque calculer le résultat pour vous garantit qu'aucun de ces inconvénients ne se produit.

Ce sont des équivalents et vous les verrez parfois aussi:

PI=DACOS(-1.D0)
PI=2.D0*DASIN(1.D0)
14
jason

Je crois que c'est parce que c'est la série la plus courte sur pi. Cela signifie également que c'est le PLUS PRÉCIS.

La série Gregory-Leibniz (4/1 - 4/3 + 4/5 - 4/7 ...) est égale à pi.

atan (x) = x ^ 1/1 - x ^ 3/3 + x ^ 5/5 - x ^ 7/7 ...

Donc, 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 ...

Cela équivaut à la série Gregory-Leibniz, et donc égale à pi, environ 3,1415926535 8979323846 2643383279 5028841971 69399373510.

Une autre façon d'utiliser atan et de trouver pi est:

pi = 16 * atan (1/5) - 4 * atan (1/239), mais je pense que c'est plus compliqué.

J'espère que ça aide!

(Pour être honnête, je pense que la série Gregory-Leibniz était basée sur atan, pas 4 * atan (1) sur la base de la série Gregory-Leibniz. En d'autres termes, la VRAIE preuve est:

sin ^ 2 x + cos ^ 2 x = 1 [Théorème] Si x = pi/4 radians, sin ^ 2 x = cos ^ 2 x, ou sin ^ 2 x = cos ^ 2 x = 1/2.

Ensuite, sin x = cos x = 1/(racine 2). tan x (sin x/cos x) = 1, atan x (1/tan x) = 1.

Donc, si atan (x) = 1, x = pi/4 et atan (1) = pi/4. Enfin, 4 * atan (1) = pi.)

S'il vous plaît, ne me chargez pas de commentaires - je suis encore un pré-adolescent.

13
Justin

C'est parce que c'est un moyen exact de calculer pi avec une précision arbitraire. Vous pouvez simplement continuer à exécuter la fonction pour obtenir une précision de plus en plus grande et vous arrêter à tout moment pour avoir une approximation.

En revanche, la spécification de pi comme constante vous fournit exactement autant de précision que ce qui avait été initialement donné, ce qui peut ne pas être approprié pour des applications hautement scientifiques ou mathématiques (comme Fortran est fréquemment utilisé avec).

9
John Feminella

Il y a plus à cette question qu'il n'y paraît. Pourquoi 4 arctan(1)? Pourquoi pas toute autre représentation telle que 3 arccos(1/2)?

Cela va essayer de trouver une réponse par exclusion.

introduction mathématique: Lors de l'utilisation de fonctions trigonométriques inverses comme arccos, arcsin et arctan, on peut facilement calculer π de différentes 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 de nombreuses autres expressions algébriques exactes pour les valeurs trigonométriques qui pourraient être utilisées ici.

argument à virgule flottante 1: il est bien entendu qu'une représentation binaire à virgule flottante finie ne peut pas représenter tous nombres réels. Quelques exemples de tels nombres sont 1/3, 0.97, π, sqrt(2), .... À cette fin, nous devons exclure tout calcul mathématique de π où l'argument des fonctions trigonométriques inverses ne peut pas être représenté 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 nombre est représenté par 0.bnbn-1... b x 2m. Si la fonction trigonométrique inverse a fourni la meilleure approximation binaire numérique pour son argument, nous ne voulons pas perdre de précision par multiplication. À cette fin, nous ne devons multiplier qu'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 la représentation IEEE-754 binaire64 (la forme la plus courante de DOUBLE PRECISION ou kind=REAL64). Là nous avons

write(*,'(F26.20)') 4.0d0*atan(1.0d0) -> "    3.14159265358979311600"
write(*,'(F26.20)') 3.0d0*acos(0.5d0) -> "    3.14159265358979356009"

Cette différence n'existe pas dans IEEE-754 binary32 (la forme la plus courante de REAL ou kind=REAL32) Et IEEE-754 binary128 ( la forme la plus courante de kind=REAL128)

Argument d'implémentation floue: à partir de ce point, tout dépend un peu de l'implémentation des fonctions trigonométriques inverses. Parfois, arccos et arcsin sont dérivés 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)))

De plus, atan2 Fait partie du jeu d'instructions x86 comme FPATAN tandis que les autres ne le sont pas. À cette fin, je dirais que:

π = 4 arctan(1)

sur tous les autres.

Remarque: ceci est un argument flou. Je suis certain qu'il y a des gens qui ont de meilleures opinions à ce sujet.

L'argument Fortran: pourquoi devrions-nous approximer π Comme:

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 pas :

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 se trouve dans le norme Fortran . La norme ne précise jamais qu'un REAL de quelque sorte que ce soit devrait représenter un nombre à virgule flottante IEEE-754 . La représentation de REAL dépend du processeur. Cela implique que je pourrais demander selected_real_kind(33, 4931) et m'attendre à obtenir un nombre à virgule flottante binaire128 , mais je pourrais obtenir un kind retourné qui représente un point flottant avec beaucoup une plus grande précision. Peut-être 100 chiffres, qui sait. Dans ce cas, ma chaîne de chiffres ci-dessus est trop courte! On ne peut pas utiliser this 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
4
kvantour