这段代码是否展示了GFortran的一个错误?

3

从下面的代码可以看出,当询问您是否继续或停止程序时,按下其他键(如“;”或“,”),它会将其读取为您按下了“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相关问题请使用标签[tag:fortran]。 - Vladimir F Героям слава
3
如果response;(或几乎任何其他字符,比如n),则response /= 'Y'的求值结果是什么。现在考虑response /= 'y'并思考.and.的意义。 - High Performance Mark
@HighPerformanceMark 所以,为什么当我们省略 .and. response /='y' 时,它就可以正常工作了? - EnthusiastiC
1
如果在第一次运行时输入“Y”或“y”,则变量“response”的值为“Y”或“y”,然后如果在第二次运行时输入“,”,则响应输入为NULL,因此通过LIST-DIRECTED解释,变量“response”不会改变,因此它保持值“Y”/“y”。Intel编译器也循环使用“,”。至于“;”的情况,我不知道,可能是gfortran的错误。 - yamajun
2个回答

3

如果没有更多关于您的输入的详细信息,我们无法得出这是gfortran中的一个错误。相反,程序存在一个可能导致“混乱”行为的特性。

为了获得响应,程序使用列表定向输入。这会导致非直观的结果。例如,在有人编写计算器的情况下,当有人输入*/时可能会感到惊讶。

在计算器示例中,*涉及重复计数,而/涉及记录分隔符。对于这个问题,,也有一个特殊的含义。在列表定向输入中,,是一个值分隔符,用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不是连接的默认模式。


我发现即使是分号也能起到同样的作用,这让人感到疑惑! - EnthusiastiC
你能提供完整的输入和编译器版本吗?可能存在编译器问题,但需要确切的输入才能进一步查看。 - francescalus

1

提供信息 - 我在英特尔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 是相同的。现代编译器比想象中更聪明。最好在程序中显示 意图 ,而不是用微观优化来掩盖它。


我们可以说这肯定是个bug吗? - EnthusiastiC
@Student404Mus - 我不能这样做,因为我不是gfortran的用户。我只是想与另一个编译器进行比较。 - John Alexiou

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接