Frage

I am trying to test the accuracy of the Euler's primality test. I wrote a function euler() that takes in a numeric and tests all numbers for primality up to the input and outputs them to the console including the nonprimes. Here is how it looks:

euler(10)
[1] 1
[1] 2
[1] 3
[1] "Not prime:" "4"         
[1] 5
[1] "Not prime:" "6"         
[1] 7
[1] "Not prime:" "8"         
[1] "Not prime:" "9"         
[1] "Not prime:" "10"        
> 

I am trying to take this output and put it into a data frame or a factor or a list. I tried x<-euler(10), but it did not work. I just get a NULL vector. Here is the code of my euler function:

## Euler's primality test

euler <- function(k) {
  for(i in 1:k) {
    a  <- 2;
    if((a^i-a) %% i == 0) {
      print(i)
    } else{print(c("Not prime:",i))}
  }   
}

I tried defining a data frame outside the "for" loop and then use rbind(), but I do not know how to do it when there is an if statement. Any help appreciated. If I was unclear let me know and I will make the necessary edits.

War es hilfreich?

Lösung

It is recommended that a function return something instead of printing it. (And you are still free to print the output after calling the function if that's what you want.)

It is also recommended that the output of a function be consistent, e.g. do not return a number in one case, or a string "Not prime" in another. Here, returning a boolean (TRUE or FALSE for prime or not) is what makes most sense.

It is also recommended (beneficial) to vectorize functions when you can. So you could call the function using a vector like 1:10 and it will quickly return a vector of ten booleans.

Taking all that into account, I would define the function as follows:

is.euler.prime <- function(k) (2^k-2) %% k == 0

Then you can do things like:

is.euler.prime(10)
is.euler.prime(1:10)
which(is.euler.prime(1:10))
data.frame(x = 1:10, euler.prime = is.euler.prime(1:10))

Andere Tipps

Considerations about the "properness" of your function apart, you can capture the print output of a function with capture.output.

In your case:

data<-capture.output(euler(10))

This will give you:

 [1] "[1] 1"                             "[1] 2"                             "[1] 3"                             "[1] \"Not prime:\" \"4\"         "
 [5] "[1] 5"                             "[1] \"Not prime:\" \"6\"         " "[1] 7"                             "[1] \"Not prime:\" \"8\"         "
 [9] "[1] \"Not prime:\" \"9\"         " "[1] \"Not prime:\" \"10\"        "

If you want, you can print it in a pretty way with cat:

cat(data,sep="\n")

That will give you back the result:

[1] 1
[1] 2
[1] 3
[1] "Not prime:" "4"         
[1] 5
[1] "Not prime:" "6"         
[1] 7
[1] "Not prime:" "8"         
[1] "Not prime:" "9"         
[1] "Not prime:" "10" 

If you want to save the results without the line breaks and the [1]'s, you can use gsub to clean the data:

data<- gsub("\\[1\\]\\s|[[:punct:]]|\\s*$", "", capture.output(euler(10)))

This will give you a vector with "clean" character strings like this:

data
[1] "1"            "2"            "3"            "Not prime 4"  "5"            "Not prime 6"  "7"            "Not prime 8"  "Not prime 9"  "Not prime 10"

But I am answering on the assumption that you want to learn how to capture print outputs and that this euler function is a toy function to test that.

If that is not your intention (and now that I have read again your comments I think that it was not), you should really rethink your function and read carefully @flodel's answer.

euler <- function(k) {
  L <- c()
  for(i in 1:k) {
    a  <- 2;
    if((a^i-a) %% i == 0) {
      L <- c(L,i)
    } 
    else{
      L <- c(L,paste("Not prime:",i))
    }
  }
  return(L)
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top