爱气象,爱气象家园! 

气象家园

 找回密码
 立即注册

QQ登录

只需一步,快速开始

新浪微博登陆

只需一步, 快速开始

搜索
查看: 4102|回复: 7

[求助] 去掉感叹号为何结果不同?——求助子程序变量作用域的问题

[复制链接]

新浪微博达人勋

发表于 2013-10-24 20:56:37 | 显示全部楼层 |阅读模式

登录后查看更多精彩内容~

您需要 登录 才可以下载或查看,没有帐号?立即注册 新浪微博登陆

x
在fortran中子程序有一个初始化定义的值integer::i=1为何它只在第一次调用的时候才赋这个值,以后再调用这个子函数时 i 不从1开始重新定义呢?
fortran书上第209页不是有说“子程序中变量的生存期仅局限在该子程序被调用期间,在下次进入子程序时,重新给这些变量分配新的存储单元”吗?
请问哪位大侠能告诉我我哪里理解错了?
举个例子:为何以下的程序把子程序中的感叹号去掉,结果会不一样?明明在定义的时候已经赋初值了啊?
myf2.dat的数据是这样的:
0.85,    6.75
1.62,    7.88
3.27,    4.44
4.44,    7.89
5.28,    9.87
6.11,    8.46
7.80,    21.50

myf2.f90的程序是这样的:
program main
implicit none
!external f
real c,x,z,f
integer i
open(1,file='myf2.dat')
open(2,file='myf2.out')
rewind (1)
rewind (2)
do i=1,7
   read(1,*)x,c
   z=f(x,c)
   write(2,'(2f6.2,f9.5)')x,c,z
end do
end program main
function f(x,c) result(g)
implicit none
integer ::n=1
real ::x,c,g,pi=3.1415926,eps=1e-10,temp !temp记录级数通项
     !      n=1
temp=cos((2*n-1)*pi*x/c)/(2*n-1)**2
g=temp
do while(abs(temp)>=eps)
      n=n+1
   temp=cos((2*n-1)*pi*x/c)/(2*n-1)**2
   g=g+temp
end do
g=sqrt((c*pi**2)/(2*x)-4*c/x*g)
end function f
密码修改失败请联系微信:mofangbao

新浪微博达人勋

0
早起挑战累计收入
发表于 2013-10-25 08:14:59 | 显示全部楼层
楼主你是说变量n吗?楼主描述的再清楚一些吧,你想象中应该是什么样的结果,现实是什么结果
fortran中的external是函数参数化的声明,这样就可以把函数当做参数传递
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2013-10-28 22:56:05 | 显示全部楼层

我自己也测试了一下,貌似真的出现了楼主的说的这种问题。为了方便计算,我将楼主的代码改了稍微改了一下,数据也换了。
myf2.txt的数据为:
1    3
2    5
3    7
4    9
5    11
6    13
7    15

程序为:
  1. program main
  2. implicit none
  3. !external f
  4. integer c,x,z,f
  5. integer i
  6. open(11,file='myf2.txt')
  7. open(21,file='myf2.out')
  8. rewind (11)
  9. rewind (21)
  10. do i=1,7
  11.    read(11,*)x,c
  12.    z=f(x,c)
  13.    write(21,*)x,c,z
  14.    write(*,*)x,c,z
  15. end do
  16. end program main

  17. function f(x,c)
  18. implicit none
  19. integer ::n=1
  20. integer ::x,c,f
  21. !      n=1
  22. f=x*n+c*2*n

  23. do while(f<=100)
  24.    n=n+1
  25.    f=x*n+c*2*n
  26.    print*,n,f
  27. end do
  28. end function f
复制代码
如果注释掉子函数中的n=1时,屏幕上的结果是:

  1.           2          14
  2.           3          21
  3.           4          28
  4.           5          35
  5.           6          42
  6.           7          49
  7.           8          56
  8.           9          63
  9.          10          70
  10.          11          77
  11.          12          84
  12.          13          91
  13.          14          98
  14.          15         105
  15.           1           3         105
  16.           2           5         180
  17.           3           7         255
  18.           4           9         330
  19.           5          11         405
  20.           6          13         480
  21.           7          15         555
