I'm trying to convert a while loop to a recursion.
I know the while loop is more efficient, but I'm trying to understand how to convert a for/while loop to recursion, and recursion to a for/while/if loop.
my function as I'm using a while loop:
harmon_sum <- function(x){
n <- 1
sum <- 0
while (sum < x)
{
sum <- sum + (1/n)
n <- (n +1)
}
return(n)
}
This function takes some numeric value, suppose x=2, and returns the number of objects for the harmonic sum that you need to sum up in order to create a greater number then x. (for x=2, you'd need to sum up the first 5 objects of the harmonic sum)
[![harmonic sum][1]][1]
**example**: `harmon_sum <- function(x){
n <- 1
sum <- 0
while (sum < x)
{
sum <- sum + (1/n)
print(sum)
n <- (n +1)
print(n)
}
return(n)
}
> harmon_sum(x =2)
[1] 1
[1] 2
[1] 1.5
[1] 3
[1] 1.833333
[1] 4
[1] 2.083333
[1] 5
[1] 5`
my version for the recursive function:
harmon_sum2 <- function(x, n =1){
if( x<= 0){
return(n-1)
}
else {
x <- (x- (1/(n)))
harmon_sum2(x, n+1)
}
}
which returns me the wrong answer.
I'd rather find a solution with just one variable (x), instead of using two variables (x, n), but I couldn't figure a way to do that.
It seems to me that if you change return(n-1) to return(n) you do get the right results.
harmon_sum2 <- function(x, n=1){
if( x <= 0){
return(n)
}
else {
x <- (x- (1/(n)))
harmon_sum2(x, n+1)
}
}
harmon_sum(2)
[1] 5
harmon_sum2(2)
[1] 5
harmon_sum(4)
[1] 32
harmon_sum2(4)
[1] 32
Your function needs to know n. If you don't want to pass it, you need to store it somewhere where all functions on the call stack can access it. For your specific case you can use sys.nframe instead:
harmon_sum2 <- function(x){
if( x<= 0){
return(sys.nframe())
}
else {
x <- (x- (1/(sys.nframe())))
harmon_sum2(x)
}
}
harmon_sum(8)
#[1] 1675
harmon_sum2(8)
#[1] 1675
However, this doesn't work if you call your function from within another function:
print(harmon_sum2(8))
#[1] 4551
Another alternative is the approach I demonstrate in this answer.
Related
I had to write a R function that will accept a vector input and then raise each element of that vector x to the power of y indicated. But besides that I need to print each exponentiated element and the summed valued of them . The sum part I got , but how do I print each exponentiated value as well if the function will only return one object ? HELP please.
( I had to use for loop as it was specified at the question)
sum.power <- function(x,y=2) {
n <- c(x)
x <- length(n)
S <- 0
for (i in 1:x){
S<- S+n[i]^y
}
return(S)
}
sum.power (3:10,5)
We don't need a loop. The ^ accepts a vector as input. Once that is done, return multiple outputs as a list
sum.power <- function(x, y = 2) {
x1 <- x^y
list(x1, sum(x1))
}
sum.power(3:10, 5)
#[[1]]
#[1] 243 1024 3125 7776 16807 32768 59049 100000
#[[2]]
#[1] 220792
If we need to use the OP's, function, create another vector for holding the values of the ^ and return a list
sum.power <- function(x,y=2) {
n <- x
x <- length(n)
S <- 0
E <- numeric(x)
for (i in seq_len(x)){
E[i] <- n[i]^y
S <- S+ E[i]
}
return(list(E, S))
}
sum.power (3:10,5)
#[[1]]
#[1] 243 1024 3125 7776 16807 32768 59049 100000
#[[2]]
#[1] 220792
In Wolfram Mathematica, there is function NestList[f,x,n] that produces vector output of length n+1 with multiple application of function f on variable x. See documentation.
Is there something similar in R?
Executing do.call would make the same computations multiple times.
Example (reaction to USER_1's suggestion):
foo <- function(x) {x+1}
map(0, foo)
# [[1]]
# [1] 1
Just write one. Such a function has to loop anyway (rescursion is not advisable if n can get large).
NestList <- function(f, x, n) {
stopifnot(n > 0)
res <- rep(x, n + 1)
if (n == 1L) return(res)
for (i in seq_len(n)) res[i+1] <- f(res[i])
res
}
NestList(function(x) x^2, 2, 5)
#[1] 2 4 16 256 65536 4294967296
This is a homework problem. I am brand new to R just FYI
This is the problem:
R does have a built-in constant pi. Here we will use random numbers to estimate the value of
π. Create a function approx.pi() that takes a parameter N. Inside this function, code the
following steps:
(1) set j equal to 0.
(2) start a for loop with counter i that repeats N times.
(3) Inside the for loop, generate two random uniform numbers x and y between -1 and +1
using runif().
(4) If x^2 + y^2 < 1 then add one to j.
(5) End the for loop.
(6) Return the estimate of π which is 4×j/N
and this is the code I have:
approx.pi <- function(N) {
j <- 0
for (i in N) {
x <- runif(1,-1,1)
y <- runif(1,-1,1)
if (x^2+y^2< 1) {
j=j+1
}
}
return(4*j/N)
}
approx.pi(N=5)
I am getting some number values returned but they are no where near pi can anyone help? Thank you.
This code will only run for 1 value i = N.
for (i in N) {}
You need to change to
for (i in 1:N){}
I have tried edited code and got the output
approx.pi <- function(N) {
j <- 0
for (i in 1:N) {
x <- runif(1,-1,1)
y <- runif(1,-1,1)
if (x^2+y^2< 1) {
j=j+1
}
}
return(4*j/N)
}
Here is my output. (you use 5 is too small).
> approx.pi(5000)
[1] 3.188
> approx.pi(5000)
[1] 3.1488
> approx.pi(5000)
[1] 3.1344
> approx.pi(5000)
[1] 3.1672
> approx.pi(5000)
[1] 3.1632
> approx.pi(5000)
[1] 3.1152
I've been set a question on the Fibonacci Sequence and although I've been successful in doing the sequence, I haven't been as lucky summing the even terms up (i.e. 2nd, 4th, 6th... etc.) My code is below as well as the part of the question I am stuck on. Any guidance would be brilliant!
Question:
Write a function which will take as an input x and y and will return either the sum of the first x even Fibonacci numbers or the sum of even Fibonacci numbers less than y.
That means the user will be able to specify either x or y but not both.
You have to return a warning if someone uses both numbers (decide
on the message to return)
Code:
y <- 10
fibvals <- numeric(y)
fibvals[1] <- 1
fibvals[2] <- 1
for (i in 3:y) {
fibvals[i] <- fibvals[i-1]+fibvals[i-2]
if (i %% 2)
v<-sum(fibvals[i])
}
v
To get you started since this sounds like an exercise.
I would split your loop up into steps rather than do the summing within the loop with an if statement. Since you already have the sequence code working, you can just return what is asked for by the user. The missing function would probably help you out here
f <- function(x, y) {
if (missing(y)) {
warning('you must give y')
y <- 10
}
fibvals <- numeric(y)
fibvals[1] <- 1
fibvals[2] <- 1
for (i in 3:y) {
fibvals[i] <- fibvals[i-1]+fibvals[i-2]
}
evens <- fibvals %% 2 == 0
odds <- fibvals %% 2 != 0
if (missing(x)) {
return(sum(fibvals[evens]))
} else return(fibvals)
}
f(y = 20)
# [1] 3382
f(10)
# [1] 1 1 2 3 5 8 13 21 34 55
# Warning message:
# In f(10) : you must give y
Problem
Find the sum of all numbers below 1000 that can be divisible by 3 or 5
One solution I created:
x <- c(1:999)
values <- x[x %% 3 == 0 | x %% 5 == 0]
sum(values
Second solution I can't get to work and need help with. I've pasted it below.
I'm trying to use a loop (here, I use while() and after this I'll try for()). I am still struggling with keeping references to indexes (locations in a vector) separate from values/observations within vectors. Loops seem to make it more challenging for me to distinguish the two.
Why does this not produce the answer to Euler #1?
x <- 0
i <- 1
while (i < 100) {
if (i %% 3 == 0 | i %% 5 == 0) {
x[i] <- c(x, i)
}
i <- i + 1
}
sum(x)
And in words, line by line this is what I understand is happening:
x gets value 0
i gets value 1
while object i's value (not the index #) is < 1000
if is divisible by 3 or 5
add that number i to the vector x
add 1 to i in order (in order to keep the loop going to defined limit of 1e3
sum all items in vector x
I am guessing x[i] <- c(x, i) is not the right way to add an element to vector x. How do I fix this and what else is not accurate?
First, your loop runs until i < 100, not i < 1000.
Second, replace x[i] <- c(x, i) with x <- c(x, i) to add an element to the vector.
Here is a shortcut that performs this sum, which is probably more in the spirit of the problem:
3*(333*334/2) + 5*(199*200/2) - 15*(66*67/2)
## [1] 233168
Here's why this works:
In the set of integers [1,999] there are:
333 values that are divisible by 3. Their sum is 3*sum(1:333) or 3*(333*334/2).
199 values that are divisible by 5. Their sum is 5*sum(1:199) or 5*(199*200/2).
Adding these up gives a number that is too high by their intersection, which are the values that are divisible by 15. There are 66 such values, and their sum is 15*(1:66) or 15*(66*67/2)
As a function of N, this can be written:
f <- function(N) {
threes <- floor(N/3)
fives <- floor(N/5)
fifteens <- floor(N/15)
3*(threes*(threes+1)/2) + 5*(fives*(fives+1)/2) - 15*(fifteens*(fifteens+1)/2)
}
Giving:
f(999)
## [1] 233168
f(99)
## [1] 2318
And another way:
x <- 1:999
sum(which(x%%5==0 | x%%3==0))
# [1] 233168
A very efficient approach is the following:
div_sum <- function(x, n) {
# calculates the double of the sum of all integers from 1 to n
# that are divisible by x
max_num <- n %/% x
(x * (max_num + 1) * max_num)
}
n <- 999
a <- 3
b <- 5
(div_sum(a, n) + div_sum(b, n) - div_sum(a * b, n)) / 2
In contrast, a very short code is the following:
x=1:999
sum(x[!x%%3|!x%%5])
Here is an alternative that I think gives the same answer (using 99 instead of 999 as the upper bound):
iters <- 100
x <- rep(0, iters-1)
i <- 1
while (i < iters) {
if (i %% 3 == 0 | i %% 5 == 0) {
x[i] <- i
}
i <- i + 1
}
sum(x)
# [1] 2318
Here is the for-loop mentioned in the original post:
iters <- 99
x <- rep(0, iters)
i <- 1
for (i in 1:iters) {
if (i %% 3 == 0 | i %% 5 == 0) {
x[i] <- i
}
i <- i + 1
}
sum(x)
# [1] 2318