2

我在 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)

你能告诉我为什么,我该如何解决?

4

5 回答 5

5

我看到代码有两个问题。第一个是我认为是错误原因的那个。该函数ran3以常量0作为实际参数引用,但相应的虚拟参数iseed用于函数中赋值语句的左侧。这是一个错误:您不能更改零的值。

第二个错误是 ran3 返回 a real*8(不管它是什么;它是一个非标准声明),但在主程序ran3中被声明为 default real

以下程序和函数使用 gfortran 4.7.2 编译。

程序苏
    隐式无
    真实的::ran3

    写(*,*)运行3(0)
结束程序 su

函数ran3(iseed)
    隐式无
    整数:: iseed, temp
    真实的::ran3

    温度 = iseed * 153941 + 1
    ran3 = 温度 * 2.328 + 0.5
结束函数ran3
于 2013-05-09T11:18:13.267 回答
2

尽管上面提出了许多优点,但上面的大多数解决方案都违背了该功能的直接目的。值得注意的是,在许多情况下,随机数生成器还需要返回 iSeed 的“新”值(尽管 OP 的帖子没有明确说明),因为通常在下一次调用 Ran s/r 时,“新”值需要 iSeed。

作为基本规则,常量应仅作为 Args 传递给 Intent(In) 虚拟对象。

从某种意义上说,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() 的调用/使用可以是迭代的,例如通过循环或 Elemental 等,以创建(准)随机序列。

使用外部等还有其他可能性,但那是另一天。

于 2015-10-28T20:32:31.897 回答
1

您的代码没有告诉编译器声明

real ran3

指您稍后在源文件中定义的函数。您已经向编译器声明了一个名为ran3. 一旦编译器读取了end程序末尾的语句,它就可以在它想要的时候溜走并喝 mojitos,它不必再进行任何编译——尽管您可能会发现某些编译器会这样做。

构造 Fortran 程序的一般规则是,编译器必须先遇到实体的定义(变量、函数、子例程、派生类型、what-have-you),然后才能使用它。您的代码违反了此规则。

一旦代码声明了一个真正的变量,它就会在这个语句中尝试,

write(*,*) ran3(0)

访问调用的数组的第 0 个元素,ran3这一切都以眼泪结束。

快速解决方法是移动end program su到源文件的末尾,并contains在函数定义之前放置一个包含关键字的行。然后您可以删除该声明real ran3,因为编译器将处理任何需要完成的链接。

哦,在我写作的时候,你可以自己做,以及那些试图理解你的代码的人,通过更加注意格式化你发布的内容来帮个忙。就个人而言(有意见,如果你很容易不高兴,现在就移开视线)我会解雇任何提交看起来像这样的代码的程序员,因为任何对小东西不太关注的人可能不会太在意大的东西。

于 2013-05-09T08:50:03.687 回答
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
于 2013-05-10T08:56:41.823 回答
1

首先,您必须定义idum为整数。

  program su
  implicit none
  integer idum
  real ran3
  idum = 334
  write(*,*) ran3(idum)
  end program su

那么您的代码将起作用

于 2016-07-29T02:52:15.980 回答