Project Euler #2 in R - r

I'm a novice at programming and I've been trying Project Euler to learn more about R.
The question that's stumping me is as follows:
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89
By considering the terms in the Fibonacci sequence whose values do not exceed 4 million, find the sum of the even valued terms.
I've started to tackle this problem by setting the first couple numbers in the sequence:
num <- c(1, 2)
Next I'm trying to create a function fib() that will sum the last two numbers in num and append them to the vector.
My first attempt has been to do the following:
num <- c(1, 2)
fib <- function(x) {
sum <- sum(tail(x,2))
while (sum <= 4e6) {
x <- append(x, sum)
return(x)
}
}
But when I run this I only get one additional Fibonacci number:
> fib(num)
[1] 1 2 3
In turn, I tried moving return(x):
num <- c(1, 2)
fib <- function(x) {
sum <- sum(tail(x,2))
while (sum <= 4e6) {
x <- append(x, sum)
}
return(x)
}
But this seems to only create an infinite loop.
As a caveat, I'm comfortable summing the even-valued terms with a modulo and I'll do this after I work out this particular issue.
Can you point out where I'm going wrong with my code? (If you could give me a bump in the right direction without providing an explicit solution that would be even more appreciated.)
Thanks to #Minnow and #blakeoft for helping me to get a handle on this. Here's what I ended up doing to solve this problem:
SPOILER ALERT
num <- c(1, 2)
fib <- function(x) {
last2 <- sum(tail(x,2))
while (last2 <= 4000000) {
x <- append(x, last2)
last2 <- sum(tail(x,2))
}
return(x)
}
I won't include the last bit with the modulo since I want to keep the answer specific to the initial question.

Is this a language-specific problem? You don't really need a function, just three variables say prev, curr and next. Preload the first two and prime the even values' sum. You know how to set the value of next, then process it and shove the values back through your history.
You didn't want a specific answer, but now you have accepted one, this is what I meant - it's not r but it shows how simple it can be.
int sum = 2;
int prev = 1;
int curr = 2;
int next = 0;
while (next < 4000000) {
next = prev + curr;
if (next % 2 == 0)
sum += next;
prev = curr;
curr = next;
}
printf ("%d", sum);

Without giving it away:
Walk through your loop and see if you can figure out the expected output. You're close, but the sequence of events is not going to yield what you expect.

Related

Does anyone know how I can make my code run faster?

