comptime sieve

This commit is contained in:
Rorik Star Platinum 2025-12-11 01:02:04 +03:00
parent 485252a76f
commit 9624356fec
14 changed files with 685 additions and 0 deletions

View file

@ -0,0 +1,37 @@
{
"authors": [
"IanWhitney"
],
"contributors": [
"ashleygwilliams",
"ClashTheBunny",
"coriolinus",
"cwhakes",
"efx",
"ErikSchierboom",
"IanWhitney",
"lutostag",
"mkantor",
"nfiles",
"petertseng",
"rofrol",
"stringparser",
"xakon",
"ZapAnton"
],
"files": {
"solution": [
"src/lib.rs",
"Cargo.toml"
],
"test": [
"tests/sieve.rs"
],
"example": [
".meta/example.rs"
]
},
"blurb": "Use the Sieve of Eratosthenes to find all the primes from 2 up to a given number.",
"source": "Sieve of Eratosthenes at Wikipedia",
"source_url": "https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes"
}

2
rust/sieve/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
/target
Cargo.lock

9
rust/sieve/Cargo.toml Normal file
View file

@ -0,0 +1,9 @@
[package]
name = "sieve"
version = "0.1.0"
edition = "2024"
# Not all libraries from crates.io are available in Exercism's test runner.
# The full list of available libraries is here:
# https://github.com/exercism/rust-test-runner/blob/main/local-registry/Cargo.toml
[dependencies]

89
rust/sieve/HELP.md Normal file
View file

