How does a break function in the inner loop in R? - r

while (statement 1){
......
......
if (statement 2){
x <- x + 1
break
}
if (statement 3){
y <- y + 1
}
}
I have a pseudocode as shown above, I want to verify my understanding whether is correct or not. Is it when the statement 2 is fulfilled, the equation in the 1st if loop will still run, then it will break the if loopand never come back again even the while loop still continue going on?
I am seeking an explanation about the break function in this scenario.

In short, break stops the loop at the exact position you write it without running any of the following code. You can test this by writing some easy statements and defining x and y. message is a useful function here as you can verify which part of the code still runs.
x <- 1
y <- 1
while (x < 100){
if (x == 1){
x <- x + 1
break
}
message(x)
if (y < 100){
y <- y + 1
}
message(y)
}
In this example, the first run is already interrupted as x == 1 is true from the beginning. You will notice that no message is printed but the value for x is 2 now.
In the second example, I made up a statement which will become true after a few iterations. Messages with the value of x and y are now printed for each iteration but once y > 10 nothing is printed and the loop stops immediately.
x <- 1
y <- 1
while (x < 100){
if (y > 10){
x <- x + 1
break
}
message(x)
if (y < 100){
y <- y + 1
}
message(y)
}
The difference of break in comparison to stop for example is that it will only interrupt the inner-most loop (and that stop prints a stop/error message). Meaning that if your code sits in another loop, that outer loop will continue. For example:
for (x in 1:10) {
y <- 1
while (x < 100){
if (y > 10){
x <- x + 1
break
}
message(x)
if (y < 100){
y <- y + 1
}
message(y)
}
}

You can verify how it works with this simple example :
num <- 2
x <- 0
y<- 0
while (TRUE){
if (num %% 10 == 0){
cat('\nprinting from 1: ', num)
x <- x + 1
break
}
if (num %% 2 == 0){
cat('\nprinting from 2: ', num)
y <- y+ 1
}
num <- num + 1
}
#printing from 2: 2
#printing from 2: 4
#printing from 2: 6
#printing from 2: 8
#printing from 1: 10
x
#[1] 1
y
#[1] 4
while(TRUE) makes it run for an infinite time. Every time num is divisible by 2 y is incremented and when num is divisible by 10 it increments y and the while loop breaks.

Related

R: cumulative sum until certain value

I want to calculate how many values are taken until the cumulative reaches a certain value.
This is my vector: myvec = seq(0,1,0.1)
I started with coding the cumulative sum function:
cumsum_for <- function(x)
{
y = 1
for(i in 2:length(x)) # pardon the case where x is of length 1 or 0
{x[i] = x[i-1] + x[i]
y = y+1}
return(y)
}
Now, with the limit
cumsum_for <- function(x, limit)
{
y = 1
for(i in 2:length(x)) # pardon the case where x is of length 1 or 0
{x[i] = x[i-1] + x[i]
if(x >= limit) break
y = y+1}
return(y)
}
which unfortunately errors:
myvec = seq(0,1,0.1)
cumsum_for(myvec, 0.9)
[1] 10
Warning messages:
1: In if (x >= limit) break :
the condition has length > 1 and only the first element will be used
[...]
What about this? You can use cumsum to compute the cumulative sum, and then count the number of values that are below a certain threshold n:
f <- function(x, n) sum(cumsum(x) <= n)
f(myvec, 4)
#[1] 9
f(myvec, 1.1)
#[1] 5
You can put a while loop in a function. This stops further calculation of the cumsum if the limit is reached.
cslim <- function(v, l) {
s <- 0
i <- 0L
while (s < l) {
i <- i + 1
s <- sum(v[1:i])
}
i - 1
}
cslim(v, .9)
# [1] 4
Especially useful for longer vectors, e.g.
v <- seq(0, 3e7, 0.1)

How to stop the counting process for the if loop in my code?

