EMi*_*ler 5 perl fortran floating-accuracy double-precision
在进行简单的编程练习时,我创建了一个while循环(Fortran中的DO循环),当一个实变量达到精确值时,它就会退出.
我注意到由于使用的精度,从未满足相等性并且循环变得无限.当然,这并不是闻所未闻的,并且建议不要将两个数字进行相等比较,最好看两个数字之间的绝对差值是否小于设定的阈值.
我发现令人失望的是我必须设置这个阈值,即使变量是双精度,我的循环也能正常退出.此外,当我在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
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
Fortran中注释掉的行是我需要使用的循环才能正常退出.请注意,阈值设置为1E-4,我觉得这很可怜.
变量的名称来自我正在执行的基于自学习的编程练习,并且没有任何相关性.
目的是当速度变量达到1700时循环停止.
以下是截断的输出:
Perl输出
170.00000000
204.00000000
238.00000000
272.00000000
306.00000000
340.00000000
Run Code Online (Sandbox Code Playgroud)
...
1564.00000000
1598.00000000
1632.00000000
1666.00000000
1700.00000000
Run Code Online (Sandbox Code Playgroud)
Fortran输出
170.00000000
204.00000051
238.00000101
272.00000152
306.00000203
340.00000253
Run Code Online (Sandbox Code Playgroud)
...
1564.00002077
1598.00002128
1632.00002179
1666.00002229
1700.00002280
Run Code Online (Sandbox Code Playgroud)
如果Fortran的准确性很糟糕,Fortran的速度和并行化的便利性有什么用呢?让我想起三种做事方式:
正确的方式
错误的方法
最大功率方式
"这不是错误的方式吗?"
"是的!但更快!"
除了开玩笑,我一定是做错了.
与其他语言相比,Fortran对数值准确性有固有的限制,还是我(很可能)是错误的?
我的编译器是gfortran(gcc版本4.1.2),Perl v5.12.1,在双核AMD Opteron @ 1 GHZ上.
yst*_*sth 15
您的作业意外地将值转换为单精度,然后再转换为双精度.
请尝试将0.1 *BE 0.1D0 *,你应该看到您的问题解决.
正如已经回答的那样,Fortran中的"普通"浮点常量将默认为默认的实数类型,这可能是单精度的.这是一个几乎经典的错误.
另外,使用"kind = 8"是不可移植的 - 它会给你带gfortran的双精度,但不能与其他编译器一起使用.在Fortran> = 90中为变量和常量指定精度的安全,可移植的方法是使用内部函数,并请求您需要的精度.然后在精度很重要的常量上指定"种类".一种方便的方法是定义自己的符号.例如:
integer, parameter :: DR_K = selected_real_kind (14)
REAL(DR_K), PARAMETER :: MACH_2_METERS_PER_SEC = 340.0_DR_K
real (DR_K) :: mass, velocity, energy
energy = 0.5_DR_K * mass * velocity**2
Run Code Online (Sandbox Code Playgroud)
这对于整数也很重要,例如,如果需要大的值.有关整数的相关问题,请参阅Fortran:整数*4与整数(4)与整数(kind = 4)和Fortran中的长整数
| 归档时间: |
|
| 查看次数: |
2112 次 |
| 最近记录: |