主题:[讨论]语句函数对数组赋值出现的一个很奇怪的问题
299792458
[专家分:60] 发布于 2010-09-25 14:15:00
程序:
PROGRAM assign_inlinefun2mat
!
implicit none
!
real,dimension(3) :: m = (/0.2,0.4,0.6/),v
real :: r
integer :: i
!
!线性内插
real :: a0,a1,position,interp
interp(a0,a1,position) = a0*(1.0-position)+a1*position
!
!直接赋值
v = 0.0
print*,'----part1----'
do i = 1,3
print*,'----start----'
print*,'v=',v
print*,'interp(0,1,m(i))=',interp(0,1,m(i))
v = interp(0,1,m(i))
print*,'----assign----'
print*,'v=',v
print*,'interp(0,1,m(i))=',interp(0,1,m(i))
end do
!
!通过变量间接赋值
v = 0.0
print*,'----part2----'
do i = 1,3
print*,'----start----'
print*,'v=',v
print*,'interp(0,1,m(i))=',interp(0,1,m(i))
r = interp(0,1,m(i))
v=r
print*,'----assign----'
print*,'v=',v
print*,'interp(0,1,m(i))=',interp(0,1,m(i))
end do
!
END PROGRAM assign_inlinefun2mat
windows下 CVF 6.5的结果:
[color=FF0000] ----part1----
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.2000000
----assign----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.2000000
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.4000000
----assign----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.4000000
----start----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.6000000
----assign----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.6000000 [/color]
----part2----
----start----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.2000000
----assign----
v= 0.2000000 0.2000000 0.2000000
----start----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.4000000
----assign----
v= 0.4000000 0.4000000 0.4000000
----start----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.6000000
----assign----
v= 0.6000000 0.6000000 0.6000000
linux下ifort 11.0的结果:
----part1----
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.2000000
----assign----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.2000000
----start----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.4000000
----assign----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.4000000
----start----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.6000000
----assign----
v= 0.6000000 0.6000000 0.6000000
interp(0,1,m(i))= 0.6000000
----part2----
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.2000000
----assign----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.2000000
----start----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.4000000
----assign----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.4000000
----start----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.6000000
----assign----
v= 0.6000000 0.6000000 0.6000000
interp(0,1,m(i))= 0.6000000
在CVF里直接用语句函数对数组赋值,得到的实际上是上一个循环的结果(结果里红色的部分),如果先把语句函数的结果赋给一个变量,再将该变量赋给数组就没有这个问题,ifort里则不管怎么赋值都没有问题。
本来这样赋值应该算一种错误,不过这个结果实在有些诡异,冒昧的发上来,请各位高手分析下为什么会得到的是上一个循环的值。
回复列表 (共23个回复)
11 楼
yeg001 [专家分:14390] 发布于 2010-09-25 18:47:00
函数内部子函数一般在主函数后面用contains语句包含. 直接在主函数体内定义, 这个我确实没用过. 是否规范有待查证.
还有, 函数调用interp(0,1,m(i), 编译器没报错? 数据类型不对应的哦.
12 楼
299792458 [专家分:60] 发布于 2010-09-25 18:57:00
[quote]循环体内先对V清零,再赋值试试。[/quote]
结果如下,赋值之前确实清零了,赋值以后仍然是上个循环的结果
----part1----
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.2000000
----assign----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.2000000
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.4000000
----assign----
v= 0.2000000 0.2000000 0.2000000
interp(0,1,m(i))= 0.4000000
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0,1,m(i))= 0.6000000
----assign----
v= 0.4000000 0.4000000 0.4000000
interp(0,1,m(i))= 0.6000000
13 楼
299792458 [专家分:60] 发布于 2010-09-25 19:07:00
[quote]函数内部子函数一般在主函数后面用contains语句包含. 直接在主函数体内定义, 这个我确实没用过. 是否规范有待查证.
还有, 函数调用interp(0,1,m(i), 编译器没报错? 数据类型不对应的哦.[/quote]
这个跟内部子函数是两个东西,语法上应该没有问题。
后面这个两边编译器都没报错,这应该相当于实数对实数数组赋值。至于语句函数是否会将等号前面的变量直接作为输出变量带到函数里,不是很清楚,不过CVF编译选项里加上fortran 90的兼容性检查以后仍然没有任何warning或者error
14 楼
yeg001 [专家分:14390] 发布于 2010-09-25 20:05:00
我忍不住差了一下<fortran_95-2003_for_scientists_and_engineers>, 里面没有提到你这种用法, 由于不在学校而又不想看电子版的<The_Fortran_2003_Handbook__The_Complete_Syntax_Features_and_Procedures>所以可能有遗漏. 我没有在书里找到楼主你的用法, 而且觉得类型比匹配竟然没报错我感到惊讶.
先附上<fortran_95-2003_for_scientists_and_engineers> 关于INTERNAL PROCEDURES 的描述:
INTERNAL PROCEDURES
III
In Chapter 7, we learned about external procedures and module procedures. There
is also a third type of procedure-the internal procedure. An internal procedure is
a procedure that is entirely contained within another program unit, called the host
program unit, or just the host. The internal procedure is compiled together with the
host, and it can only be invoked from the host program unit. Like module procedures,
internal procedures are introduced by a CON T A INS statement. An internal procedure
must follow all of the executable statements within the host procedure, and must be
introduced by a CONTAINS statement.
我把你的代码复制过来用cvf算了一下, 情况如你所说. 即使我把原来0改为0.0, 1给成1.0也是得到那样的结果, 于是我把你的函数改成内部函数.
PROGRAM assign_inlinefun2mat
!
implicit none
!
real,dimension(3) :: m = (/0.2,0.4,0.6/),v
real :: r
integer :: i
!直接赋值
v = 0.0
print*,'----part1----'
do i = 1,3
print*,'----start----'
print*,'v=',v
print*,'interp([color=000080]0.0,1.0[/color],m(i))=',interp(([color=000080]0.0,1.0[/color],m(i))
v = interp(([color=000080]0.0,1.0[/color],m(i))
print*,'----assign----'
print*,'v=',v
print*,'interp(([color=000080]0.0,1.0[/color],m(i))=',interp(([color=000080]0.0,1.0[/color],m(i))
end do
!通过变量间接赋值
v = 0.0
print*,'----part2----'
do i = 1,3
print*,'----start----'
print*,'v=',v
print*,'interp(([color=000080]0.0,1.0[/color],m(i))=',interp(([color=000080]0.0,1.0[/color],m(i))
r = interp(([color=000080]0.0,1.0[/color],m(i))
v=r
print*,'----assign----'
print*,'v=',v
print*,'interp(([color=000080]0.0,1.0[/color],m(i))=',interp(([color=000080]0.0,1.0[/color],m(i))
end do
!
[color=FF0000]contains
function interp(a0,a1,position)!线性内插
real :: a0,a1,position,interp
interp = a0*(1.0-position)+a1*position
end function[/color]
END PROGRAM assign_inlinefun2mat
这里不用0.0和1.0会报错, 要保证类型匹配.
运行结果
----part1----
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0.0,1.0,m(i))= 0.2000000
----assign----
[color=FF0000] v= 0.2000000 0.2000000 0.2000000[/color]
interp(0.0,1.0,m(i))= 0.2000000
----start----
v= 0.2000000 0.2000000 0.2000000
interp(0.0,1.0,m(i))= 0.4000000
----assign----
v= 0.4000000 0.4000000 0.4000000
interp(0.0,1.0,m(i))= 0.4000000
----start----
v= 0.4000000 0.4000000 0.4000000
interp(0.0,1.0,m(i))= 0.6000000
----assign----
v= 0.6000000 0.6000000 0.6000000
interp(0.0,1.0,m(i))= 0.6000000
----part2----
----start----
v= 0.0000000E+00 0.0000000E+00 0.0000000E+00
interp(0.0,1.0,m(i))= 0.2000000
----assign----
v= 0.2000000 0.2000000 0.2000000
interp(0.0,1.0,m(i))= 0.2000000
----start----
v= 0.2000000 0.2000000 0.2000000
interp(0.0,1.0,m(i))= 0.4000000
----assign----
v= 0.4000000 0.4000000 0.4000000
interp(0.0,1.0,m(i))= 0.4000000
----start----
v= 0.4000000 0.4000000 0.4000000
interp(0.0,1.0,m(i))= 0.6000000
----assign----
v= 0.6000000 0.6000000 0.6000000
interp(0.0,1.0,m(i))= 0.6000000
Press any key to continue
15 楼
yeg001 [专家分:14390] 发布于 2010-09-25 20:06:00
楼主你可以提供你那种用法是在哪里看到的吗? 上面的INTERNAL PROCEDURES 在<fortran_95-2003_for_scientists_and_engineers>英文版P452
我印象中似乎也见过, 但一直没有用过这种用法, 不确定.
16 楼
asymptotic [专家分:16630] 发布于 2010-09-25 20:38:00
yeg001 网友: 楼主提供的用法确实是 Statement Function,这一点上面已经有网友说了,请参考 The Fortran 2003 Handbook P449
17 楼
299792458 [专家分:60] 发布于 2010-09-25 20:45:00
记不清最早是在哪里见到的了,CVF help里的说法
Statement Function
Statement: Defines a function in a single statement in the same program unit in which the procedure is referenced.
Syntax
fun ([d-arg [, d-arg] ...]) = expr
fun
Is the name of the statement function.
d-arg
Is a dummy argument. A dummy argument can appear only once in any list of dummy arguments, and its scope is local to the statement function.
expr
Is a scalar expression defining the computation to be performed.
Named constants and variables used in the expression must have been declared previously in the specification part of the scoping unit or made accessible by use or host association.
If the expression contains a function reference, the function must have been defined previously in the same program unit.
A statement function reference takes the following form:
fun ([a-arg [, a-arg] ...])
fun
Is the name of the statement function.
a-arg
Is an actual argument.
Rules and Behavior
When a statement function reference appears in an expression, the values of the actual arguments are associated with the dummy arguments in the statement function definition. The expression in the definition is then evaluated. The resulting value is used to complete the evaluation of the expression containing the function reference.
The data type of a statement function can be explicitly defined in a type declaration statement. If no type is specified, the type is determined by implicit typing rules in effect for the program unit.
Actual arguments must agree in number, order, and data type with their corresponding dummy arguments.
Except for the data type, declarative information associated with an entity is not associated with dummy arguments in the statement function; for example, declaring an entity to be an array or to be in a common block does not affect a dummy argument with the same name.
The name of the statement function cannot be the same as the name of any other entity within the same program unit.
Any reference to a statement function must appear in the same program unit as the definition of that function.
A statement function reference must appear as (or be part of) an expression. The reference cannot appear on the left side of an assignment statement.
A statement function must not be provided as a procedure argument.
Compatibility
CONSOLE STANDARD GRAPHICS QUICKWIN GRAPHICS WINDOWS DLL LIB
See Also: FUNCTION, Argument Association, Use and Host Association
Examples
The following are examples of statement functions:
REAL VOLUME, RADIUS
VOLUME(RADIUS) = 4.189*RADIUS**3
CHARACTER*10 CSF,A,B
CSF(A,B) = A(6:10)//B(1:5)
The following example shows a statement function and some references to it:
AVG(A,B,C) = (A+B+C)/3.
...
GRADE = AVG(TEST1,TEST2,XLAB)
IF (AVG(P,D,Q) .LT. AVG(X,Y,Z)) STOP
FINAL = AVG(TEST3,TEST4,LAB2) ! Invalid reference; implicit
... ! type of third argument does not
... ! match implicit type of dummy argument
Implicit typing problems can be avoided if all arguments are explicitly typed.
The following statement function definition is invalid because it contains a constant, which cannot be used as a dummy argument:
REAL COMP, C, D, E
COMP(C,D,E,3.) = (C + D - E)/3.
The following shows another example:
Add (a, b) = a + b
REAL(4) y, x(6)
. . .
DO n = 2, 6
x(n) = Add (y, x(n-1))
END DO
18 楼
yeg001 [专家分:14390] 发布于 2010-09-25 21:56:00
statement function 类型不匹配不报错的吗? 难道是一个宏, 只代入不检查属性? 我觉得这可能是一个bug.
楼主的问题恐怕要懂反汇编的朋友查查什么原因. 也可能是个bug.
19 楼
BiCGSTAB [专家分:780] 发布于 2010-09-26 06:54:00
[quote]statement function 类型不匹配不报错的吗? 难道是一个宏, 只代入不检查属性? 我觉得这可能是一个bug.
楼主的问题恐怕要懂反汇编的朋友查查什么原因. 也可能是个bug.[/quote]
类型不匹配恐怕不是主要问题,我改成interp(0.,1.,m(i)) 一样出错。
我试了一下,将v = interp(0.,1.,m(i))改成
do j=1,3
v(j) = interp(0.,1.,m(i))
end do
CVF Compiler就没问题了,看来直接给数组每个元素赋值这种写法,对语句函数不可用。
不过我也不太清楚为什么,呵呵。
20 楼
yeg001 [专家分:14390] 发布于 2010-09-26 09:37:00
已经转移到下一个回帖
我来回复