gpt4 book ai didi

arrays - gfortran 中隐含 do 的数组构造函数的奇怪初始化行为

转载 作者:行者123 更新时间:2023-12-04 19:28:22 28 4
gpt4 key购买 nike

假设我有 3 个 double 数组,

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 (具有常量参数的数组理解)只要 n>65535 , 独立 其精度。 AFAIK, 65535unsigned 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

是什么赋予了?

最佳答案

编译器处理数组构造函数的方式确实存在很大差异。对于 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.单精度数组没有类型转换,但 double 数组有一些类型转换。这导致了这两种情况的差异。

关于arrays - gfortran 中隐含 do 的数组构造函数的奇怪初始化行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49330816/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com