简体   繁体   English

Fortran浮点数相等

[英]Fortran floating point equality

I have a Fortran program that tests equality in two floating point numbers. 我有一个Fortran程序,用于测试两个浮点数的相等性。 It can be condensed to what is shown below. 可以将其浓缩为如下所示。 When this program is run with "0.1" given as a command line argument, I expect it to print "what I expected" but instead it prints "strange". 当使用命令行参数“ 0.1”运行该程序时,我希望它显示“期望值”,但会显示“奇怪”。 I understand that this is probably due to a floating point rounding issue, but am hoping someone might be able to explain exactly how I should change inputvariable to make this code print "what I expected" with a command line argument of 0.1 我知道这可能是由于浮点舍入问题引起的,但是我希望有人可以确切解释我应该如何更改inputvariable以使此代码使用0.1的命令行参数“按预期输出”

program equalitytest
  character(len=3) :: arg1
  real*8           :: inputvariable
  CALL GET_COMMAND_ARGUMENT(1,arg1)
  READ(arg1,*) inputvariable
  IF (inputvariable.EQ.0.1) THEN
    PRINT*, "what I expected"
  ELSE
    PRINT*, "strange"
  ENDIF
end program equalitytest

Run as follows: 运行如下:

./equalitytest 0.1
strange

As a general point, there should be very few reasons why one should need to compare equality with real numbers. 一般而言,应该将相等与实数进行比较的理由很少。 If I ever find myself writing such code, I tend to pause and have a think about what I am trying to achieve. 如果我发现自己正在编写这样的代码,我会停下来思考一下我要实现的目标。 What real-world condition is actually a reflection of this? 实际情况实际上反映了什么?

The exception to the above relate to zeros, either when writing robust code which checks for and handles possible divisions by zero, or for cases searching for a convergent solution to an equation - in the latter case, this should be considered using a delta anyway. 上面的例外情况涉及零,在编写健壮的代码来检查并处理可能的除以零时,或者在寻找方程的收敛解的情况下,零都是例外-在后一种情况下,无论如何都应考虑使用增量。

If there really is a need for this check, why not outsource it to a standard library within the project, eg 如果确实需要进行此检查,为什么不将其外包给项目中的标准库,例如

module mylib
    use iso_fortran_env

    implicit none
    private

    public :: isReal4EqualReal4
    public :: isReal4EqualReal8
    public :: isReal8EqualReal4
    public :: isReal8EqualReal8

    real(real32), parameter :: delta4 = 0.001
    real(real64), parameter :: delta8 = 0.0000000001

    contains

        logical function isReal4EqualReal4(lhs, rhs) result(equal)
            real(real32), intent(in) :: lhs
            real(real32), intent(in) :: rhs
            equal = (abs(lhs - rhs) .le. delta4)
        end function isReal4EqualReal4

        logical function isReal4EqualReal8(lhs, rhs) result(equal)
            real(real32), intent(in) :: lhs
            real(real64), intent(in) :: rhs
            equal = (abs(lhs - real(rhs,4)) .le. delta4)
        end function isReal4EqualReal8

        logical function isReal8EqualReal4(lhs, rhs) result(equal)
            real(real64), intent(in) :: lhs
            real(real32), intent(in) :: rhs
            equal = isReal4EqualReal8(rhs, lhs)
        end function isReal8EqualReal4

        logical function isReal8EqualReal8(lhs, rhs) result(equal)
            real(real64), intent(in) :: lhs
            real(real64), intent(in) :: rhs
            equal = (dabs(lhs - rhs) .le. delta8)
        end function isReal8EqualReal8

end module mylib

EDIT: Forgot to add that one of the benefits of the above is the compiler will warn me if I'm attempting to compare two real numbers of different types while using the wrong interface 编辑:忘记添加以上的好处之一是,如果我尝试使用错误的接口比较两个不同类型的实数时,编译器会警告我

EDIT: Updated to use portable real number definitions. 编辑:更新为使用可移植的实数定义。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM