cak*_*ako 5 arrays constructor fortran intel gfortran
假设我有3个双精度数组,
real*8, dimension(n) :: x, y, z
Run Code Online (Sandbox Code Playgroud)
初始化为
x = 1.
y = (/ (1., i=1,n) /)
z = (/ (1. +0*i, i=1,n) /)
Run Code Online (Sandbox Code Playgroud)
他们应该将所有数组的所有元素初始化为1.在ifort(16.0.0 20150815)中,这适用n于声明的精度范围内的任何范围.也就是说,如果我们初始化n为
integer*4, parameter :: n
Run Code Online (Sandbox Code Playgroud)
然后,只要n < 2147483647初始化按预期用于所有声明.
在gfortran(4.8.5 20150623红帽4.8.5-16),初始化失败对于y(具有恒定的参数数组理解),只要n>65535,独立的其精度.AFAIK,65535是a的最大值unsigned short int,也就是说unsigned int*2,它在范围内integer*4.
以下是MWE:
program test
implicit none
integer*4, parameter :: n = 65536
integer*4, parameter :: m = 65535
real*8, dimension(n) :: x, y, z
real*8, dimension(m) :: a, b, c
integer*4 :: i
print *, huge(n)
x = 1.
y = (/ (1., i=1,n) /)
z = (/ (1.+0*i, i=1,n) /)
print *, x(n), y(n), z(n)
a = 1.
b = (/ (1., i=1,m) /)
c = (/ (1.+0*i, i=1,m) /)
print *, a(m), c(m), c(m)
end program test
Run Code Online (Sandbox Code Playgroud)
用gfortran(gfortran test.f90 -o gfortran_test)编译,它输出:
2147483647
1.0000000000000000 0.0000000000000000 1.0000000000000000
1.0000000000000000 1.0000000000000000 1.0000000000000000
Run Code Online (Sandbox Code Playgroud)
用ifort(ifort test.f90 -o ifort_test)编译,它输出:
2147483647
1.00000000000000 1.00000000000000 1.00000000000000
1.00000000000000 1.00000000000000 1.00000000000000
Run Code Online (Sandbox Code Playgroud)
是什么赋予了?
编译器对待数组构造函数的方式确实存在很大差异。因为n<=65535目标文件中(或某些中间表示形式)存储了实际的 [1., 1., 1.,...] 数组。
对于更大的数组,编译器会生成一个循环:
(*(real(kind=8)[65536] * restrict) atmp.0.data)[offset.1] = 1.0e+0;
offset.1 = offset.1 + 1;
{
integer(kind=8) S.2;
S.2 = 0;
while (1)
{
if (S.2 > 65535) goto L.1;
y[S.2] = (*(real(kind=8)[65536] * restrict) atmp.0.data)[S.2];
S.2 = S.2 + 1;
}
L.1:;
}
Run Code Online (Sandbox Code Playgroud)
在我看来,首先它仅设置临时数组的一个元素,然后将(大部分未定义的)临时数组复制到y. 这是错误的。Valgrind 还报告未初始化内存的使用情况。
对于默认实数,我们有
while (1)
{
if (shadow_loopvar.2 > 65536) goto L.1;
(*(real(kind=4)[65536] * restrict) atmp.0.data)[offset.1] = 1.0e+0;
offset.1 = offset.1 + 1;
shadow_loopvar.2 = shadow_loopvar.2 + 1;
}
L.1:;
{
integer(kind=8) S.3;
S.3 = 0;
while (1)
{
if (S.3 > 65535) goto L.2;
y[S.3] = (*(real(kind=4)[65536] * restrict) atmp.0.data)[S.3];
S.3 = S.3 + 1;
}
L.2:;
}
Run Code Online (Sandbox Code Playgroud)
我们现在有两个循环,一个循环设置整个临时数组,第二个循环将其复制到y,一切都很好。
该问题由阅读此问题的 GCC 开发人员解决。该错误可在https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84931进行跟踪
他们还发现该问题与类型转换有关。构造函数具有默认精度1.,对于单精度数组,没有类型转换,但对于双精度数组,存在一些类型转换。这导致了这两种情况的差异。
| 归档时间: |
|
| 查看次数: |
247 次 |
| 最近记录: |