我刚才有一个简短的问题,这个问题是我在尝试获取Fortran中数字的平方根时所做的观察。比较以下两个陈述
wp = selected_real_kind(15, 307)
somevar = sqrt(3.0)
somevar2 = (3.0_wp)**(1.0/2.0)
我发现somevar = 1.7320507764816284和somevar2 = 1.7320508075688772。根据{{3}},似乎somevar2是更正确的答案。我的问题是如果声明
squareroot = real(x,wp) ** (1.0/2.0)
总是会为数字的平方根产生更正确的值吗?
如果是这样,这与sqrt()
函数默认返回单个精度变量的事实有关,还是与使用的编译器有关?
答案 0 :(得分:5)
此处引用的sqrt
是通用内在函数。此泛型接受任何实数或复数参数,并返回与参数类型和种类相同的结果。
在这种情况下,参数3.0
是默认类型的实数(文字常量),因此结果也是真实的默认类型。另一方面,表达式(3.0_wp)**(1.0/2.0)
是带有类型参数wp
的实数。很可能这是一个比其他真实更高精度的真实。
如果你写sqrt(3.0_wp)
那么这两个表达式将是同一类,我希望这两个值更加一致。
更一般地说,我不希望第二个表达式总能给出更准确的结果。
答案 1 :(得分:3)
让我们在这里剖析一下代码。这与已经给出的评论和答案一致,但我觉得还有一些可以解决的谜题。
somevar = sqrt(3.0)
这里,3.0
是一个常量,将作为默认精度存储(可能是32位浮点值。无论如何都是默认的gfortran)。因此,sqrt
会计算出该准确度的平方根。
对于somevar2
,基数定义为精确wp
,但指数不定义。
somevar2 = (3.0_wp)**(1.0/2.0)
这没有影响,因为1.0/2.0
正好存储在二进制表示中。您可以通过比较两个精度来检查:
program test
implicit none
integer, parameter :: wp = selected_real_kind(15, 307)
real :: default_prec_half
real(kind=wp) :: wp_prec_half
default_prec_half = 1.0/2.0
wp_prec_half = 1.0_wp/2.0_wp
write(*,*) default_prec_half, wp_prec_half, default_prec_half-wp_prec_half
end program test
差异的输出正好是0.
为了说明,我使用NumPy的类型化例程来检查断言:
import numpy as np
sqrt_3_32 = np.sqrt(3, dtype=np.float32)
sqrt_3_64 = np.sqrt(3, dtype=np.float64)
print(sqrt_3_32, sqrt_3_64)
使用这两个结果,我会检查somevar
和somevar2
的准确性:
In [67]: somevar = 1.7320507764816284
In [68]: somevar2 = 1.7320508075688772
In [69]: somevar-sqrt_3_64
Out[69]: -3.1087248775207854e-08
In [70]: somevar-sqrt_3_32
Out[70]: 0.0
In [72]: somevar2-sqrt_3_64
Out[72]: 0.0
In [73]: somevar2-sqrt_3_32
Out[73]: 3.1087248775207854e-08
这是由于:
somevar
是3的平方根,默认精度与32位NumPy计算的平方根3的值相同。somevar2
是3的平方根,最高wp
精度,与64位NumPy计算机的平方根3相同。注意:我可以进行比较,因为准确性在我的平台上匹配。虽然这通常是 的情况,但我提供了比较图示,您应该选择适合您的问题的准确度并在程序中一致地使用它。有关一般准则,请参阅有关浮点数的fortran90.org段落。