下面的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
答案 0 :(得分:3)
这里的问题是函数a
的参数pow
。在函数中,参数a
(可能)在行
a=MOD(a*a,m)
引用函数时的实际参数10_8
是一个不能修改的文字常量。这是你的程序失败的时候。当您使用print*,pow(j,i)
时,j
是一个可以修改 的变量,而您的程序也不会失败。
这里有很多复杂的东西,我在这个答案中没有完全解释(你可以搜索其他问题)。一个主题是参数关联,它解释了为什么要尝试修改常量10_8
。但是,我会对dummy argument intents说些什么。
伪参数a
没有指定意图。当您打算在进入函数时使用a
的值并且您希望(可能)修改它时,适当的意图将是intent(inout)
。如果你应用它,你会发现你的编译器抱怨该分配线。
没有意图,例如在问题的情况下,是一种可以接受的东西。这有certain meaning。也就是说,是否可以修改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
属性,则在引用该函数时需要显式接口可用。使用该功能的模块就是这种情况,但在更一般的情况下需要考虑这一点。