1+ # Sieve of Eratosthenes Algorithm
2+ #
3+ # The Sieve of Eratosthenes is an ancient algorithm for finding all prime numbers
4+ # up to a given limit. It works by iteratively marking the multiples of each prime
5+ # starting from 2, and the unmarked numbers that remain are primes.
6+ #
7+ # Time Complexity: O(n log log n)
8+ # Space Complexity: O(n)
9+ #
10+ # Input: A positive integer n (the upper limit)
11+ # Output: A vector of all prime numbers from 2 to n
12+
13+ sieve_of_eratosthenes <- function (n ) {
14+ # Handle edge cases
15+ if (n < 2 ) {
16+ return (integer(0 )) # No primes less than 2
17+ }
18+
19+ # Create a boolean array "prime[0..n]" and initialize all entries as TRUE
20+ prime <- rep(TRUE , n + 1 )
21+ prime [1 ] <- FALSE # 1 is not a prime number
22+
23+ p <- 2
24+ while (p * p < = n ) {
25+ # If prime[p] is not changed, then it is a prime
26+ if (prime [p ]) {
27+ # Update all multiples of p starting from p^2
28+ for (i in seq(p * p , n , by = p )) {
29+ prime [i ] <- FALSE
30+ }
31+ }
32+ p <- p + 1
33+ }
34+
35+ # Collect all prime numbers
36+ primes <- which(prime )[- 1 ] # Remove index 1 (since 1 is not prime)
37+ return (primes )
38+ }
39+
40+ # Optimized version that only checks odd numbers after 2
41+ sieve_of_eratosthenes_optimized <- function (n ) {
42+ # Handle edge cases
43+ if (n < 2 ) {
44+ return (integer(0 ))
45+ }
46+ if (n == 2 ) {
47+ return (2 )
48+ }
49+
50+ # Start with 2 (the only even prime)
51+ primes <- c(2 )
52+
53+ # Create boolean array for odd numbers only (3, 5, 7, ...)
54+ # Index i represents number (2*i + 3)
55+ size <- (n - 1 ) %/% 2
56+ is_prime <- rep(TRUE , size )
57+
58+ # Sieve process for odd numbers
59+ for (i in 1 : size ) {
60+ if (is_prime [i ]) {
61+ num <- 2 * i + 1 # Convert index to actual odd number
62+
63+ # Mark multiples of num starting from num^2
64+ if (num * num < = n ) {
65+ start_idx <- (num * num - 1 ) %/% 2 # Convert num^2 to index
66+ for (j in seq(start_idx , size , by = num )) {
67+ if (j < = size ) {
68+ is_prime [j ] <- FALSE
69+ }
70+ }
71+ }
72+ }
73+ }
74+
75+ # Collect odd primes
76+ odd_primes <- 2 * which(is_prime ) + 1
77+ primes <- c(primes , odd_primes )
78+
79+ return (primes )
80+ }
81+
82+ # Function to count primes up to n (useful for large n)
83+ count_primes_sieve <- function (n ) {
84+ if (n < 2 ) {
85+ return (0 )
86+ }
87+
88+ prime <- rep(TRUE , n + 1 )
89+ prime [1 ] <- FALSE
90+
91+ p <- 2
92+ while (p * p < = n ) {
93+ if (prime [p ]) {
94+ for (i in seq(p * p , n , by = p )) {
95+ prime [i ] <- FALSE
96+ }
97+ }
98+ p <- p + 1
99+ }
100+
101+ return (sum(prime ))
102+ }
103+
104+ # Function to check if a number is prime using trial division (for comparison)
105+ is_prime_trial_division <- function (n ) {
106+ if (n < = 1 ) return (FALSE )
107+ if (n < = 3 ) return (TRUE )
108+ if (n %% 2 == 0 || n %% 3 == 0 ) return (FALSE )
109+
110+ i <- 5
111+ while (i * i < = n ) {
112+ if (n %% i == 0 || n %% (i + 2 ) == 0 ) {
113+ return (FALSE )
114+ }
115+ i <- i + 6
116+ }
117+ return (TRUE )
118+ }
119+
120+ # Segmented sieve for finding primes in a range [low, high]
121+ segmented_sieve <- function (low , high ) {
122+ # First, find all primes up to sqrt(high)
123+ limit <- floor(sqrt(high ))
124+ primes <- sieve_of_eratosthenes(limit )
125+
126+ # Create a boolean array for range [low, high]
127+ size <- high - low + 1
128+ is_prime <- rep(TRUE , size )
129+
130+ # Mark multiples of each prime in the range
131+ for (prime in primes ) {
132+ # Find the minimum number in [low, high] that is a multiple of prime
133+ start <- max(prime * prime , low + (prime - low %% prime ) %% prime )
134+
135+ # Mark multiples of prime in the range
136+ for (j in seq(start , high , by = prime )) {
137+ is_prime [j - low + 1 ] <- FALSE
138+ }
139+ }
140+
141+ # Handle the case where low = 1 (1 is not prime)
142+ if (low == 1 ) {
143+ is_prime [1 ] <- FALSE
144+ }
145+
146+ # Collect primes in the range
147+ range_primes <- (low : high )[is_prime ]
148+ return (range_primes )
149+ }
150+
151+ # Example usage and testing
152+ cat(" === Sieve of Eratosthenes Algorithm ===\n " )
153+
154+ # Test with small number
155+ cat(" Primes up to 30:\n " )
156+ primes_30 <- sieve_of_eratosthenes(30 )
157+ cat(paste(primes_30 , collapse = " , " ), " \n " )
158+ cat(" Count:" , length(primes_30 ), " \n\n " )
159+
160+ # Test optimized version
161+ cat(" Optimized sieve - Primes up to 30:\n " )
162+ primes_30_opt <- sieve_of_eratosthenes_optimized(30 )
163+ cat(paste(primes_30_opt , collapse = " , " ), " \n " )
164+ cat(" Count:" , length(primes_30_opt ), " \n\n " )
165+
166+ # Test with larger number
167+ cat(" Primes up to 100:\n " )
168+ primes_100 <- sieve_of_eratosthenes(100 )
169+ cat(" Count:" , length(primes_100 ), " \n " )
170+ cat(" First 10 primes:" , paste(primes_100 [1 : 10 ], collapse = " , " ), " \n " )
171+ cat(" Last 10 primes:" , paste(tail(primes_100 , 10 ), collapse = " , " ), " \n\n " )
172+
173+ # Performance comparison for counting primes
174+ cat(" === Performance Comparison ===\n " )
175+ n <- 1000
176+
177+ # Count using sieve
178+ start_time <- Sys.time()
179+ sieve_count <- count_primes_sieve(n )
180+ sieve_time <- as.numeric(Sys.time() - start_time , units = " secs" )
181+
182+ # Count using trial division
183+ start_time <- Sys.time()
184+ trial_count <- sum(sapply(2 : n , is_prime_trial_division ))
185+ trial_time <- as.numeric(Sys.time() - start_time , units = " secs" )
186+
187+ cat(" Primes up to" , n , " :\n " )
188+ cat(" Sieve method:" , sieve_count , " primes (" , sprintf(" %.4f" , sieve_time ), " seconds )\n " )
189+ cat(" Trial division:" , trial_count , " primes (" , sprintf(" %.4f" , trial_time ), " seconds )\n " )
190+ cat(" Speedup:" , sprintf(" %.2f" , trial_time / sieve_time ), " x\n\n " )
191+
192+ # Test segmented sieve
193+ cat(" === Segmented Sieve Example ===\n " )
194+ cat(" Primes between 50 and 100:\n " )
195+ range_primes <- segmented_sieve(50 , 100 )
196+ cat(paste(range_primes , collapse = " , " ), " \n " )
197+ cat(" Count:" , length(range_primes ), " \n\n " )
198+
199+ # Edge cases
200+ cat(" === Edge Cases ===\n " )
201+ cat(" Primes up to 1:" , paste(sieve_of_eratosthenes(1 ), collapse = " , " ), " \n " )
202+ cat(" Primes up to 2:" , paste(sieve_of_eratosthenes(2 ), collapse = " , " ), " \n " )
203+ cat(" Primes up to 3:" , paste(sieve_of_eratosthenes(3 ), collapse = " , " ), " \n " )
204+
205+ # Large example (uncomment for larger tests)
206+ # cat("\n=== Large Scale Test ===\n")
207+ # large_n <- 10000
208+ # start_time <- Sys.time()
209+ # large_primes <- sieve_of_eratosthenes(large_n)
210+ # end_time <- Sys.time()
211+ # cat("Found", length(large_primes), "primes up to", large_n, "\n")
212+ # cat("Computation time:", as.numeric(end_time - start_time, units = "secs"), "seconds\n")
0 commit comments