【问题标题】:Using larger array in a Fortran subroutine在 Fortran 子例程中使用更大的数组
【发布时间】:2018-06-01 13:13:21
【问题描述】:

我的 Fortran 代码如下(test.f):

subroutine sub(n1,n2,wa)
implicit none
integer, intent(in)  :: n1, n2
real(4), intent(inout) :: wa(1_8:1_8*n1*n2)
integer(8) :: i, j, ms

print*, 'in sub, 1_8*n1*n2=', 1_8*n1*n2
print*, 'in sub, size of wa:', size(wa,kind=8)

ms=0
!$omp parallel default(shared) private(i,j,ms)
!$omp do 
    do i=1, n1
    do j=1, n2
       ms=(i-1)*n2+j
       wa(ms)=ms*1.d0
    enddo; enddo;
!$omp end do nowait
!$omp end parallel

print*, 'size of wa:', size(wa,kind=8)

return
end subroutine sub

program main
implicit none
integer, parameter :: n1=2**11,n2=2**20
real(4), allocatable :: wave(:)
integer :: ierr
integer(8) :: i

allocate(wave(1_8*n1*n2), stat=ierr)

!$omp parallel default(shared) private(i)
!$omp do
     do i=1_8,1_8*n1*n2
       wave(i)=0.d0
     enddo
!$omp end do nowait
!$omp end parallel


print*, 'in main, size of wave:', size(wave,kind=8)

call sub(n1, n2, wave)

print*, wave(1_8*n1*n2)

deallocate(wave, stat=ierr)
end program main

n1 和 n2 可以更大,并确保 n1*n2 是一个长整数(>2**31-1)。我只是想测试如何在子程序中使用非常大的数组。

我编译时使用:ifort -openmp -CB test.f

如果我使用-CB 选项检查数组的边界,子程序sub 中的数组wa 会出错。

这是错误信息:

主要,波浪大小:2147483648
在子中,1_8*n1*n2= 2147483648
在 sub 中,wa 的大小:0
forrtl: 严重 (408): fort: (2): 数组 WA 的下标 #1
值 108003329 大于 -2147483648 的上限。

错误信息中的数字是随机的。

当我在子程序中将wa 声明为real(4), intent(inout) :: wa(1) 时,程序将运行良好。谁能告诉我为什么?

【问题讨论】:

  • 您是否知道编译器可能会将real(4), intent(inout) :: wa(1) 解释为不意味着wa 是一个大小为1 的数组(但假定大小)?根据编译器看到的“错误”,这可能很重要。如果您有来自编译器的消息(编译或运行),请显示出来。
  • 这是错误信息:forrtl:severe (408):fort:(2): 数组 WA 的下标 #1 的值为 108003329,大于 -2147483648 的上限。错误信息中的数字是随机的。
  • edit的问题,不要使用cmets。不,不建议直接使用种类编号作为48,也不可移植。这些数字不是字节数stackoverflow.com/questions/838310/fortran-90-kind-parameter
  • 我在运行您的代码时没有收到任何错误消息。此外,号码-2147483648 是可疑的。请仔细检查您显示的代码是否准确且与错误消息完全对应。
  • 当我将 n1 和 n2 设置得更小(n1*n2

标签: arrays fortran subroutine


【解决方案1】:

forrtl: Serious (408): fort: (2): 数组 WA 的下标 #1 有 值 108003329 大于 -2147483648 的上限

错误上的索引可能是随机的,但上限不是。 -2147483648 是未经检查的表达式 2**11 * 2**20 的结果,默认整数 (kind=int32),因为最大可表示数是 2**31-1 = 2147483647

您在子例程中声明虚拟数组的上限,如下所示:

wa(1_8:1_8*n1*n2)

由于这两个操作具有相同的优先级,可能编译器先将 n1 和 n2 相乘,得到否定的结果,然后再乘以 1_8 以将其转换为更大的种类。我现在无法测试。

您可以尝试在表达式上使用括号,如果您可以访问调试器,则可以在运行时检查变量的类型和边界。

另外,不要依赖像 4 或 8 这样的“神奇数字”。Thosr 数字取决于编译器。您应该使用selected_int_kind 或内部模块iso_fortran_env 上的常量。

【讨论】:

  • 我认为 Fortran 表达式的规则不允许您进行解释。如果开头有 1_8,则结果必须至少有种类 8。另外,我注意到,我的 Intel Fortran 版本不会发生这种情况。
  • 另请注意:in sub, 1_8*n1*n2= 2147483648
  • 其实我也有同样的问题,但是编译器没有报错。我确实有size(wa)=0。但解释会比你建议的更微妙。该表达式具有正确的种类。在 gfortran size(wa)=2147483648.
  • Vladimir F 是正确的:a*b*ca 的范围大于bc)的类型是a。这并不是说编译器没有在较低范围内执行b*c,但如果是这样,那是一个明显的错误。
  • 是的,我刚刚检查了标准,NOTE 10.9 说它应该是从左到右的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-09
  • 2017-02-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
相关资源
最近更新 更多