Fortran中Sin与Cos函数的精度

时间:2018-01-26 08:46:24

标签: floating-point fortran precision gfortran

考虑代码,

PROGRAM TRIG_TEST
IMPLICIT NONE

DOUBLE PRECISION, PARAMETER :: PI=4.D0*DATAN(1.0D)

print *, sin(PI/2.0), cos(PI/2.0)

END PROGRAM TRIG_TEST

使用gfortran输出进行编译,

1.0000000000000000 6.1232339957367660E-017

我知道通常的浮点问题但是sin函数是否相同为1,但cos函数不一样为零?

2 个答案:

答案 0 :(得分:4)

以下假设double是IEEE 754基本64位二进制格式。三角函数例程的常见实现不如格式要求准确。但是,对于这个答案,让我们假设它们可以返回最准确的结果。

π无法在double中准确表示。最接近的可能值是884279719003555/281474976710656或3.141592653589793115997963468544185161590576171875。我们称之为 p

p / 2的正弦值约为1 - 1.8747•10 -33 。在double中可以表示的两个值是1和0.99999999999999988897769753748434595763683319091796875,其大约是1 - 1.11•10 -16 。它们中的较近者是1,因此p/2的正弦值的最接近的可表示值恰好为1.

p / 2的余弦值约为6.123233995736765886•10 -17 。在double中可以表示的最接近的值是6.12323399573676603586882014729198302312846062338790031898128063403419218957424163818359375•10 -17

因此,您观察到的结果是与真实数学值最接近的可能结果。

答案 1 :(得分:1)

让我们看看为什么sin的结果给出了1.在您的代码中

DOUBLE PRECISION, PARAMETER :: PI=4.D0*DATAN(1.0D0)

这是pi值的浮点近似值。它可能非常接近实际价值,但它并非如此。此外,sin函数在评估罪时有错误。我们希望这些都是小错误。

我们期望cos(pi / 2)的值为零。您的浮点计算cos(PI/2)在数学答案中的误差约为6.1232339957367660E-017。让我们假设你的罪计算具有相似的误差幅度。

现在看看epsilon(0d)的价值。这是1d0+epsilon(0d0)不等于1d0的最小数字。假设误差远小于此数字,在模型中(您报告" ~2.2e-16")。

因此,1是与浮点计算的实际值最接近的可表示数字。

考虑一下程序

  use, intrinsic :: iso_fortran_env, only : real128, real64
  implicit none

  real(real64), parameter :: PI=4.D0*ATAN(1._real64)
  real(real128), parameter :: PI_approx = PI   ! Not 4*ATAN(1._real128)

  print *, SIN(PI/2), COS(PI/2)
  print *, SIN(PI_approx/2), COS(PI_approx/2)

end

这计算(可能)你PI/2的罪,但精度更高(使用相同的pi近似值)。我的编译器在第二种情况下报告的值与1不同,但差异远小于epsilon(0._real64)

作为样式点,通常最好避免datan并使用通用atandouble precision也可以由适当的种类参数替换。这些都显示在我上面的程序中。