使用 ifort 的指数的 Fortran 运算符优先级错误

Posted

技术标签:

【中文标题】使用 ifort 的指数的 Fortran 运算符优先级错误【英文标题】:Fortran operator precedence error for exponent with ifort 【发布时间】:2013-03-14 17:19:43 【问题描述】:

在使用指数后跟乘法计算简单表达式时,我在 Portland 和 Intel fortran 编译器之间得到了不同的行为。根据我对运算符优先级的理解,我很确定 pgf90(和 gfortran)可以正常工作,但我想要第二个意见,因为这些事情可能会有点棘手。

这是我的代码简化为一个非常基本的形式。当使用 ifort 运行时,d1=a**-2*b 形式的表达式被 ifort 解释为 d1=a**(-2*b),被 pgf90 和 gfortran 解释为 d1=(a**-2)*b。如果我从指数中删除负号,所有三个编译器都将其解释为d1=(a**2)*b。如果我将 *b 更改为 +b,我也会从这三个方面获得良好的表现。

program badvals
  implicit none
  real :: a, b, c1, c2, d1, d2

  a = 2.
  b = 4.

  ! Works with addition following the exponent.
  c1 = a**-2+b
  c2 = a**(-2)+b

  ! Ifort differs with multiplication following negative exponent.
  d1 = a**-2*b
  d2 = a**(-2)*b

  print*, "c1, d1       = ",c1, d1
  print*, "c2, d2       = ",c1, d2
  print*, "c2-c1, d2-d1 = ",c2-c1, d2-d1
end program badvals

!Program output for ifort v13.0.1.117: (either -O0 or -fast):
! c1, d1       =    4.250000      3.9062500E-03
! c2, d2       =    4.250000       1.000000
! c2-c1, d2-d1 =   0.0000000E+00  0.9960938

!Program output for pgf90 v12.10-0: (either -O0 or -fast):
! c1, d1       =     4.250000        1.000000
! c2, d2       =     4.250000        1.000000
! c2-c1, d2-d1 =     0.000000        0.000000

!Program output for gfortran v4.1.2: (either -O0 or -O3):
! c1, d1       =    4.250000       1.000000
! c2, d2       =    4.250000       1.000000
! c2-c1, d2-d1 =    0.000000       0.000000

这些差异背后是否有历史,因此它们应该被视为“特征”?或者,这是否是英特尔的一个彻头彻尾的错误?

【问题讨论】:

因此,根据 MSB 和 IanH 的响应,这将是 ifort 的“功能”。总的来说,我从中得到的是,我需要将“不要将两个算术运算符放在一起”的规则添加到我的想法中。和往常一样,要慷慨地使用括号。 IanH 提供的链接对于理解 ifort 的想法非常有帮助。我在将 * 更改为 + 时看到的不同行为是因为一元 +- 优先级介于 * 和二元 +- 之间。 【参考方案1】:

在网上搜索,我发现不允许两个连续运算符的说法。因此,解释而不是拒绝这个表达是对语言的扩展。该扩展已由不同的编译器供应商以不同的方式实现。

确实,当我使用带有限制性编译器选项的 gfortran 时,它会拒绝此代码示例:

badvals.f90:9.11:
  c1 = a**-2+b
           1
Error: Extension: Unary operator following arithmetic operator (use parentheses) at (1)
badvals.f90:13.11:

  d1 = a**-2*b
           1
Error: Extension: Unary operator following arithmetic operator (use parentheses) at (1)

同样,带有限制性编译器选项的 ifort 提供以下功能:

badvals.f90(9): warning #7026: Non-standard extension
  c1 = a**-2+b
----------^
badvals.f90(13): warning #7026: Non-standard extension
  d1 = a**-2*b
----------^

所以: 1) 使用编译器的警告和错误选项会很有帮助, 2)它更多的是扩展而不是错误, 3) 即使语言允许这种表达方式,gfortran 的建议也很好——即使不需要,也要使用括号来清楚说明。

【讨论】:

"不允许两个连续的运算符" 需要一点限定 - 它适用于此处,因为二级表达式(算术表达式)的语法规则但通常不... to_be .or. .not. to_be 可以(并且在莎士比亚的 Fortran 中很常见),您也可以在其中添加一个已定义的一元运算符。如果 OP 想要扩展的正式描述,他们可以阅读this。 这些限制性选项是什么?

以上是关于使用 ifort 的指数的 Fortran 运算符优先级错误的主要内容,如果未能解决你的问题,请参考以下文章

使用 ifort/icc 时未定义对“main”的引用

启用英特尔Fortran时“找不到psxevars命令”

使用Fortran共享库时名称不匹配

CMake Fortran 编译器相关标志

如何使用 gdb 为 Fortran 程序打印数组大小(绑定)

主程序中应该允许返回语句吗?