@ -0,0 +1,89 @@
# Help
## Running the tests
Execute the tests with:
```bash
$ cargo test
```
All but the first test have been ignored. After you get the first test to
pass, open the tests source file which is located in the `tests` directory
and remove the `#[ignore]` flag from the next test and get the tests to pass
again. Each separate test is a function with `#[test]` flag above it.
Continue, until you pass every test.
If you wish to run _only ignored_ tests without editing the tests source file, use:
```bash
$ cargo test -- --ignored
```
If you are using Rust 1.51 or later, you can run _all_ tests with
```bash
$ cargo test -- --include-ignored
```
To run a specific test, for example `some_test`, you can use:
```bash
$ cargo test some_test
```
If the specific test is ignored, use:
```bash
$ cargo test some_test -- --ignored
```
To learn more about Rust tests refer to the online [test documentation][rust-tests].
[rust-tests]: https://doc.rust-lang.org/book/ch11-02-running-tests.html
## Submitting your solution
You can submit your solution using the `exercism submit src/lib.rs Cargo.toml` command.
This command will upload your solution to the Exercism website and print the solution page's URL.
It's possible to submit an incomplete solution which allows you to:
- See how others have completed the exercise
- Request help from a mentor
## Need to get help?
If you'd like help solving the exercise, check the following pages:
- The [Rust track's documentation](https://exercism.org/docs/tracks/rust)
- The [Rust track's programming category on the forum](https://forum.exercism.org/c/programming/rust)
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
## Rust Installation
Refer to the [exercism help page][help-page] for Rust installation and learning
resources.
## Submitting the solution
Generally you should submit all files in which you implemented your solution (`src/lib.rs` in most cases). If you are using any external crates, please consider submitting the `Cargo.toml` file. This will make the review process faster and clearer.
## Feedback, Issues, Pull Requests
Head to [the forum](https://forum.exercism.org/c/programming/rust/) and create a post to provide feedback about an exercise or if you want to help implement new exercises.
Members of the rust track team are happy to help!
The GitHub [track repository][github] is the home for all of the Rust exercises.
If you want to know more about Exercism, take a look at the [contribution guide].
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
[help-page]: https://exercism.org/tracks/rust/learning
[github]: https://github.com/exercism/rust
[contribution guide]: https://exercism.org/docs/community/contributors

142
rust/sieve/README.md Normal file
View file

@ -0,0 +1,142 @@
# Sieve
Welcome to Sieve on Exercism's Rust Track.
If you need help running the tests or submitting your code, check out `HELP.md`.
## Introduction
You bought a big box of random computer parts at a garage sale.
You've started putting the parts together to build custom computers.
You want to test the performance of different combinations of parts, and decide to create your own benchmarking program to see how your computers compare.
You choose the famous "Sieve of Eratosthenes" algorithm, an ancient algorithm, but one that should push your computers to the limits.
## Instructions
Your task is to create a program that implements the Sieve of Eratosthenes algorithm to find all prime numbers less than or equal to a given number.
A prime number is a number larger than 1 that is only divisible by 1 and itself.
For example, 2, 3, 5, 7, 11, and 13 are prime numbers.
By contrast, 6 is _not_ a prime number as it not only divisible by 1 and itself, but also by 2 and 3.
To use the Sieve of Eratosthenes, first, write out all the numbers from 2 up to and including your given number.
Then, follow these steps:
1. Find the next unmarked number (skipping over marked numbers).
This is a prime number.
2. Mark all the multiples of that prime number as **not** prime.
Repeat the steps until you've gone through every number.
At the end, all the unmarked numbers are prime.
~~~~exercism/note
The Sieve of Eratosthenes marks off multiples of each prime using addition (repeatedly adding the prime) or multiplication (directly computing its multiples), rather than checking each number for divisibility.
The tests don't check that you've implemented the algorithm, only that you've come up with the correct primes.
~~~~
## Example
Let's say you're finding the primes less than or equal to 10.
- Write out 2, 3, 4, 5, 6, 7, 8, 9, 10, leaving them all unmarked.
```text
2 3 4 5 6 7 8 9 10
```
- 2 is unmarked and is therefore a prime.
Mark 4, 6, 8 and 10 as "not prime".
```text
2 3 [4] 5 [6] 7 [8] 9 [10]
```
- 3 is unmarked and is therefore a prime.
Mark 6 and 9 as not prime _(marking 6 is optional - as it's already been marked)_.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 4 is marked as "not prime", so we skip over it.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 5 is unmarked and is therefore a prime.
Mark 10 as not prime _(optional - as it's already been marked)_.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 6 is marked as "not prime", so we skip over it.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 7 is unmarked and is therefore a prime.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 8 is marked as "not prime", so we skip over it.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 9 is marked as "not prime", so we skip over it.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
- 10 is marked as "not prime", so we stop as there are no more numbers to check.
```text
2 3 [4] 5 [6] 7 [8] [9] [10]
```
You've examined all the numbers and found that 2, 3, 5, and 7 are still unmarked, meaning they're the primes less than or equal to 10.
## Source
### Created by
- @IanWhitney
### Contributed to by
- @ashleygwilliams
- @ClashTheBunny
- @coriolinus
- @cwhakes
- @efx
- @ErikSchierboom
- @IanWhitney
- @lutostag
- @mkantor
- @nfiles
- @petertseng
- @rofrol
- @stringparser
- @xakon
- @ZapAnton
### Based on
Sieve of Eratosthenes at Wikipedia - https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

52
rust/sieve/src/lib.rs Normal file
View file

@ -0,0 +1,52 @@
const PRIME_LEN: usize = 10_010;
const LIMIT: usize = 106_000;
struct PrimeCache {
primes: [u64; PRIME_LEN],
}
impl PrimeCache {
const fn new() -> Self {
let mut primes = [0; PRIME_LEN];
let mut sieve = [true; LIMIT];
sieve[0] = false;
sieve[1] = false;
let mut i = 2;
while i * i < LIMIT {
if sieve[i] {
let mut j = i * i;
while j < LIMIT {
sieve[j] = false;
j += i;
}
}
i += 1;
}
let mut num = 0;
let mut j = 0;
while num < LIMIT && j < PRIME_LEN {
if sieve[num] {
primes[j] = num as u64;
j += 1;
}
num += 1;
}
Self { primes }
}
}
static CACHE: PrimeCache = PrimeCache::new();
pub fn primes_up_to(upper_bound: u64) -> Vec<u64> {
let mut nth = 0;
if upper_bound < 2 {
return vec![];
}
while CACHE.primes[nth] <= upper_bound {
nth += 1;
}
let slice = &CACHE.primes[0..nth];
slice.to_vec()
}

51
rust/sieve/tests/sieve.rs Normal file
View file

@ -0,0 +1,51 @@
use sieve::*;
#[test]
fn no_primes_under_two() {
let input = 1;
let output = primes_up_to(input);
let expected = [];
assert_eq!(output, expected);
}
#[test]
fn find_first_prime() {
let input = 2;
let output = primes_up_to(input);
let expected = [2];
assert_eq!(output, expected);
}
#[test]
fn find_primes_up_to_10() {
let input = 10;
let output = primes_up_to(input);
let expected = [2, 3, 5, 7];
assert_eq!(output, expected);
}
#[test]
fn limit_is_prime() {
let input = 13;
let output = primes_up_to(input);
let expected = [2, 3, 5, 7, 11, 13];
assert_eq!(output, expected);
}
#[test]
fn find_primes_up_to_1000() {
let input = 1000;
let output = primes_up_to(input);
let expected = [
2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89,
97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181,
191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397,
401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503,
509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619,
631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743,
751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997,
];
assert_eq!(output, expected);
}