Dennis
Dennis

Reputation: 533

Fibonacci Sequence in R

I am a new R user and have very limited programming experience, hence my question and poorly written code.

I was assigned a problem where I had to use a while loop to generate the numbers of the Fibonacci sequence that are less than 4,000,000 (the Fibonacci sequence is characterized by the fact that every number after the first two is the sum of the two preceding ones).

Next, I had to compute the sum of the even numbers in the sequence that was generated.

I was successful with my response, however, I don't think the code is written very well. What could I have done better?

> x <- 0
> y <- 1
> z <- 0
if (x == 0 & y == 1) {
  cat(x)
  cat(" ")
  cat(y)
  cat(" ")
    while (x < 4000000 & y < 4000000) {
    x <- x + y
    cat(x)
    cat(" ")
    if (x %% 2 == 0) {
        z <- x + z
    }
    y <- x + y
    cat(y)
    cat(" ")
    if (y %% 2 == 0) {
        z <- y + z
    }
  }
}

0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765 10946 17711 28657 46368 75025 121393 196418 317811 514229 832040 1346269 2178309 3524578 5702887 9227465

cat(z)

4613732

Upvotes: 3

Views: 16393

Answers (4)

LeoLetItRip
LeoLetItRip

Reputation: 1

This is how I would do it. First, I defined a global variable i to include the first two elements of the Fibonacci series. Then at the end, I re-assigned the global variable to its initial value (i.e. 1). If I don't do that, then when I call the function fib(0,1) again, the output is incorrect as it calls the function with the last value of i. It's also important to do return() to ensure it doesn't return anything in the else clause. If you don't specify return(), the final output will be 1, instead of the Fibonacci series.

Please note the series only goes till the number 13 (z<14) obviously you can change that to whatever you want. May also be a good option to include this as the third argument of the function, something like fib(0,1,14). Try it out!

i <<- 1
fib <- function(x,y){
  z <- x+y
  if(z<14){
    if (i==1){
      i <<- i+1
      c(x,y,z,fib(y,z))
    }
    else c(z, fib(y,z))
  }
  else {
    i <<- 1
    return()
  }
}

a <- fib(0,1)
a

Upvotes: 0

erocoar
erocoar

Reputation: 5893

First of all, cat comes with a sep argument. You can do cat(x, y, sep = " ") rather than using 3 lines for that.

Secondly, when you call while (x < 4000000 & y < 4000000) note that y will always be greater than x because it is the sum of the last x and y ... so it should suffice to check for y < 4000000 here.

For the while loop, you could also use a counter - might be more intuitive. Indexing in R isn't that fast though

fib <- c(0, 1)
i <- 2
while (fib[i] < 4000000) {
  fib <- c(fib, fib[i-1] + fib[i])
  i <- i + 1
}

sum(fib[fib %% 2 == 0]) 

If you don't necessarily need the while, you could also approach it via recursion

fib <- function(x, y) {
  s <- x + y
  c(s, if (s < 4000000) fib(y, s))
}

f <- fib(0, 1)
sum(f[f %% 2 == 0])

Upvotes: 3

Michael Lugo
Michael Lugo

Reputation: 377

First, there's no need o explicitly print everything out.

Second, it's more idiomatic in R to make a vector of the Fibonacci numbers and then sum. If you don't know an explicit closed form for the Fibonacci numbers, or if you've been told not to use this, then use a loop to create the list of Fibonacci numbers.

So to construct the list of Fibonacci numbers (two at a time) you can do

x <- 0
y <- 1
fib <- c()
while (x < 4000000 & y < 4000000){
  x <- x + y
  y <- x + y
  fib = c(fib, x, y)
}

This will give you a vector of Fibonacci numbers, containing all those less than 4000000 and a few more (the last element is 9227465).

Then run

sum(fib[fib %% 2 == 0 & fib < 4000000])

to get the result. This returns 4613732, like your code does. The subsetting operator [], when you put a logical condition inside it, will output just those numbers which satisfy the logical condition -- in this case, that they're even and less than 4000000.

Upvotes: 1

quant
quant

Reputation: 4482

I am using the closed form of the fibonacci sequence as found here

fib = function(n) round(((5 + sqrt(5)) / 10) * (( 1 + sqrt(5)) / 2) ** (1:n - 1))

numbers <- 2
while (max(fib(numbers)) < 4000000){ # try amount of numbers while the maximum of the sequence is less than 4000000
  sequence <- fib(numbers) # here the sequence that satisfies the "4000000 condition will be saved"
  numbers <- numbers + 1 # increase the amount of numbers
}
total_sum <- sum(sequence[sequence%%2==0]) # summing the even numbers

Upvotes: 0

Related Questions