簡単なプログラミング演習に取り組んでいるときに、実変数が正確な値に達したときに終了することを意図した while ループ (Fortran では DO ループ) を作成しました。
精度が使用されているため、等式が満たされず、ループが無限になることに気付きました。もちろん、これは前例のないことではなく、2 つの数値が等しいかどうかを比較するのではなく、2 つの数値の絶対差が設定されたしきい値よりも小さいかどうかを確認することをお勧めします。
残念だったのは、変数が倍精度であっても、ループが適切に終了するために、このしきい値をどれだけ低く設定しなければならなかったかということです。さらに、Perl でこのループの「蒸留」バージョンを書き直したところ、数値の精度に問題はなく、ループは正常に終了しました。
Perl と Fortran の両方で、問題を生成するコードは非常に小さいため、重要な詳細を説明する場合に備えて、ここで再現したいと思います。
Fortran コード
PROGRAM precision_test
IMPLICIT NONE
! Data Dictionary
INTEGER :: count = 0 ! Number of times the loop has iterated
REAL(KIND=8) :: velocity
REAL(KIND=8), PARAMETER :: MACH_2_METERS_PER_SEC = 340.0
velocity = 0.5 * MACH_2_METERS_PER_SEC ! Initial Velocity
DO
WRITE (*, 300) velocity
300 FORMAT (F20.8)
IF (count == 50) EXIT
IF (velocity == 5.0 * MACH_2_METERS_PER_SEC) EXIT
! IF (abs(velocity - (5.0 * MACH_2_METERS_PER_SEC)) < 1E-4) EXIT
velocity = velocity + 0.1 * MACH_2_METERS_PER_SEC
count = count + 1
END DO
END PROGRAM precision_test
Perl コード
#! /usr/bin/perl -w
use strict;
my $mach_2_meters_per_sec = 340.0;
my $velocity = 0.5 * $mach_2_meters_per_sec;
while (1) {
printf "%20.8f\n", $velocity;
exit if ($velocity == 5.0 * $mach_2_meters_per_sec);
$velocity = $velocity + 0.1 * $mach_2_meters_per_sec;
}
Fortran のコメントアウトされた行は、ループが正常に終了するために使用する必要があるものです。しきい値が 1E-4 に設定されていることに注意してください。
変数の名前は、私が行っていた自習ベースのプログラミング演習に由来するものであり、関連性はありません。
その意図は、速度変数が 1700 に達したときにループが停止することです。
切り捨てられた出力は次のとおりです。
Perl 出力
170.00000000
204.00000000
238.00000000
272.00000000
306.00000000
340.00000000
...
1564.00000000
1598.00000000
1632.00000000
1666.00000000
1700.00000000
Fortran 出力
170.00000000
204.00000051
238.00000101
272.00000152
306.00000203
340.00000253
...
1564.00002077
1598.00002128
1632.00002179
1666.00002229
1700.00002280
精度が悪ければ、Fortran の速度と並列化の容易さは何の役に立つでしょうか? 物事を行う3つの方法を思い出します:
正しい道
間違った方法
マックスパワーウェイ
「やり方が間違っているだけじゃないの?」
「うん!でももっと早く!」
冗談はさておき、私は何か間違ったことをしているに違いありません。
Fortran は、他の言語と比較して数値の精度に固有の制限がありますか、それとも (かなりの確率で) 私に問題があるのでしょうか?
私のコンパイラは gfortran (gcc バージョン 4.1.2)、Perl v5.12.1、デュアル コア AMD Opteron @ 1 GHZ です。