sqrt(x)和x **(1./2.)

时间:2017-10-16 21:00:42

标签: fortran

我刚才有一个简短的问题,这个问题是我在尝试获取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()函数默认返回单个精度变量的事实有关,还是与使用的编译器有关?

2 个答案:

答案 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)

使用这两个结果,我会检查somevarsomevar2的准确性:

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

这是由于:

  1. somevar是3的平方根,默认精度与32位NumPy计算的平方根3的值相同。
  2. somevar2是3的平方根,最高wp精度,与64位NumPy计算机的平方根3相同。
  3. 注意:我可以进行比较,因为准确性在我的平台上匹配。虽然这通常是 的情况,但我提供了比较图示,您应该选择适合您的问题的准确度并在程序中一致地使用它。有关一般准则,请参阅有关浮点数的fortran90.org段落。