我们说我有3个双精度数组,
real*8, dimension(n) :: x, y, z
初始化为
x = 1.
y = (/ (1., i=1,n) /)
z = (/ (1. +0*i, i=1,n) /)
他们应该将所有数组的所有元素初始化为1
。在ifort
(16.0.0 20150815)中,这适用于声明精度范围内的任何n
。也就是说,如果我们将n
初始化为
integer*4, parameter :: n
然后只要n < 2147483647
,初始化就像所有声明一样工作。
在gfortran
(4.8.5 20150623 Red Hat 4.8.5-16)中,只要y
,<{1}},n>65535
(具有常量参数的数组理解)的初始化失败>独立的精确度。 AFAIK,65535
是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
使用gfortran
(gfortran test.f90 -o gfortran_test
)进行编译,输出:
2147483647
1.0000000000000000 0.0000000000000000 1.0000000000000000
1.0000000000000000 1.0000000000000000 1.0000000000000000
使用ifort
(ifort test.f90 -o ifort_test
)进行编译,输出:
2147483647
1.00000000000000 1.00000000000000 1.00000000000000
1.00000000000000 1.00000000000000 1.00000000000000
是什么给出了?
答案 0 :(得分:4)
编译器如何处理数组构造函数确实存在很大差异。对于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:;
}
在我看来,首先它只设置一个临时数组的一个元素,然后将(大部分未定义的)临时数组复制到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:;
}
我们现在有两个循环,一个设置整个临时数组,第二个循环复制到y
,一切都很好。
这个问题由阅读此问题的GCC开发人员修复。该错误在https://gcc.gnu.org/bugzilla/show_bug.cgi?id=84931
进行跟踪他们还发现问题与类型转换有关。构造函数具有默认精度1.
,并且对于单精度数组,没有类型转换,但对于双精度数组,存在一些类型转换。这导致了这两种情况的不同。