Fortran中的数据类型不匹配 [英] Data type mismatch in fortran

查看:358
本文介绍了Fortran中的数据类型不匹配的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Fortran 95中编写了一个基本的算法,用中心差分(Richardson外推法)来计算函数的梯度(在代码中规定了一个例子)。

 函数f(n,x)
!标量多变量函数被区分

integer :: n
real(kind = kind(1d0)):: x(n),f

f = x (1)** 5.d0 + cos(x(2))+ log(x(3)) - sqrt(x(4))

结束函数f
!== ===!
!=====!
!=====!

程序渐变
!=================================== ===========================================!
!用x = 0计算标量函数f的梯度,使用有限!
!差分近似,具有低阶理查森外推。 !
!============================================= =================================!

参数(n = 4,M = 25)
real(kind = kind(1d0)):: x(n),xhup(n),xhdown(n),d M),r(M),dfdxi,h0,h,gradf(n)

h0 = 1.d0
x = 3.d0

!循环遍历向量x的每个分量并计算适当的
!衍生工具
do i = 1,n
!重置步长
h = h0

!进行M个连续的中心差分近似的导数
do j = 1,M
xhup = x
xhdown = x
xhup(i)= xhup(i)+ h
xhdown(i)= xhdown(i)-h
d(j)=(f(n,xhup) - f(n,xhdown))/(2.d0 * h)
h = h / 2.d0
end do

