为什么 Fortran 代码会出现分段错误?



下面的 fortran 代码会出现分段错误。 但是,当我将print*,pow(10_8,i)修改为print*,pow(j,i)时,它可以工作而不会呕吐分割错误。为什么?这很奇怪。

module mdl
implicit none
integer(kind=8)::n,m=1000000007
integer(kind=8)::p(1000),k(1000),div(10000000)
contains
integer(kind=8) function pow(a,pwr)
implicit none
integer(kind=8)::a,pwr
integer(kind=8)::cur
cur=pwr
pow=1
do while(cur>0)
if(mod(cur,2)==1)pow=mod(pow*a,m)
a=MOD(a*a,m)
cur=cur/2
end do
end function
end module

program main
use mdl
implicit none
integer(kind=8)::i,j,l,r,x,y
i=2
j=10
print*,pow(10_8,i)
print*,i
end program

这里的问题在于函数pow的参数a。 在函数中,参数a(可能)在行上被修改

a=MOD(a*a,m)

引用函数时10_8的实际参数是一个文字常量,不能修改。 这是程序失败的时候。 当您使用print*,pow(j,i)时,j是一个可以修改的变量,并且您的程序不会失败。

这里有很多复杂的事情,我不会在这个答案中完全解释(你可以搜索其他问题)。 一个主题是参数关联,它解释了为什么您尝试修改常量10_8。 但是,我会说一些关于虚拟论证意图的事情。

虚拟参数a没有指定意图。 当您打算在a进入函数时使用它的值,并且您希望(可能)修改它,因此intent(inout)适当的意图。 如果应用此功能,则应发现编译器对该赋值行的抱怨。

没有意图,例如在问题的情况下,是可以接受的事情。 这是有一定意义的。 也就是说,是否可以修改a取决于引用函数时的实际参数是否可以修改。 当实际参数10_8时,它可能不会;当它j时,它可能会。

关键是,检查程序是否在这里做了不应该做的事情不是编译器的责任,而是你的责任。

现在,您可能不想修改实际参数j即使允许您这样做。 您有以下几种选择:

  • 您可以制作一个临时的本地副本(并将a标记为intent(in)),可以安全地修改;
  • 您可以使用value属性创建输入数据的匿名可修改副本。

您首先使用cur=pwr执行此操作。 作为第二个示例:

integer(kind=bigint) function pow(a,pwr)
implicit none
integer(kind=bigint), value :: a, pwr
pow=1
do while(cur>0)
if(mod(pwr,2)==1)pow=mod(pow*a,m)
a=MOD(a*a,m)
pwr=pwr/2
end do
end function

您现在甚至可以将pow标记为纯函数。

最后,如果使用value属性,则在引用函数时需要显式接口可用。 对于函数的模块,这里就是这种情况,但在更一般的情况下需要考虑这一点。

相关内容

  • 没有找到相关文章

最新更新