复制代码
但是不注释n=1时,屏幕上得到的结果是:

  1.            2          14
  2.            3          21
  3.            4          28
  4.            5          35
  5.            6          42
  6.            7          49
  7.            8          56
  8.            9          63
  9.           10          70
  10.           11          77
  11.           12          84
  12.           13          91
  13.           14          98
  14.           15         105
  15.            1           3         105
  16.            2          24
  17.            3          36
  18.            4          48
  19.            5          60
  20.            6          72
  21.            7          84
  22.            8          96
  23.            9         108
  24.            2           5         108
  25.            2          34
  26.            3          51
  27.            4          68
  28.            5          85
  29.            6         102
  30.            3           7         102
  31.            2          44
  32.            3          66
  33.            4          88
  34.            5         110
  35.            4           9         110
  36.            2          54
  37.            3          81
  38.            4         108
  39.            5          11         108
  40.            2          64
  41.            3          96
  42.            4         128
  43.            6          13         128
  44.            2          74
  45.            3         111
  46.            7          15         111
复制代码
可以看到两个结果是截然不同的。第一个结果中显然在第一次循环以后(即i=2,3,4,5,6,7)是记住了第一次循环结束时n=15的值,并在第一次循环之后被程序记住了(子程序中声明中integer n=1,显然在第一次循环后是失效的),这与fortran书中所说的“子程序中变量的生存期仅局限在该子程序被调用期间,在下次进入子程序时,重新给这些变量分配新的存储单元”不一致。

不知道我这样说明是不是楼主想表达的意思。关于这一点我也不明白,所以希望高手解答。我自己也去看看书,看看究竟是怎么回事。

密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2013-10-28 22:58:27 | 显示全部楼层
楼主,不知道你是否已经知道了原因。如果知晓,求解释。
密码修改失败请联系微信:mofangbao

新浪微博达人勋

0
早起挑战累计收入
发表于 2013-10-28 23:20:14 | 显示全部楼层
冬日情愫+ 发表于 2013-10-28 22:56
我自己也测试了一下,貌似真的出现了楼主的说的这种问题。为了方便计算,我将楼主的代码改了稍微改了一下 ...

仔细看这段话应该就能明白了,是编译器的原因~
1.png
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2013-10-29 09:15:44 | 显示全部楼层
mofangbao 发表于 2013-10-28 23:20
仔细看这段话应该就能明白了,是编译器的原因~

谢谢。
也就是说如果我要想每次进入子函数的时候都要求n=1,就不能使用在声明的时候就赋值了(integer::n=1),必须在声明之后单独赋值了是吗?
密码修改失败请联系微信:mofangbao

新浪微博达人勋

0
早起挑战累计收入
发表于 2013-10-29 09:25:03 | 显示全部楼层
冬日情愫+ 发表于 2013-10-29 09:15
谢谢。
也就是说如果我要想每次进入子函数的时候都要求n=1,就不能使用在声明的时候就赋值了(integer:: ...

那你的需求 有这个需求的话就是的  那段话的意思就是你处理的时候要认为值一直是连续的,如果你想让他连续,就加save关键字,更保险,不想让他连续,就要自己再做另外的处理
密码修改失败请联系微信:mofangbao

新浪微博达人勋

发表于 2013-10-29 09:29:52 | 显示全部楼层
mofangbao 发表于 2013-10-29 09:25
那你的需求 有这个需求的话就是的  那段话的意思就是你处理的时候要认为值一直是连续的,如果你想让他连续 ...

谢谢。
密码修改失败请联系微信:mofangbao
您需要登录后才可以回帖 登录 | 立即注册 新浪微博登陆

本版积分规则

Copyright ©2011-2014 bbs.06climate.com All Rights Reserved.  Powered by Discuz! (京ICP-10201084)

本站信息均由会员发表,不代表气象家园立场,禁止在本站发表与国家法律相抵触言论

快速回复 返回顶部 返回列表