Search code examples
rwhile-loopapproximation

I'm trying to make a while loop that approximates the value of cos(x) so that its to within - or + 1-e10


We must use a while loop to solve this problem (approximating the value of cos to within - or + 1-e10 ) and I believe I have all the right setup but I keep getting the error "missing value where TRUE/FALSE needed"

The question stating

A Taylor expansion of a function is an expression of the function as an infinite sum of terms. We can approximate the function by taking the first several terms of the infinite sum. The more terms we include, the better will be our approximation.

The Taylor expansion of the cosine function $cos(x)$ is: 1-((x^2)/(2!))+(x^4)/(4!)...

x = pi/2
n = 0
approximation = 1
limit = 1e-10
while(approximation < (limit*(-1)) || approximation > limit){
  (term = c(((-1)^n)*((x)^(2*n)))/factorial(2*n))
  (n  = n + 1)
  (approximation = approximation + term)
}
approximation

This is the code that I attempted but like I said it keeps giving me the error stated above.


Solution

  • Solution

    To avoid this error, simply initialize n <- 1, which aligns your terms with the Taylor series.

    Diagnosis

    When you initialize n <- 0, the series starts with 2 rather than 1, unlike the Taylor series. This causes approximation to converge wrongly on 1, by the 11th iteration.

    x = pi/2
    n = 0
    approximation = 1
    limit = 1e-10
    while(approximation < (limit*(-1)) || approximation > limit){
      (term = c(((-1)^n)*((x)^(2*n)))/factorial(2*n))
      (n  = n + 1)
      (approximation = approximation + term)
      
      # Debugging.
      cat(sep = "\n",
        sprintf("n = %3s; term = %22s; approximation = %17s", n, term, approximation)
      )
    }
    approximation
    

    As discussed below, this loops out of control until throwing an error.

    n =   1; term =                      1; approximation =                     2
    n =   2; term =      -1.23370055013617; approximation =      0.76629944986383
    n =   3; term =      0.253669507901048; approximation =      1.01996895776488
    n =   4; term =     -0.020863480763353; approximation =     0.999105477001525
    n =   5; term =   0.000919260274839426; approximation =      1.00002473727636
    n =   6; term =  -2.52020423730606e-05; approximation =     0.999999535233992
    n =   7; term =   4.71087477881817e-07; approximation =      1.00000000632147
    n =   8; term =  -6.38660308379185e-09; approximation =     0.999999999934866
    n =   9; term =   6.56596311497947e-11; approximation =      1.00000000000053
    n =  10; term =  -5.29440020073462e-13; approximation =     0.999999999999996
    n =  11; term =    3.4377391790986e-15; approximation =                     1
    n =  12; term =  -1.83599165215524e-17; approximation =                     1
    
    # ...
    
    n =  85; term =  3.51311990046563e-270; approximation =                     1
    n =  86; term = -3.01715137758328e-274; approximation =                     1
    n =  87; term =                      0; approximation =                     1
    n =  88; term =                      0; approximation =                     1
    
    # ...
    
    n = 785; term =                      0; approximation =                     1
    n = 786; term =                      0; approximation =                     1
    n = 787; term =                    NaN; approximation =                   NaN
    Error in while (approximation < (limit * (-1)) || approximation > limit) { : 
      missing value where TRUE/FALSE needed
    

    But with n <- 1 we properly obtain an approximation of -6.51335680512735e-11, which terminates on the 7th iteration:

    n =   2; term =      -1.23370055013617; approximation =     -0.23370055013617
    n =   3; term =      0.253669507901048; approximation =    0.0199689577648782
    n =   4; term =     -0.020863480763353; approximation = -0.000894522998474732
    n =   5; term =   0.000919260274839426; approximation =  2.47372763646945e-05
    n =   6; term =  -2.52020423730606e-05; approximation = -4.64766008366076e-07
    n =   7; term =   4.71087477881817e-07; approximation =  6.32146951574058e-09
    n =   8; term =  -6.38660308379185e-09; approximation = -6.51335680512735e-11
    

    Error

    As shown above, approximation converges on 1, and always remains greater than the limit of 1e-10. So the condition is always TRUE, and the while loop continues indefinitely.

    #                                     |------ TRUE -------|
    while(approximation < (limit*(-1)) || approximation > limit){
      # ...
    }
    

    But when n reaches 786, your term's numerator ((-1)^n)*((x)^(2*n)) maxes out at Infinity.

    n <- 785
    ((-1)^n)*((x)^(2*n))
    #> [1] -8.094815e+307
    
    n <- 786
    ((-1)^n)*((x)^(2*n))
    #> Inf
    

    Now your denominator factorial(2*n) has been Inf for some time, ever since n reached 86.

    n <- 85
    factorial(2*n)
    #> [1] 7.257416e+306
    
    n <- 86
    factorial(2*n)
    #> [1] Inf
    

    So until now, the overall quotient has been 0: a finite number divided by Infinity. But when n reaches 786, your term becomes Inf / Inf, which is NaN: "Not a Number".

    n <- 785
    c(((-1)^n)*((x)^(2*n)))/factorial(2*n)
    #> [1] 0
    -8.094815e+307 / Inf
    #> [1] 0
    
    n <- 786
    c(((-1)^n)*((x)^(2*n)))/factorial(2*n)
    #> [1] NaN
    Inf / Inf
    #> [1] NaN
    

    When approximation is incremented by NaN, the result is still NaN.

    1 + NaN
    #> [1] NaN
    

    With an approximation of NaN, your while conditions evaluate to NA: "Not Available".

    limit <- 1e-10
    
    NaN < (limit*(-1))
    #> [1] NA
    NaN > limit
    #> [1] NA
    
    NA || NA
    #> [1] NA
    

    In your while loop, this NA condition throws the error you encountered.

    while(NA){
      # ...
    }
    #> Error in while (NA) { : missing value where TRUE/FALSE needed