与其他语言相比,Fortran是否对数值精度有固有限制? [英] Does Fortran have inherent limitations on numerical accuracy compared to other languages?

查看:204
本文介绍了与其他语言相比,Fortran是否对数值精度有固有限制?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在进行简单的编程练习时,我创建了一个while循环(Fortran中的DO循环),当真实变量达到精确值时,它将退出。



<我注意到,由于使用了精度,平等从未被满足,循环变得无限。这当然不是闻所未闻,有人建议说,不要比较两个数字的平等性,最好看看两个数字之间的绝对差值是否小于设定的阈值。

我发现令人失望的是我必须设置这个阈值,即使对于双精度的变量,我的循环能够正确退出的程度也很低。此外,当我在Perl中重写了这个循环的蒸馏版本时,我没有数值准确性的问题,并且循环退出正常。



由于生成问题是如此之小,在Perl和Fortran中,我希望在这里重现它,以防止我忽略了一个重要细节:

Fortran代码

  PROGRAM precision_test 
IMPLICIT NONE

!数据字典
INTEGER :: count = 0!迭代次数
REAL(KIND = 8):: velocity
REAL(KIND = 8),PARAMETER :: MACH_2_METERS_PER_SEC = 340.0

velocity = 0.5 * MACH_2_METERS_PER_SEC !初始速度
DO
WRITE(*,300)速度
300 FORMAT(F20.8)
IF(count == 50)EXIT
IF(速度== 5.0 * MACH_2_METERS_PER_SEC)退出
! 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

结束程序precision_test

Perl代码

 #! / usr / bin / perl -w 
使用strict;

my $ mach_2_meters_per_sec = 340.0;

my $ velocity = 0.5 * $ mach_2_meters_per_sec;

while(1){
printf%20.8f\\\
,$ 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






  1. 正确的方法


  2. 错误的方式


  3. 最大功率方式


  4. b

    这不正是错误的方式吗?



    是的,但速度更快!



    所有开玩笑的人,我一定在做错事。



    Fortran与其他语言相比,在数值精度上有固有限制吗?我的编译器是gfortran(gcc版本4.1.2),Perl v5.12.1,在双核AMD Opteron @ 1 GHZ上。

    / p>

    解决方案

    您的任务意外地将该值转换为单精度,然后返回到double。



    尽量让你的 0.1 * 0.1D0 * ,你应该看到你的问题得到解决。 p>

    While working on a simple programming exercise, I produced a while loop (DO loop in Fortran) that was meant to exit when a real variable had reached a precise value.

    I noticed that due to the precision being used, the equality was never met and the loop became infinite. This is, of course, not unheard of and one is advised that, rather than comparing two numbers for equality, it is best see if the absolute difference between two numbers is less than a set threshold.

    What I found disappointing was how low I had to set this threshold, even with variables at double precision, for my loop to exit properly. Furthermore, when I rewrote a "distilled" version of this loop in Perl, I had no problems with numerical accuracy and the loop exited fine.

    Since the code to produce the problem is so small, in both Perl and Fortran, I'd like to reproduce it here in case I am glossing over an important detail:

    Fortran Code

    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 Code

    #! /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;
    }
    

    The commented-out line in Fortran is what I would need to use for the loop to exit normally. Notice that the threshold is set to 1E-4, which I feel is quite pathetic.

    The names of the variables come from the self-study-based programming exercise I was performing and don't have any relevance.

    The intent is that the loop stops when the velocity variable reaches 1700.

    Here are the truncated outputs:

    Perl Output

        170.00000000
        204.00000000
        238.00000000
        272.00000000
        306.00000000
        340.00000000
    

    ...

       1564.00000000
       1598.00000000
       1632.00000000
       1666.00000000
       1700.00000000
    

    Fortran Output

        170.00000000
        204.00000051
        238.00000101
        272.00000152
        306.00000203
        340.00000253
    

    ...

       1564.00002077
       1598.00002128
       1632.00002179
       1666.00002229
       1700.00002280
    

    What good is Fortran's speed and ease of parallelization if its accuracy stinks? Reminds me of the three ways to do things:

    1. The Right Way

    2. The Wrong Way

    3. The Max Power Way

    "Isn't that just the wrong way?"

    "Yeah! But faster!"

    All kidding aside, I must be doing something wrong.

    Does Fortran have inherent limitations on numerical accuracy compared to other languages, or am I (quite likely) the one at fault?

    My compiler is gfortran (gcc version 4.1.2), Perl v5.12.1, on a Dual Core AMD Opteron @ 1 GHZ.

    解决方案

    Your assignment is accidentally converting the value to single precision and then back to double.

    Try making your 0.1 * be 0.1D0 * and you should see your problem fixed.

    这篇关于与其他语言相比,Fortran是否对数值精度有固有限制?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