【问题标题】:Does this code demonstrate a bug in GFortran?此代码是否演示了 GFortran 中的错误?
【发布时间】:2020-02-12 13:24:26
【问题描述】:

从下面的代码可以看出,当它询问你是继续还是停止程序时,通过按“;”等其他键或“,”它读起来就好像您按下了“Y”或“y”键但您没有按下。所以,我在问这是编译器中的错误,还是代码有问题?

program vols

!Calculates difference in volume of 2 spheres
implicit none

real :: rad1,rad2,vol1,vol2
character :: response

do
print *, 'Please enter the two radii'
read *, rad1,rad2
call volume(rad1,vol1)
call volume(rad2,vol2)
write(*,10) 'The difference in volumes is, ',abs(vol1-vol2)
10       format(a,2f10.3)
print *, 'Any more? - hit Y for yes, otherwise hit any key'
read *, response
if (response /= 'Y' .and. response /= 'y') stop
end do

end program vols

!________________________________________________

subroutine volume(rad,vol)
implicit none
real :: rad,vol,pi
!calculates the volume of a sphere
pi=4.0*atan(1.0)
vol=4./3.*pi*rad*rad*rad
!It's a little quicker in processing to  do r*r*r than r**3!
end subroutine volume

【问题讨论】:

  • 欢迎,Fortran 问题请使用标签fortran
  • 如果response;(或几乎其他任何东西,试试n),考虑response /= 'Y' 的结果。现在考虑response /= 'y' 并考虑.and.
  • @HighPerformanceMark 那么,为什么当我们省略 .and. response /='y' 时它可以正常工作?
  • 第一次输入'Y'或'y',变量“response”的值为'Y'或'y',第二次输入','运行,响应的输入为 NULL,因此通过 LIST-DIRECTED 解释,变量“响应”未更改,因此它保持值“Y”/“y”。英特尔编译器还会循环“,”。 ';'的情况,我不知道,可能是gfortran的bug。

标签: fortran gfortran


【解决方案1】:

如果没有关于您的确切输入的更多详细信息,我们无法断定这是 gfortran 中的错误。相反,该程序的一个特性可能会导致“令人困惑”的行为。

为了获得响应,程序使用列表导向输入。这会导致不直观的结果。例如,对于someone writing a calculator,当有人输入*/ 时会发生什么,您可能会感到惊讶。

在计算器示例中,* 涉及重复计数,/ 涉及记录分隔符。对于这个问题,也有特殊意义。在列表导向输入中,, 是一个值分隔符,带有该字符的read *, x 不会将x 设置为值','

取而代之的是输入语句

read *, response

当出现输入时

,

将来到, 并看到“哈哈,用户告诉我没有指定值”。这与空行形成对比,在空行中输入处理继续​​等待一个值。

这个值分隔符与列表导向输入的另一个特性相结合:允许空值。空值完成输入语句,但保留相应的值不变(未设置为空白)。

这意味着如果输入像这样

1 1
y
1 1
,

在第二次传递中,字符 response 与值 'y'未更改。同样,对于

1 1
,

response 未定义状态不变:不允许程序将其值与'y' 进行比较。

如何解决这个问题?只需使用适当的格式:

read '(A)', response

这样,输入,被视为字符而不是值分隔符。

虽然逗号在问题的列表导向输入中以特殊方式处理,但分号不是。如果您看到分号输入出现意外行为,那么这可能会引起关注。我看不到我可用的 gfortran 会发生这种情况。

但是,分号可能是特殊的。当十进制编辑模式为COMMA(而不是默认的POINT)时,分号将被视为值分隔符而不是逗号(现在在1,23 等值中充当小数分隔符)。 COMMA 不是默认的连接模式。

【讨论】:

  • 我看到即使是分号也做了同样的伎俩,这让人怀疑!
  • 您能提供完整的输入和编译器版本吗?可能存在编译器问题,但需要准确了解您输入的内容。
【解决方案2】:

仅供参考 - 我在 Intel Fortran 中尝试了此代码,它按预期工作。当responseyY 时循环,否则退出循环。

program vols

!Calculates difference in volume of 2 spheres
implicit none

real :: rad1,rad2,vol1,vol2
character :: response

do
    print *, 'Please enter the two radii'
    read *, rad1,rad2
    call volume(rad1,vol1)
    call volume(rad2,vol2)
    print '(a,2f10.3)', 'The difference in volumes is, ',abs(vol1-vol2)
    print *, 'Any more? - hit Y for yes, otherwise hit any key'
    read *, response
    if (response /= 'Y' .and. response /= 'y') stop
end do

contains

subroutine volume(rad,vol)
implicit none
real :: rad,vol,pi
!calculates the volume of a sphere
pi=4.0*atan(1.0)
vol=4./3.*pi*rad*rad*rad
!It's a little quicker in processing to  do r*r*r than r**3!
end subroutine volume

end program vols

看来,问题可能特定于gfortran 这里。

PS。我在program 块中移动了函数,这样它就不需要接口或外部声明。

PS2。我检查了编译结果,rad**3rad*rad*rad 相同。现代编译器比你想象的要聪明。最好在程序中显示意图,而不是用微优化来掩盖它。

【讨论】:

  • 我们可以说这肯定是一个错误吗?
  • @Student404Mus - 我不能,因为我不是gfortran 用户。我只是想与不同的编译器进行比较。
猜你喜欢
  • 1970-01-01
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-03
相关资源
最近更新 更多