我在Fortran中编写了这个非常简单的代码:
program su
implicit none
real ran3
write(*,*) ran3(0)
end program su
real*8 function ran3(iseed)
implicit none
integer iseed
iseed=iseed*153941+1
ran3=float(iseed)*2.328+0.5
end function ran3
我编译它没有问题,但是当我执行代码时,我收到了这条消息:
Program received signal SIGSEGV: Segmentation fault - invalid memory reference.
Backtrace for this error:
#0 0xB76BAC8B
#1 0xB76BB2DC
#2 0xB77BA3FF
#3 0x8048653 in ran3_
#4 0x80486B3 in MAIN__ at der.f90:?
Segmentation fault (core dumped)
你能告诉我为什么,以及如何解决它?
答案 0 :(得分:5)
我发现代码存在两个问题。第一个是我认为是错误原因的那个。函数ran3
以常量0
作为实际参数引用,但相应的伪参数iseed
在函数的赋值语句的左侧使用。这是一个错误:您无法更改零值。
第二个错误是ran3返回real*8
(无论可能是什么;它是非标准声明),但在主程序ran3
中声明为默认real
}。
以下程序和函数使用gfortran 4.7.2进行编译。
program su implicit none real :: ran3 write(*, *) ran3(0) end program su function ran3(iseed) implicit none integer :: iseed, temp real :: ran3 temp = iseed * 153941 + 1 ran3 = temp * 2.328 + 0.5 end function ran3
答案 1 :(得分:2)
虽然上面提出了很多好处,但上述大多数解决方案都无法实现该功能的直接目的。值得注意的是,随机数生成器在许多情况下也需要返回iSeed的“新”值(虽然OP的帖子没有明确说明),因为通常在下一次调用Ran s / r时,“new”值为iSeed是必需的。
作为一项基本规则,常量应仅作为Args传递给Intent(In)dummy。
从某种意义上说,OP获得segv是“幸运的”,因为在(糟糕的)过去,可以将“数字”“0”发送为“0”,但返回“0”在其他任何地方都会包含iSeed和没有segv的值,但是有很多不好的算法。
在这种特殊情况下,更合适的解决方案是不要传递常数,而是:
program su
implicit none
Integer :: iSeed
!
iSeed = 0 ! or whatever iSeed is requried
!
write(*, *) ran3(iSeed)
contains
function ran3(iseed)
implicit none
real :: ran3
integer, intent(InOut) :: iSeed
iseed = iseed*153941+1
ran3 = float(iseed)*2.328+0.5
end function ran3
end program su
现在,Ran3()的调用/使用可以是迭代的,例如通过循环或元素等来创建(准)随机序列。
还有其他可能使用外部等,但这是另一天。
答案 2 :(得分:1)
您的代码没有告诉编译器声明
real ran3
指的是您稍后在源文件中定义的函数。对于编译器,您已声明了一个名为ran3
的实数变量。一旦编译器在程序结束时读取了end
语句,它就可以根据需要进行操作,并且不需要再进行任何编译 - 尽管您可能会发现某些编译器会这样做。
构造Fortran程序的一般规则是编译器在遇到任何实体之前必须遇到实体的定义(变量,函数,子例程,派生类型,有什么用)。你的代码违反了这条规则。
一旦代码声明了一个真正的变量,它就会在这个语句中尝试
write(*,*) ran3(0)
访问名为ran3
的数组的第0个元素,这一切都以泪水结束。
快速解决方法是将end program su
移动到源文件的末尾,并在函数定义之前放置包含关键字contains
的行。然后,您可以删除声明real ran3
,因为编译器将处理需要完成的任何链接。
哦,在我写作的时候,你可以做自己,那些试图理解你的代码的人,通过更加注意格式化你发布的内容来帮助你。个人(意见即将到来,如果你很容易不高兴的话,现在就把目光移开)我会解雇那些把代码看起来像这样的程序员,理由是那些对这些小东西很少关注的人可能并不太关注也很重要。
答案 3 :(得分:1)
如果您因任何原因想要通过该功能修改iseed
,则应使用intent(in out)
进行标记。如果这样做,编译器将在编译时使用文字常量调用函数时触发错误。如果您想将参数作为输入使用,则可以将其标记为intent(in)
,并且由于您在函数内部分配了iseed,因此会再次出现错误。
我认为养成宣布意图的习惯是个好主意。
您的代码可能看起来像
program su
implicit none
write(*, *) ran3(0)
contains
function ran3(iseed)
implicit none
real :: ran3
integer, intent(in) :: iseed
! or intent(in out) :: iseed
iseed = iseed*153941+1
ran3 = float(iseed)*2.328+0.5
end function ran3
end program su
(无论你是否使用“in”或“in out”作为意图,这都不会编译,因为早期解释了这一点。)
以下代码将编译(也应该有效)
program su
implicit none
write(*, *) ran3(0)
contains
function ran3(iseed)
implicit none
real :: ran3
integer, intent(in) :: iseed
ran3 = real(iseed*153941+1)*2.328+0.5
end function ran3
end program su
答案 4 :(得分:1)
首先,您必须将idum
定义为整数。
program su
implicit none
integer idum
real ran3
idum = 334
write(*,*) ran3(idum)
end program su
那么你的代码就可以了