r = 0.d0
do k = 3,M r(k)=(64.d0 * d(k) - 20。如果(abs(r(k)-r(k-1))<0.0001d0),那么
(d0 * d(k-1)+ d dfdxi = r(k)
出口
结束如果
结束

gradf(i)= dfdxi
结束

!打印出渐变
write(*,*)
write(*,*)Grad(f(x))=
write(*,*)$ b (*,*)gradf(i)
end do

结束程序渐变

单精度运行正常,并给我很好的结果。但是,当我试图改变到双精度代码中显示,当我试图编译声明赋值语句时出现错误

  d(j)=(f(n,xhup) -  f(n,xhdown))/(2.d0 * h)

产生一个类型不匹配 real(4)/ real(8)。我已经尝试了几个不同的双精度声明,并在代码中添加了每个适当的双精度常量( d0 ),每次都得到同样的错误。我有点难以理解函数 f 是否可能产生一个精确数字。

方案

问题是f在你的主程序中没有明确的定义,所以它被隐含地假定为单精度,这是gfortran的真实类型(4)。
$ b

我完全同意High Performance Mark的评论,你真的应该在你所有的fortran代码中使用 implicit none 来确保所有的对象被明确地声明。这样,你就可以得到一个关于f没有明确定义的更合适的错误信息。

另外,你可以考虑另外两件事:


  • 在模块中定义你的函数,并在主程序中导入这个模块。在模块中定义所有的子程序/函数是一个很好的习惯,所以当你调用函数时,编译器可以对参数的数量和类型进行额外的检查。


  • <你可以(再次在模块中)引入一个用于精确化的常量,并在任何地方使用它,必须指定真实类型。以下面的例子来说,只改变行:

      integer,参数:: dp = kind(1.0d0)

    转换为

      integer,parameter :: dp = kind(1.0)

    您可以将所有实际变量从double单精度。还要注意字面常量的 _dp 后缀,而不是 d0 后缀,后缀会自动调整它们的精度。

     模块准确性
    隐式无

    整数,参数:: dp = kind(1.0 d0)

    结束模块准确性


    模块myfunc
    使用准确性
    隐式无

    包含

    函数f(n,x)
    整数:: n
    实数(dp):: x(n),f
    f = 0.5_dp * x(1)* * 5 + cos(x(2))+ log(x(3)) - sqrt(x(4))
    结束函数f

    结束模块myfunc


    程序渐变
    使用myfunc
    隐式无

    真(dp):: x(n),xhup(n),xhdown(n),d (M),r(M),dfdxi,h0,h,gradf(n)


    结束程序渐变



I've written a rudimentary algorithm in Fortran 95 to calculate the gradient of a function (an example of which is prescribed in the code) using central differences augmented with a procedure known as Richardson extrapolation.

function f(n,x)
! The scalar multivariable function to be differentiated

integer :: n
real(kind = kind(1d0)) :: x(n), f

f = x(1)**5.d0 + cos(x(2)) + log(x(3)) - sqrt(x(4))

end function f
!=====!
!=====!
!=====!

program gradient
!==============================================================================!
! Calculates the gradient of the scalar function f at x=0using a finite        !
! difference approximation, with a low order Richardson extrapolation.         !
!==============================================================================!

parameter (n = 4, M = 25)
real(kind = kind(1d0)) :: x(n), xhup(n), xhdown(n), d(M), r(M), dfdxi, h0, h, gradf(n)

h0 = 1.d0
x  = 3.d0

! Loop through each component of the vector x and calculate the appropriate
! derivative
do i = 1,n
! Reset step size
h = h0

    ! Carry out M successive central difference approximations of the derivative
do j = 1,M
        xhup = x
        xhdown = x
        xhup(i) = xhup(i) + h
        xhdown(i) = xhdown(i) - h
        d(j) = ( f(n,xhup) - f(n,xhdown) ) / (2.d0*h)
    h = h / 2.d0
    end do

    r = 0.d0
    do k = 3,M      r(k) = ( 64.d0*d(k) - 20.d0*d(k-1) + d(k-2) ) / 45.d0
        if ( abs(r(k) - r(k-1)) < 0.0001d0 ) then
        dfdxi = r(k)
            exit
        end if
    end do

    gradf(i) = dfdxi
end do

! Print out the gradient
write(*,*) " "
write(*,*) " Grad(f(x)) = "
write(*,*) " "
do i = 1,n
    write(*,*) gradf(i)
end do

end program gradient

In single precision it runs fine and gives me decent results. But when I try to change to double precision as shown in the code, I get an error when trying to compile claiming that the assignment statement

d(j) = ( f(n,xhup) - f(n,xhdown) ) / (2.d0*h)

is producing a type mismatch real(4)/real(8). I have tried several different declarations of double precision, appended every appropriate double precision constant in the code with d0, and I get the same error every time. I'm a little stumped as to how the function f is possibly producing a single precision number.

解决方案

The problem is that f is not explicitely defined in your main program, therefore it is implicitly assumed to be of single precision, which is the type real(4) for gfortran.

I completely agree to the comment of High Performance Mark, that you really should use implicit none in all your fortran code, to make sure all object are explicitely declared. This way, you would have obtained a more appropriate error message about f not being explicitely defined.

Also, you could consider two more things:

  • Define your function within a module and import that module in the main program. It is a good practice to define all subroutines/functions within modules only, so that the compiler can make extra checks on number and type of the arguments, when you invoke the function.

  • You could (again in module) introduce a constant for the precicision and use it everywhere, where the kind of a real must be specified. Taking the example below, by changing only the line

    integer, parameter :: dp = kind(1.0d0)
    

    into

    integer, parameter :: dp = kind(1.0)
    

    you would change all your real variables from double to single precision. Also note the _dp suffix for the literal constants instead of the d0 suffix, which would automatically adjust their precision as well.

    module accuracy
      implicit none
    
      integer, parameter :: dp = kind(1.0d0)
    
    end module accuracy
    
    
    module myfunc
      use accuracy
      implicit none
    
    contains
    
      function f(n,x)
        integer :: n
        real(dp) :: x(n), f
        f = 0.5_dp * x(1)**5 + cos(x(2)) + log(x(3)) - sqrt(x(4))
      end function f
    
    end module myfunc
    
    
    program gradient
      use myfunc
      implicit none
    
      real(dp) :: x(n), xhup(n), xhdown(n), d(M), r(M), dfdxi, h0, h, gradf(n)
      :
    
    end program gradient
    

这篇关于Fortran中的数据类型不匹配的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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