52


10

PI = 4 * ATAN(1.d0)を定義する理由

PIを次のように定義する動機は何ですか?

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

Fortran 77コード内で? 私はそれがどのように機能するか理解していますが、理由は何ですか?

6 Answer


62


このスタイルにより、PIに値を割り当てるときに、どのアーキテクチャでも利用可能な最大精度が使用されることが保証されます。


14


Fortranには `PI`の組み込み定数がないためです。 ただし、番号を手動で入力して間違いを犯したり、特定の実装で最大限の精度を得られない可能性があるのではなく、ライブラリに結果を計算させて、これらの欠点が発生しないことを保証します。

これらは同等であり、時々表示されることもあります。

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


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)ですが、もっと複雑だと思います。

これが助けになれば幸いです。

(正直なところ、グレゴリーライプニッツシリーズはグレゴリーライプニッツシリーズに基づく4 * atan(1)ではなく、atanに基づいていたと思います。 つまり、実際の証明は次のとおりです。

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 /(root 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)

コメントを私にロードしないでください-私はまだ十代前です。


9


これは、これが `pi`を任意の精度で計算する正確な方法だからです。 関数を実行し続けるだけで精度を高め、任意の時点で停止して近似値を得ることができます。

対照的に、定数として「pi」を指定すると、元々与えられたのとまったく同じ精度が得られますが、これは高度な科学的または数学的なアプリケーションには適していません(Fortranがよく使用されます)。


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) = ...

ここで使用できる他の多くのhttps://en.wikipedia.org/wiki/Trigonometric_constants_expressed_in_real_radicals [三角値の正確な代数式]が存在します。

浮動小数点引数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)

_note:_これはhttps://en.wikipedia.org/wiki/Double-precision_floating-point_format[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"

この違いはhttps://en.wikipedia.org/wiki/Single-precision_floating-point_format[IEEE-754 binary32]( REAL`または kind = REAL32`の最も一般的な形式)およびhttps://にはありません。 en.wikipedia.org/wiki/Quadruple-precision_floating-point_format[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`はhttps://x86.puri.sm/html/file_module_x86_id_106.html[x86 Instruction 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

答えはhttps://j3-fortran.org/doc/year/10/10-007.pdf[Fortran standard]にあります。 標準の* never *は、あらゆる種類の `REAL`がhttp://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4610935[IEEE-754浮動小数点数]を表すことを示しています。 「REAL」の表現はプロセッサに依存します。 これは、「selected_real_kind(33、4931)」に問い合わせてhttps://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format[binary128 floating point number]を取得することを期待できることを意味しますが、「kind `はるかに高い精度で浮動小数点を表す返されます。 たぶん、100桁でしょう。 この場合、上記の数字の列は短くなります! 念のためhttps://introcs.cs.princeton.edu/java/data/pi-10million.txt[this]を使用することはできませんか? そのファイルでさえ短すぎます!

*興味深い事実: 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(δ) ≈ δ

'' '' '

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


これは、コンパイラのバグの回避策に非常によく似ています。 または、この特定のプログラムがそのIDが正確であることに依存している可能性があるため、プログラマーはそれを保証しました。