I want to stop the counting process for y after it first time meet the condition of y < 0 for each i in the for loop. Which means, the counting process for x will still continue as long as x > 0 (condition stated in the while loop).
I had tried to do something which is if (y < 0 & (y - 120*(16/81)*time + (z-2)) > 0 & z > 2), it make sense for me but the result doesn't make sense because after I run the code, count_x is around 100 (make sense) but count_y is more than 1000 which doesn't make sense since the for loop is only from 1:1000.
count_x <- 0
count_y <- 0
for (i in 1:1000){
x <- 25
y <- 25
t <- 0
while ((x > 0 | y > 0) & t < 100){
time <- rexp(1,100)
u <- runif(1,0,1)
z <- 4/((1-u)^0.2) - 4
if (z < 2){
x <- x + 110*(65/81)*time - z
} else {
y <- y + 120*(16/81)*time - (z-2)
x <- x + 110*(65/81)*time - 2
}
t <- t + time
if (x < 0){
count_x <- count_x + 1
}
if (y < 0 & (y - 120*(16/81)*time + (z-2)) > 0 & z > 2){
count_y <- count_y + 1
}
}
}
For example, during the 1st iteration i=1, the while loop will start and run the code inside the loop. So what I want to do is:
When y first time reach negative value in the first iteration, it will update the count_y by one, then the whole if loop for the counting process of y will stop doing any thing even though the while loop is still continue to run since the if loop for counting process of x might not reach it first negative value yet (the condition for the while loop still satisfied if t is still smaller than 100), so the while loop need to be continue without touching last inner if loop until either t>100 first or x first time reach its negative value. Once, the conditions for while loop do not satisfied, then only go for the 2nd iteration i=2.
Same thing goes to x, the counting process for x will stop doing anything once x first time become a negative value but the while loop will continue working as long as the condition for the while loop still satisfied.
So, there will only be one time update for either x or y for each iteration (so maximum for y should be 1000 since we have 1000 iteration, although unlikely to reach 1000) since the counting process for both x and y will stop once it reaches the first negative value.
I'm thinking to add break function into it but not sure where should I add.
I don't think there's anything wrong with the code. The y counter, to me at least, seems like it is correct. The reason why y is larger is two-fold. Firstly, even though the outer for loop is only 1000, the inner while loop could potentially run for more than a 100 at each i iteration. Secondly, it appears that y goes below 0 before x does, hence why the x counter is smaller.
I've modified your code to include a counter that counts how many while iterations occur, and two variables that store the values of x and y respectively, the first time that y goes below zero.
count_x <- 0
count_y <- 0
while_count <- 0
store_x <- 0
store_y <- 0
a <- 1
b <- 1
for (i in 1:1000){
x <- 25
y <- 25
t <- 0
count_while <- 0
while ((x > 0 | y > 0) & t < 100){
time <- rexp(1,100)
u <- runif(1,0,1)
z <- 4/((1-u)^0.2) - 4
if (z < 2){
x <- x + 110*(65/81)*time - z
} else {
y <- y + 120*(16/81)*time - (z-2)
x <- x + 110*(65/81)*time - 2
}
t <- t + time
if (x < 0){
count_x <- count_x + 1
}
if (y < 0 & (y - 120*(16/81)*time + (z-2)) > 0 & z > 2){
count_y <- count_y + 1
store_y[a] <- y
store_x[a] <- x
a <- a + 1
}
if (y > 0){
count_while <- count_while + 1
}
}
while_count[b] <- count_while
b <- b + 1
}
Checking the averages shows that x is almost exclusively greater than zero the first time y goes below zero. The while loop averages 163 iterations.
mean(store_x)
[1] 38.90333
mean(store_y)
[1] -2.035492
mean(while_count)
[1] 163.052
which(store_x < 0)
[1] 656
So, your counter seems correct to me, x is low simply because it rarely goes below zero. In fact, run the loop for just one iteration by setting for (i in 1:1) and run it several time, you'll find that your count_x rarely goes above zero, despite the while loop iterating over a 100 times. On the other hand, y goes below zero at least once on each i iteration.
I hope this helps!
We will create variables for both x and y that will store and track when both cross zero on each i iteration. First we will check if x or y is zero and if neg is of class NULL. If so, then this is the first negative. We store x_0 or y_0 as 1. Then when counting, we check if x_0 or y_0 is equal to one and if neg is NULL. Then we will add to the counter and record the first negative. Thereafter, the condition evaluates to FALSE.
count_x <- 0
count_y <- 0
while_x <- 0
while_y <- 0
for (i in 1:1000){
x <- 25
y <- 25
t <- 0
x_0 <- 0
y_0 <- 0
neg <- NULL
neg_x <- NULL
while ((x > 0 | y > 0) & t < 100){
time <- rexp(1,100)
u <- runif(1,0,1)
z <- 4/((1-u)^0.2) - 4
if (z < 2){
x <- x + 110*(65/81)*time - z
if (x < 0 & is.null(neg_x)){
x_0 <- 1
}
} else {
y <- y + 120*(16/81)*time - (z-2)
x <- x + 110*(65/81)*time - 2
if (x < 0 & is.null(neg_x)){
x_0 <- 1
}
if (y < 0 & is.null(neg)) {
y_0 <- 1
}
}
t <- t + time
if (x_0 == 1 & is.null(neg_x)){
count_x <- count_x + 1
neg_x <- "First Negative"
x_0 <- x_0 + 1
}
if (y_0 == 1 & is.null(neg)){
count_y <- count_y + 1
neg <- "first negative"
y_0 <- y_0 + 1
}
}
}
You can also place a counter outside the while loop. If x or y is less than 0, add to the counter. This is probably a better solution. The condition will evaluate regardless of when x or y cross below zero, as long as it went below zero, it will evaluate to TRUE
count_x <- 0
count_y <- 0
for (i in 1:1000){
x <- 25
y <- 25
t <- 0
while ((x > 0 | y > 0) & t < 100){
time <- rexp(1,100)
u <- runif(1,0,1)
z <- 4/((1-u)^0.2) - 4
if (z < 2){
x <- x + 110*(65/81)*time - z
} else {
y <- y + 120*(16/81)*time - (z-2)
x <- x + 110*(65/81)*time - 2
}
t <- t + time
}
if(x < 0) {
count_x <- count_x + 1
}
if(y < 0){
count_y <- count_y + 1
}
}
For me, count_y comes out at a 1000 in both cases. This confirms what I said previously, y goes below zero at each while iteration.

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
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])
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.
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
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

