matmul 内在函数的 Fortran 数组排名

Posted

技术标签:

【中文标题】matmul 内在函数的 Fortran 数组排名【英文标题】:Fortran array rank for matmul intrinsic 【发布时间】:2017-06-02 14:56:33 【问题描述】:

以下链接https://gcc.gnu.org/onlinedocs/gcc-5.4.0/gfortran/MATMUL.html 明确指出,gfortran 期望输入到matmul 的矩阵排名为 1 或 2。但是以下 sn-p 无法编译:

Program scratch
  real(kind=8) :: A(10)=(/0,1,2,3,4,5,6,7,8,9/)
  real(kind=8) :: B(10)=(/0,1,2,3,4,5,6,7,8,9/)
  real(kind=8) :: C(10,10)
  print *,rank(A),rank(B)
  C=matmul(A,B)  
End Program scratch

gfortran 给出错误:

$gfortran scratch.f90 
scratch.f90:6:13:

   C=matmul(A,B)
         1
Error: ‘matrix_b’ argument of ‘matmul’ intrinsic at (1) must be of rank 2

我的 gfortran 是 5.4.0(与上面的链接兼容)。我做的事情真的很愚蠢吗?

【问题讨论】:

是的,你这样做了,你正在使用kind=8 @VladimirF 谢谢你,不幸的是我将声明更改为real(kind=4) 并且 gfortran 报告了同样的错误。 这不是重点,请参阅 ***.com/questions/838310/fortran-90-kind-parameter 和 ***.com/documentation/fortran/939/data-types/4390/… 以及我的回答。与报错无关。 非常密切相关,但不是精确重复的***.com/questions/22305554/… 【参考方案1】:

您可以使用RESHAPE 将它们转换成MATMUL 喜欢的形式:

Program scratch
  real(kind=8) :: A(10)=(/0,1,2,3,4,5,6,7,8,9/)
  real(kind=8) :: B(10)=(/0,1,2,3,4,5,6,7,8,9/)
  real(kind=8) :: C(10,10)
  print *,rank(A),rank(B)
  C = matmul( RESHAPE(A,(/10,1/)), RESHAPE(B,(/1,10/)) )
  WRITE(*,"(10F7.2)") C
End Program scratch

【讨论】:

谢谢,这很有帮助,我真的很想知道 gfortran 文档和编译器之间的脱节。 @ClintonWinant 重塑是一种将 (10) 数组视为 (1,10) 或 (10,1) 数组的方法。解释保持不变。 @ClintonWinant 你是对的——gfortran 文档不正确。这是 Fortran 标准中的相关行:“MATRIX A 和 MATRIX B 不应都具有等级一。” j3-fortran.org/doc/year/10/10-007.pdf @Jack 谢谢,只是为了关闭循环,gfortran 只接受具有 2 级的数组,否则编译器返回:Error: Incompatible ranks 2 and 1 in assignment at (1),即使标准另有说明。我相信我们已经用尽了这个主题...... 其实,没有。对于A(10)B(10),gfortran 将同时采用C = matmul( reshape(A,(/1,10/)), B )C = matmul( A, reshape(B,(/10,1/)) )。但是,在这两种情况下,C 都必须是秩为 1 的单元素数组:C(1)【参考方案2】:

您必须对两个向量的张量积执行此操作

Program scratch
  integer, parameter :: dp = kind(1.d0)
  real(dp) :: A(10,1)=reshape((/0,1,2,3,4,5,6,7,8,9/), (/ 10, 1 /))
  real(dp) :: B(1,10)=reshape((/0,1,2,3,4,5,6,7,8,9/), (/ 1, 10 /))
  real(dp) :: C(10,10)
  print *,rank(A),rank(B)
  C=matmul(A,B)
  print *, C
End Program scratch

如果你这样做

   A(1,10)
   B(10,1)

您将得到一个标量积。只有两个一维数组,不清楚您想要两种产品中的哪一种(尽管对于点产品,有一个特殊的功能可用)。

当您将矩阵乘以向量时,A 或 B 可以是一维数组。

【讨论】:

所以关键是,尽管手册上说 1 阶矩阵输入是可接受的,但编译器更聪明,知道这是模棱两可的,并坚持 2 阶。因为 dot_product 内在存在,我以为 matmul 会默认为二元乘积,错了...谢谢 排名 1 是允许的,但不是两个参数。 这一行 real(dp) :: A(10,1)=(/0,1,2,3,4,5,6,7,8,9/) 给了我错误 Error: Incompatible rank 2 and 1 in assignment at (1) in gfortran 和 PGF90-S-0155-初始值设定项的形状与 pgfortran 中 (scratch.f90: 4) 的形状不匹配。我在这里做错了吗? 不,我认为我有一个错误,但我的编译器出于某种原因允许这样做。我确实测试过。 那是什么编译器?

以上是关于matmul 内在函数的 Fortran 数组排名的主要内容,如果未能解决你的问题,请参考以下文章

对于不属于标准的 FORTRAN 内在函数,我该怎么办?

intel fortran 编译错误“此内在函数在常量表达式中无效”

由非内在函数给出的常量值

Fortran 重塑 - N 维转置

Simd matmul 程序给出不同的数值结果

fortran关于数组内部函数的问题