如何在Fortran获得泰勒系列正弦

时间:2017-03-23 15:34:42

标签: loops fortran expansion sine

我的目标是找到一个Maclaurin系列的正弦,其中程序返回3个东西:用户提供的角度的扩展,精度为10 ^ - 15,第一个术语丢弃以获得该精度和从函数sine(x)计算的正弦值。这是我的计划:

          program serie de taylor seno
             implicit none 
             integer*8  N, i, j
             real*8  serie, x, xrad
             real*8 xtest, pi, senx, func, ten, fat
             write(*,*)"Choose en angle in degrees"
             read(5,*) x
             fat = 1.d0
             ten = 10**(-15)
             senx = 0.d0
             pi= datan2(0.d0,-1.d0)
             xrad = (x*pi)/180.d0
             xtest = (x*pi)/180.d0
             func =dsin(xtest)
             i = 0
             do while (serie .ge. ten)
                   do j = 1, 2*i +1
                      fat = fat*j
                   end do
                   N = (2*i)+1
                   serie = (((-1)**i)*(xrad**N))/fat
                   senx = senx + serie
                   i = i + 1
                   fat = 1
             end do
             write(*,*)senx
             write (*,*) i
             write(*,*)func
          end program serie de taylor seno

我的问题是do循环只对任何角度运行两次。我做错了什么?

1 个答案:

答案 0 :(得分:0)

总的来说,你有正确的想法,但有几个问题。在尝试像这样进行调试时,您应该在每次循环迭代期间包含详细输出,以尝试准确跟踪发生的情况。我发现的问题是:

  • 您必须将容差与serie幅度进行比较。泰勒系列的罪包括否定词,第一个否定词是导致你的循环退出(每次都是第二个)。
  • 您设置的容差实际为0. 10**(-15)仅包含整数,因此答案将被计算为整数。使用10.**(15),或者更好1.e-15
  • 您的计划名称不能包含空格,至少对于我的gfortranifort版本而言。编辑:显然这是因为我将你的代码复制成自由格式,谢谢francescalus
  • 为确保首次输入while循环,在评估任何系列之前,请将serie定义为某个较大的值。

此外,我还有以下其他建议:

  • 请勿使用非便携式种类修饰符,例如real*8。根据系统的不同,您将获得不同的答案。选择您的类型,例如REAL_SELECTED_KINDREAL64。因为您要求给定的容忍度,所以最好的办法就是要求对您的实物进行容忍。
  • 同样,不要使用datandsin - 使用泛型函数将是与类型无关的,并将评估它给出的变量的精度。
  • 不是在循环结束时将阶乘设置为1,而是需要单独初始化,只需在循环之前设置它以计算阶乘。
  • 这里不需要8字节整数。
  • 仅仅因为最后一项小于公差并不一定意味着系列会收敛到该公差。许多术语的总和可能会给你一个问题,虽然这可能不是一个快速收敛的罪恶系列的问题。
  • 单位5通常是标准输入,但并非总是如此。 read(*,...将连接到标准输入,或使用INPUT_UNIT中的ISO_FORTRAN_ENV
  • xteste用于什么?它应该是xtest吗?
  • 将不应更改的变量(例如pi和容差)设置为参数。
  • 评论您的代码!它现在不太可读。考虑一下如果你在一年内回归它会有什么想法。我还保留了用于检查代码是否正常工作的调试输出。这种输出有利于初学者学习。

总而言之,您的固定程序如下:

program taylor
   implicit none
   integer, parameter :: wp = selected_real_kind(15,300)
   real(wp), parameter :: pi = atan2(0._wp,-1._wp)
   real(wp), parameter :: ten = 1.e-15_wp

   integer :: N, i, j
   real(wp) :: serie, x, xrad
   real(wp) :: xtest, senx, func, fat

   ! -- Initialization
   write(*,*) "Choose an angle in degrees"
   read(*,*) x

   senx = 0._wp
   xrad = (x*pi)/180._wp
   xtest = (x*pi)/180_wp

   func = sin(xtest)

   ! -- Main loop
   i = 0
   serie = huge(serie)
   do while (abs(serie) .ge. ten)

      ! -- Compute factorial
      fat = 1._wp
      do j=1,2*i+1
         fat = fat*j
      enddo

      ! -- Evaluate i-th term in series
      N = (2*i)+1
      serie = (((-1)**i)*(xrad**N))/fat
      senx = senx + serie
      i = i + 1

      write(*,*) 'Completed iteration ', i
      write(*,*) 'serie, senx: ', serie, senx
   enddo

   write(*,*) 'Completed while loop'

   write(*,*) 'senx: ', senx
   write (*,*) 'i: ', i
   write(*,*) 'func: ', func

end program taylor

这为我提供了正确的输出:

mach5% gfortran main.f90 && ./a.out
 Choose an angle in degrees
30
 Completed iteration            1
 serie, senx:   0.52359877559829882       0.52359877559829882     
 Completed iteration            2
 serie, senx:   -2.3924596203935038E-002  0.49967417939436376     
 Completed iteration            3
 serie, senx:    3.2795319442867078E-004  0.50000213258879245     
 Completed iteration            4
 serie, senx:   -2.1407197692357951E-006  0.49999999186902322     
 Completed iteration            5
 serie, senx:    8.1512566573875745E-009  0.50000000002027989     
 Completed iteration            6
 serie, senx:   -2.0315575399030637E-011  0.49999999999996431     
 Completed iteration            7
 serie, senx:    3.5702758612702185E-014  0.50000000000000000     
 Completed iteration            8
 serie, senx:   -4.6610066605152958E-017  0.49999999999999994     
 Completed while loop
 senx:   0.49999999999999994     
 i:            8
 func:   0.49999999999999994 

关于将整数值分配给实数的最后注释,例如fat=1._wp。简单地说fat=1fat=1.就是一样的。但是,使用相同的表示法(例如fat=1.5)指定非整数值会导致精度损失,因此正确的表示法为fat=1.5_wp。所以我倾向于在任何地方保持我的符号一致,并且为了简单起见使用fat=1._wp