I am trying to calculate Sigma(n=0 to infinity) (−1)^n/(n + 1) as accurately as possible. But my code takes forever and I am not able to see whether my answer is right. Does anyone know how I can make my code faster? The sum is supposed to converge to log(2). My idea is that f(n) will eventually become a very small number (less than 2^-52) and a time would come when R would consider sum = sum + f(n) and that's when I'd want the code to stop running. But clearly, that doesn't seem to work and my code takes forever to run and at least to me, it doesn't seem to ever stop.
f <- function(n)
return(((-1)^(n))/(n+1))
s <- function(f){
sum <- 0
n <- 0
while(sum != sum + f(n)) {
sum <- sum + f(n)
n <- n + 1
}
return(c(sum, n))
}
s(f)
library(Rcpp)
cppFunction("
List s(int max_iter) {
double sum = 0;
double sum_prec=NA_REAL;
double n = 0;
for (;sum != sum_prec && n < max_iter;n++) {
sum_prec = sum;
sum+=pow(-1,n)/(n+1);
}
return List::create(
_[\"sum\"] = sum,
_[\"iterations\"] = n,
_[\"precision\"] = sum-sum_prec
) ;
}")
test <- s(100000000)
test
When you use a huge number of subsequent iterations you know that R is not appropriated. However C++ functions are very easy to use within R. You can do something like that by example. The function needs a max of iterations and returns a list with your sum, the number of iterations and the precision.
EDIT : By precision I only do sum-sum_prec so this is not the real interval.
EDIT 2 : I let the sum != sum_prec for the example but if you don't have a supercomputer you're not supposed to see the end lol
EDIT 3 :
Typically, a fast R base solution would be something like :
base_sol <- function(n_iter) {
v <- seq_len(n_iter)
v <- (-1L)^(v-1L)/v
list(
sum = sum(v),
iterations = n_iter,
precision = v[length(v)]
)
}
Which is only 1.5 times slower than c++, which is pretty fast for an interpreted language, but has the con of loading every member of the sum in ram (but then, R is made for stats not for calculating things at 2^-52)

Dynamic Programming: Child running up a staircase

I'm starting to practice Dynamic Programming and I just can't wrap my head around this question:
Question:
A child is running up a staircase with n steps and can hop either 1 step, 2 steps, or 3 steps at a time. Implement a method to count how many possible ways the child can run up the stairs.
The solution from the cracking the coding interview book is like this:
"If we thought about all the paths to the nth step, we could just build them off the paths to the three previous steps. We can get up to the nth stop by any of the following:
Going to the (n-1) step and hopping 1 step
Going to the (n-2) step and hopping 2 steps
Going to the (n-3) step and hopping 3 steps"
Therefor to find the solution you just add the number of these path together !
That's what loses me ! Why isn't the answer like this: add number of those paths then add 3 ? Since if you are on step n-1 or n-2 or n-3, there are 3 ways to get the nth step? I understand that if you write down the answers for the first 4 bases cases (assuming that n=0 returns 1) You can see the fibonacci-like pattern. But you may not also see it so it's difficult.
And then they came up with this code:
public static int countWaysDP(int n, int[] map) {
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (map[n] > -1)
return map[n];
else {
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map);
return map[n]; }
}
So my second question. How does it return 1 when n == 0. Even if I accept that fact, I still can't figure out a way to solve it if I return 0 when n == 1.
Hope this makes sense.
Thank you
Here is how I wrapped my head around this-
From the book -
On the very last hop, up to the nth step, the child could have
done either a single, double, or triple step hop. That is, the last
move might have been a single step hop from step n-1, a double
step hop from step n-2, or a triple step hop from n-3. The
total number of ways of reaching the last step is therefore the sum of
the number of ways of reaching each of the last three steps
You are correctly contemplating -
Why isn't the answer like this: add number of those paths then add 3 ?
Since if you are on step n-1 or n-2 or n-3, there are 3 ways to get
the nth step?
The problem with such a base case is that it will be applicable only if n >= 3. You clearly will not add 3 if there are only 2 steps.
Let's break down the individual cases and understand what exactly is the base case here.
n=0
There are no stairs to climb.
Total number of ways = 0
n=1
Total number of ways = 1StepHop from (n-1)
Number of ways to do 1StepHop from Step 0(n-1) = 1
Total number of ways = 1
n=2
Total number of ways = 2StepHop from (n-2) + 1StepHop from (n-1)
Number of ways to do 2StepHop to reach Step 2 from Step 0(n-2) = 1
Number of ways to do 1StepHop to reach Step 2 from Step 1(n-1) = 1 (Previous answer for n=1)
Total number of ways = 1 + 1 = 2
n=3
Total number of ways = 3StepHop from (n-3) + 2StepHop from (n-2) + 1StepHop from (n-1)
Number of ways to do 3StepHop to reach Step 3 from Step 0(n-3) = 1
Number of ways to do 2StepHop to reach Step 3 from Step 1(n-2) = 2 (From previous answer for n = 2)
Number of ways to do 1StepHop to reach Step 3 from Step 2 = 1 (From previous answer for n=1)
Total number of ways = 1 + 2 + 1 = 4
Observation -
As you can see from above, we are correctly accounting for the last step in each case. Adding one for each of -> 1StepHop from n-1, 2StepHop from n-2 and 3StepHop from n-3.
Now looking at the code, the case where we return 1 if n==0 is a bit counter-intuitive since we already saw that the answer should be 0 if n==0. -
public static int countWaysDP(int n, int[] map) {
if (n < 0)
return 0;
else if (n == 0)
return 1; <------------- this case is counter-intuitive
else if (map[n] > -1)
return map[n];
else {
map[n] = countWaysDP(n - 1, map) + countWaysDP(n - 2, map) + countWaysDP(n - 3, map);
return map[n];
}
From the observation, you can see that this counter intuitive case of n==0 is actually the one which is accounting for the final step - 1StepHop from n-1, 2StepHop from n-2 and 3StepHop from n-3.
So hitting n==0 case makes sense only during recursion - which will happen only when the initial value of n is greater than 0.
A more complete solution to this problem may have a driver method which handles that case outside of the core recursive algorithm -
int countWays(int n) {
if (n <= 0 ) return 0;
int[] map = new int[n+1];
for(int i = 0; i<n+1; i++){
map[i] = -1;
}
return countWaysDP(n, map);
}
Hope this is helpful.
You can find the solution on
https://github.com/CrispenGari/Triple-Step-Algorithim/blob/master/main.cpp .
int count_Ways(int n){
if(n<0){
return 0;
}else if(n==0){
return 1;
}else{
return count_Ways(n-1) +count_Ways(n-2) + count_Ways(n-3);
}
}
int main(){
cout<<"Enter number of stairs: ";
int n;
cin>>n;
cout<<"There are "<< count_Ways(n)<<" possible ways the child can run up
thestairs."<<endl;
return 0;
}

create binary search tree from sorted list in R

I am practicing recursion and tried to implement a BST from a linked list.
I tried to translate the solution from here to R:
Create Balanced Binary Search Tree from Sorted linked list
Given a vector vec I want to find the BST, for example:
0
/ \
-3 9
/ /
-10 5
vec <- c(-10,-3,0,5,9)
This is my attempt to solve this recursively, but it does not work:
tobt <- function(vec, start, end) {
if (start > end) return(NA)
mid <- start + (end - start) / 2
left <- tobt(vec, start, mid-1)
right <- tobt(vec, mid+1, end)
return(c(left, right))
}
tobt(vec, 1, 5)
Where is my mistake?
You need to use structure that allow build trees, for example list. Second problem is ignoring parent that filled a node of tree with number.
A possible variant of your function:
tobt <- function(vec, start, end) {
if (start > end) return(NULL)
mid <- start + (end - start) %/% 2
left <- tobt(vec, start, mid-1)
parent <- vec[mid]
right <- tobt(vec, mid+1, end)
return(list(left=left, node = parent, right=right))
}

Iteration in R, weird result with for-loop

I'm writing some code in R in order to determine an optimal estimator for ai given any tolerance. So far, I've come up with this:
iter<- function (ai, k, tolerance){
at = ai*(1-ai^2*R[k]^ai*(log(R[k]))^2/(1-R[k]^ai)^2)/
(1 - (ai^2*R[k]^ai*(log(R[k]))^2)/(1-R[k]^ai)^2 + ai*(H(k)
- 1/ai - R[k]^ai*log(R[k])/(1-R[k]^ai)))
while((at-ai) > tolerance) {
ai = at
at = ai*(1-ai^2*R[k]^ai*(log(R[k]))^2/(1-R[k]^ai)^2)/
(1 - (ai^2*R[k]^ai*(log(R[k]))^2)/(1-R[k]^ai)^2 + ai*(H(k)
- 1/ai - R[k]^ai*log(R[k])/(1-R[k]^ai)))
a0 = at
}
return(at)
}
x<- iter(ai = H(k), k, tolerance = 0.000001)
where R and H are known variables for every k and also an initial estimator for ai is known, namely H(k). This code works fine for any value of k, for example,
x<- iter(ai = H(k), 21, tolerance = 0.000001)
gives a good result. However, my problem is, that when I try to embed this in a for-loop (I actually want a vector x[k] where every iteration for k is calculated), i.e. :
for (k in seq (along = 1: (n-1)){
x<- iter(ai = H(k), 21, tolerance = 0.000001)
}
this code doesn't give me a vector, but instead it gives one value for x. That doesn't make much sense to me, as I'm trying to assign a value to x for every possible k. What am I missing here?
As always, any help would be dearly appreciated.
Since you want a vector, x should be a vector.
x<-numeric(n-1)
for (k in seq (along = 1: (n-1)){
x[k]<- iter(ai = H(k), 21, tolerance = 0.000001)
}

Speeding up Julia's poorly written R examples

The Julia examples to compare performance against R seem particularly convoluted. https://github.com/JuliaLang/julia/blob/master/test/perf/perf.R
What is the fastest performance you can eke out of the two algorithms below (preferably with an explanation of what you changed to make it more R-like)?
## mandel
mandel = function(z) {
c = z
maxiter = 80
for (n in 1:maxiter) {
if (Mod(z) > 2) return(n-1)
z = z^2+c
}
return(maxiter)
}
mandelperf = function() {
re = seq(-2,0.5,.1)
im = seq(-1,1,.1)
M = matrix(0.0,nrow=length(re),ncol=length(im))
count = 1
for (r in re) {
for (i in im) {
M[count] = mandel(complex(real=r,imag=i))
count = count + 1
}
}
return(M)
}
assert(sum(mandelperf()) == 14791)
## quicksort ##
qsort_kernel = function(a, lo, hi) {
i = lo
j = hi
while (i < hi) {
pivot = a[floor((lo+hi)/2)]
while (i <= j) {
while (a[i] < pivot) i = i + 1
while (a[j] > pivot) j = j - 1
if (i <= j) {
t = a[i]
a[i] = a[j]
a[j] = t
}
i = i + 1;
j = j - 1;
}
if (lo < j) qsort_kernel(a, lo, j)
lo = i
j = hi
}
return(a)
}
qsort = function(a) {
return(qsort_kernel(a, 1, length(a)))
}
sortperf = function(n) {
v = runif(n)
return(qsort(v))
}
sortperf(5000)
The key word in this question is "algorithm":
What is the fastest performance you can eke out of the two algorithms below (preferably with an explanation of what you changed to make it more R-like)?
As in "how fast can you make these algorithms in R?" The algorithms in question here are the standard Mandelbrot complex loop iteration algorithm and the standard recursive quicksort kernel.
There are certainly faster ways to compute the answers to the problems posed in these benchmarks – but not using the same algorithms. You can avoid recursion, avoid iteration, and avoid whatever else R isn't good at. But then you're no longer comparing the same algorithms.
If you really wanted to compute Mandelbrot sets in R or sort numbers, yes, this is not how you would write the code. You would either vectorize it as much as possible – thereby pushing all the work into predefined C kernels – or just write a custom C extension and do the computation there. Either way, the conclusion is that R isn't fast enough to get really good performance on its own – you need have C do most of the work in order to get good performance.
And that's exactly the point of these benchmarks: in Julia you never have to rely on C code to get good performance. You can just write what you want to do in pure Julia and it will have good performance. If an iterative scalar loop algorithm is the most natural way to do what you want to do, then just do that. If recursion is the most natural way to solve the problem, then that's ok too. At no point will you be forced to rely on C for performance – whether via unnatural vectorization or writing custom C extensions. Of course, you can write vectorized code when it's natural, as it often is in linear algebra; and you can call C if you already have some library that does what you want. But you don't have to.
We do want to have the fairest possible comparison of the same algorithms across languages:
If someone does have faster versions in R that use the same algorithm, please submit patches!
I believe that the R benchmarks on the julia site are already byte-compiled, but if I'm doing it wrong and the comparison is unfair to R, please let me know and I will fix it and update the benchmarks.
Hmm, in the Mandelbrot example the matrix M has its dimensions transposed
M = matrix(0.0,nrow=length(im), ncol=length(re))
because it's filled by incrementing count in the inner loop (successive values of im). My implementation creates a vector of complex numbers in mandelperf.1 and operates on all elements, using an index and subsetting to keep track of which elements of the vector have not yet satisfied the condition Mod(z) <= 2
mandel.1 = function(z, maxiter=80L) {
c <- z
result <- integer(length(z))
i <- seq_along(z)
n <- 0L
while (n < maxiter && length(z)) {
j <- Mod(z) <= 2
if (!all(j)) {
result[i[!j]] <- n
i <- i[j]
z <- z[j]
c <- c[j]
}
z <- z^2 + c
n <- n + 1L
}
result[i] <- maxiter
result
}
mandelperf.1 = function() {
re = seq(-2,0.5,.1)
im = seq(-1,1,.1)
mandel.1(complex(real=rep(re, each=length(im)),
imaginary=im))
}
for a 13-fold speed-up (the results are equal but not identical because the original returns numeric rather than integer values).
> library(rbenchmark)
> benchmark(mandelperf(), mandelperf.1(),
+ columns=c("test", "elapsed", "relative"),
+ order="relative")
test elapsed relative
2 mandelperf.1() 0.412 1.00000
1 mandelperf() 5.705 13.84709
> all.equal(sum(mandelperf()), sum(mandelperf.1()))
[1] TRUE
The quicksort example doesn't actually sort
> set.seed(123L); qsort(sample(5))
[1] 2 4 1 3 5
but my main speed-up was to vectorize the partition around the pivot
qsort_kernel.1 = function(a) {
if (length(a) < 2L)
return(a)
pivot <- a[floor(length(a) / 2)]
c(qsort_kernel.1(a[a < pivot]), a[a == pivot], qsort_kernel.1(a[a > pivot]))
}
qsort.1 = function(a) {
qsort_kernel.1(a)
}
sortperf.1 = function(n) {
v = runif(n)
return(qsort.1(v))
}
for a 7-fold speedup (in comparison to the uncorrected original)
> benchmark(sortperf(5000), sortperf.1(5000),
+ columns=c("test", "elapsed", "relative"),
+ order="relative")
test elapsed relative
2 sortperf.1(5000) 6.60 1.000000
1 sortperf(5000) 47.73 7.231818
Since in the original comparison Julia is about 30 times faster than R for mandel, and 500 times faster for quicksort, the implementations above are still not really competitive.

Resources