在Fortran中赋值时自动分配数组 [英] Automatic array allocation upon assignment in Fortran

查看:755
本文介绍了在Fortran中赋值时自动分配数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

最近我们发现我们正在为Fortran中的未分配数组做一个分配。 GNU gfortran编译器没有发现错误,代码在OSX和Linux下运行。但是,IBM Power PC上的代码分段错误相同。

我的问题是,以下代码是否正确?看起来,分配给 array 的数组在内存中自动分配内存,而不是其他内存。这里有工作具体细节吗?



该代码是一个混合的C / Fortran代码:

 #包括< stdlib.h> 

void assign_array_(double x [],int * n);
void print_array_();

int main()
{
int n,i;
double * x;

n = 5;
x =(double *)malloc(sizeof(double)* n); (i = 0; i< n; i ++)
x [i] =(double)i;



assign_array_(x,& n);
print_array_();

返回0;
}

以及Fortran代码:

  MODULE test_mod 
DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:) :: array
integer :: nsize
END MODULE test_mod

SUBROUTINE assign_array(x,n)
USE test_mod
IMPLICIT NONE

INTEGER :: n
DOUBLE PRECISION :: x(n)

CALL test_allocated()
array = x
CALL test_allocated()
nsize = n

END SUBROUTINE assign_array


SUBROUTINE print_array()
USE test_mod,ONLY:nsize,array
IMPLICIT NONE

INTEGER :: i

DO i = 1 ,nsize
WRITE(6,'(F24.16)')array(i)
END DO

END SUBROUTINE print_array

SUBROUTINE test_allocated )
USE test_mod
IMPLICIT NONE

IF(ALLOCATED(array))THEN
WRITE(6,*)'数组分配'
WRITE 6,*)'size is',SIZE(array)
ELSE
WRITE(6,*)'Arra y不分配'
END IF
END SUBROUTINE test_allocated

输出(当它运行时):

 数组不分配
数组分配
大小为5
0.0000000000000000
1.0000000000000000
2.0000000000000000
3.0000000000000000
4.0000000000000000



<这里是Power PC上的输出:

 数组未分配
分段错误(核心转储)

总结:它在GNU编译时运行(GNU Fortran(MacPorts gcc5 5.4.0_0)5.4。 0)在OSX上的gfortran(arch:x86_64h)和Linux(在OSX上托管的虚拟机上,GNU Fortran(Ubuntu 4.9.4-2ubuntu1〜14.04.1)4.9.4),但在Power PC上编译时无法运行(arch:ppc64)使用GNU Fortran(GCC)4.4.7 20120313(Red Hat 4.4.7-17)编译。在我们最初的代码中,Power PC的实现只是在代码中稍后进行了隔离,其中引用了分配数组的条目,这使得我们的'错误'(如果它实际上是一个错误)真的很难追查。



以上代码的正确行为是什么?

解决方案

代码的有效性就像

  integer,allocatable :: array(:) 
array =(/ 1,2, 3 /)
end

取决于Fortran用来解释它的标准。 p>

Fortran 2003引入了内在赋值自动分配的概念。在Fortran 2003之前,这种赋值语句左侧的数组必须被分配,并且与右侧数组的形状相同。



从Fortran 2003开始,只有排名需要匹配。如果形状不匹配,则数组将首先解除分配,然后重新分配给正确的形状。如果最初没有分配,它将被分配。



因此,上面的程序不是有效的Fortran 90,而是Fortran 2003的有效。



现实世界代码的不同之处在于语言编译器支持的语法。



对于gfortran,Fortran 2003的任务一个可分配数组是在4.6,2011-01-28中引入的



正如所评论的,命令行选项 -fno-realloc-lhs 1 禁用了这个自动(重新)分配,使编译器不符合Fortran 2003+。




1 其他编译器具有相似的行为:添加必要的检查以确定是否需要重新分配是Fortran 90兼容代码中冗余的性能命中,并且可能是许多甚至在现代代码中都未使用的功能。例如,对于英特尔编译器,在某些支持F2003的版本中,缺省情况是忽略此项。



通过使用数组部分,可以在现代代码中始终抑制数组的(重新)分配检查/操作。

  array(:) =(/ 1,2,3 /)

这种情况下, array (如果是可分配的)必须被分配,等级1和大小为3的赋值语句有效。这就像在整个数组 array =(/ 1,2,3 /)中赋值的Fortran 90解释一样。



原因在于,对于这个脚注的数组部分,即使数组本身是左边也是不可分配的。


