下面的 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
属性,则在引用函数时需要显式接口可用。 对于函数的模块,这里就是这种情况,但在更一般的情况下需要考虑这一点。