Value of a bar in a graph

I made a thread about this earlier although it got closed since I was unclear. I will try to be more clear now.
What I'm wondering is, if you enter my code into Rstudio, it will give you a graph. On the x-axis there are 6 bars (6 different states), and on the y-axis is the frequency 0-300. All I can see is that state 1 is somewhere in-between 0 and 50. Is there any code that can let me exactly what value state 1 and the others states have?
Here is a matrix:
spec_sim <- function(x){
u <- runif(1)
if(x==0){ if(u < 0.5){ y <- 3
} else{
y <- 5
}
} else if(x==1){
if(u<0.1){
y <- 0
} else if(u < 0.1 + 0.1){
y <- 1
} else if(u < 0.1 + 0.1 + 0.4){
y <- 3
} else{
y <- 5
}
} else if(x==2){
if(u<0.2){
y <- 1
} else if(u < 0.2 + 0.2){
y <- 2
} else if(u < 0.2 + 0.2 + 0.3){
y <- 3
} else{
y <- 5
}
} else if(x==3){
if(u<0.3){
y <- 2
} else if(u < 0.3 + 0.5){
y <- 3
} else{
y <- 5
}
} else if(x==4){
if(u<0.4){
y <- 3
} else{
y <- 4
}
} else if(x==5){
if(u<0.4){
y <- 4
} else{
y <- 5
}
}
y
}
set.seed(1)
results <- numeric(1001)
for(i in 2:length(results)){
results[i]<- spec_sim(results[i - 1])
}
results <- results[-1]
barplot(table(results), xlab="states", ylab="frequency",
main="1000 simuleringar av en Markovkedja")
To identify the value in an active plotting device (window), you use ?identify. Since the data to be plotted were from a table that was created (but not saved to an object) within the plotting command, you need to enter that for the x and labels arguments to the function. Once you run the command, the mouse pointer will display as a plus over the plotting device. Then you just click on the bar you want. Consider:
identify(table(results), labels=table(results))
The value for 1 is evidently 26.
This is a very general method for getting values from a plot. Of course, you can also just inspect the underlying data object. That is more straightforward in this case:
table(results)
# results
# 0 1 2 3 4 5
# 4 26 112 306 296 256

Euler Project #1 in R

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

Resources