主题:[讨论]矢量下标作数组索引时的只读属性
helo_aBiNg
[专家分:480] 发布于 2011-06-12 10:30:00
最近在 debug 程序时得到了确认,花去了我几天的时间,实在有些不甘心。为避免诸位误入此类陷阱,特发帖说明。其实无论是 Intel 的 reference 还是 IBM 的线上文档都有说明,但在遇到这个问题之前谁又会注意到呢?:P
program main
implicit none
integer, dimension(4) :: array
array = 0
call eval(array(2:), 3)
print *, array(3)
array = 0
call eval(array((/2,3,4/)), 3)
print *, array(3)
stop
end program
subroutine eval(a, n)
implicit none
integer, intent(in) :: n
integer, dimension(n) :: a
a(2) = -1
return
end subroutine eval
以上为测试代码,如果遇到过这个问题的朋友,一看便知。
[quote][I]If you pass an array section with a vector subscript as an actual argument, the associated dummy argument must not be defined or redefined.[/I][/quote]
这是 IBM 线上文档对于矢量下标哑实传递的说明。用的是 must not be defined or redefined,所以我想这应该是个只读属性。正如上例中所示,即使 redefined,实参并无影响。
但如果不作子程序传递,直接赋值,比如:
array((/2,3,4/)) = -1
这是可行的。也即,只是哑实传递时才会有这个限制。对于 Intel 汇编不熟悉,不太清楚编译器是如何实现的。是直接抛弃还是在传递时作了复制操作?
另外,基于 gcc 4.5.3 的 gfortran 尚不支持 array((/1,3:4/)) 这种混合下标索引。
回复列表 (共17个回复)
沙发
yeg001 [专家分:14390] 发布于 2011-06-12 11:43:00
果然是有这种问题. 在linux下测试了ivf11.1, 12 和gfortran 4.5.2. 第二次调用所修改的值没有传递回去原数组.
如果它等同于只读属性而进行了修改, 编译器不提示, 这实在有风险.
等有时间查查相关的文档.
多谢楼主辛苦提示!!
板凳
cgl_lgs [专家分:21040] 发布于 2011-06-12 16:55:00
第二次调用时,程序将数组做了一个副本,所以会有这样的现象出来:)
试想,如果不做副本,你的下标不连续我该在子程序中如何访问?
3 楼
dongyuanxun [专家分:7180] 发布于 2011-06-12 16:56:00
恩,这是非地址传递的一种情况
4 楼
helo_aBiNg [专家分:480] 发布于 2011-06-12 19:58:00
@yeg001:
是哦,编译器应该有个 warning,比如子例程中没有加 intent(in) 属性时。
@cgl_lgs:
嗯,这个反问很有道理。应该是作了复制操作。但如果有人帮忙看下汇编,会更加放心些。:)
有人考虑去给 gfortran 提交个补丁么?顺便把混合下标也一并支持了吧。XD
5 楼
dongyuanxun [专家分:7180] 发布于 2011-06-12 20:46:00
objdump -d自己看下就知道了
补丁这个要看是不是现有路线图中的,估计改array.c那几个match就行了
个人感觉这个用法很少见,而且是很低效的写法(指运行效率)
6 楼
helo_aBiNg [专家分:480] 发布于 2011-06-12 21:39:00
@dongyuanxun:
之前看过 arm assembly,但 intel 语法好像复杂些。不想去学习嘛。:P
你看过后确认是有副本操作了吗?
效率能低多少,方便倒是,我自己常用。我的实际情况是要求解矩阵部分行列的逆阵,有什么更理想的算法么?
7 楼
dongyuanxun [专家分:7180] 发布于 2011-06-12 22:33:00
你看下汇编就知道了,第一次使用只有6条指令左右,第二次有20多条,大多数都是赋值操作,肯定效率低了。
我觉得你可以在传递之前先重新构造一个数组再传递即可,用循环之类的均可,因为现在编译器自动向量化水平都还可以,这种级别的循环很容易转变成SIMD指令。
8 楼
cgl_lgs [专家分:21040] 发布于 2011-06-12 23:05:00
如果对于小数组(矩阵)这样倒不是不行,但确实应少用这样的方式,用连续的行或列完全可以不用这样的表达方式:)
9 楼
yeg001 [专家分:14390] 发布于 2011-06-12 23:56:00
这种用法可能不会用得很多,不过就语义来说,既然不返回修改值,那还是应该提示一下.
继续关注中.
10 楼
helo_aBiNg [专家分:480] 发布于 2011-06-13 00:03:00
@dongyuanxun @cgl_lgs:
按照我首帖的说明,我的这种求逆需求显然需要重构数组的。连续的行列只用到 subscript triplets 索引即可,也不必重构。矢量下标索引在我需要抽取数组片断时还是很方便。:D
我来回复