We recently discovered we were making an assignment to an unallocated array in Fortran. The GNU gfortran compiler didn't catch the error, and the code runs under both OSX and Linux. However, the same code segmentation faults on a IBM Power PC.

My question is, is the following code correct? It seems that the array assigned to array is automatically allocating memory, on some architectures, but not on others. Are there implementation specific details at work here?

The code is a mixed C/Fortran code :

#include <stdlib.h>

void assign_array_(double x[], int* n);
void print_array_();

int main()
{
    int n,i;
    double *x;

    n = 5;
    x = (double*) malloc(sizeof(double)*n);

    for (i = 0; i < n; i++)
        x[i] = (double) i;

    assign_array_(x,&n);
    print_array_();

    return 0;
}

And the Fortran code :

MODULE test_mod
  DOUBLE PRECISION, ALLOCATABLE, DIMENSION(:) :: array
  integer :: nsize
END MODULE test_mod

SUBROUTINE assign_array(x,n)
  USE test_mod
  IMPLICIT NONE

  INTEGER :: n
  DOUBLE PRECISION :: x(n)

  CALL test_allocated()
  array = x
  CALL test_allocated()
  nsize = n

END SUBROUTINE assign_array


SUBROUTINE print_array()
  USE test_mod, ONLY: nsize, array
  IMPLICIT NONE

  INTEGER :: i

  DO i = 1,nsize
     WRITE(6,'(F24.16)') array(i)
  END DO

END SUBROUTINE print_array

SUBROUTINE test_allocated()
  USE test_mod
  IMPLICIT NONE

  IF (ALLOCATED(array)) THEN
     WRITE(6,*) 'Array is allocated'
     WRITE(6,*) 'size is ', SIZE(array)
  ELSE
     WRITE(6,*) 'Array is NOT allocated'
  END IF
END SUBROUTINE test_allocated

The output (when it runs) is :

Array is NOT allocated
Array is allocated
size is            5
  0.0000000000000000
  1.0000000000000000
  2.0000000000000000
  3.0000000000000000
  4.0000000000000000

And here is the output on the Power PC :

Array is NOT allocated
Segmentation fault (core dumped)

In summary: It runs when compiled under GNU (GNU Fortran (MacPorts gcc5 5.4.0_0) 5.4.0) gfortran on OSX (arch : x86_64h) and Linux (in a virtual machine hosted on OSX, GNU Fortran (Ubuntu 4.9.4-2ubuntu1~14.04.1) 4.9.4), but fails to run when compiled on the Power PC (arch: ppc64) compiled using GNU Fortran (GCC) 4.4.7 20120313 (Red Hat 4.4.7-17). In our original code, the Power PC implementation only segfaulted much later in the code, where entries assigned array was referenced, making our 'bug' (if it is in fact a bug) really hard to track down.

What is the correct behavior for the above code?

解决方案

The validity of code like

integer, allocatable :: array(:)
array = (/1,2,3/)
end

depends on the standard of Fortran used to interpret it.

Fortran 2003 introduced the concept of automatic allocation on intrinsic assignment. Before Fortran 2003 the array on the left-hand side of such an assignment statement must be allocated, and of the same shape as the array on the right-hand side.

From Fortran 2003 only the rank needs match. If there is a shape mismatch, the array would be first deallocated and then reallocated to the correct shape. If not allocated initially, it would be allocated.

So, the program above isn't valid Fortran 90, but is valid Fortran 2003.

The difference in the real-world code, then, is from what language syntax the compilers support.

For gfortran, Fortran 2003's assignment to an allocatable array was introduced in 4.6, 2011-01-28.

As also commented, the command line option -fno-realloc-lhs1 disables this automatic (re-)allocation, making the compiler not Fortran 2003+ compliant.


1 Other compilers have similar behaviour: adding a required check for whether reallocation is necessary is a performance hit which is redundant in Fortran 90 compliant code and may be a feature not used by many even in modern code. For Intel's compiler, for example, in some versions which do support F2003 the default is to ignore this.

One can always suppress the (re-)allocation checks/actions of an array in modern code by using an array section

array(:) = (/1,2,3/)

In this case, array (if allocatable) must be allocated, of rank 1 and of size 3 for the assignment statement to be valid. This is as would be under a Fortran 90 interpretation of the assignment with the whole array array=(/1,2,3/).

The reason for this is that with the array section of this footnote, the left-hand side is not allocatable, even though the array itself is.

这篇关于在Fortran中赋值时自动分配数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