diff --git a/README.md b/README.md index 1c219b01..1f77e5dd 100644 --- a/README.md +++ b/README.md @@ -143,10 +143,11 @@ Performance results for cpython 3.9 are applicable to for pkpy. See https://pocketpy.dev/performance/ for details. -And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20.04 LTS), which *roughly* reflects the performance among lua, pkpy and cpython. +And these are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20.04 LTS), which *roughly* reflects the performance among c++, lua, pkpy and cpython. | name | version | time | file | | ---- | ---- | ---- | ---- | +| c++ | gnu++11 | `0.104s ■□□□□□□□□□□□□□□□` | [benchmarks/primes.cpp](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.cpp) | | lua | 5.3.3 | `1.576s ■■■■■■■■■□□□□□□□` | [benchmarks/primes.lua](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.lua) | | pkpy | 1.2.7 | `2.385s ■■■■■■■■■■■■■□□□` | [benchmarks/primes.py](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.py) | | cpython | 3.8.10 | `2.871s ■■■■■■■■■■■■■■■■` | [benchmarks/primes.py](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.py) | diff --git a/benchmarks/primes.cpp b/benchmarks/primes.cpp new file mode 100644 index 00000000..7ef6e690 --- /dev/null +++ b/benchmarks/primes.cpp @@ -0,0 +1,167 @@ +#include +#include +#include +#include +#include +#include + +typedef long long LL; + +struct Node{ + std::unordered_map children; + bool terminal; + + Node(){ + terminal = false; + } +}; + +struct Sieve{ + LL limit; + std::vector prime; + + Sieve(LL limit){ + this->limit = limit; + prime = std::vector(limit + 1, false); + } + + std::vector to_list(){ + std::vector result; + result.push_back(2); + result.push_back(3); + for(LL p = 5; p <= limit; p++){ + if(prime[p]){ + result.push_back(p); + } + } + return result; + } + + void omit_squares(){ + LL r = 5; + while(r * r < limit){ + if(prime[r]){ + LL i = r * r; + while(i < limit){ + prime[i] = false; + i = i + r * r; + } + } + r += 1; + } + } + + void step1(LL x, LL y){ + LL n = (4 * x * x) + (y * y); + if(n <= limit && (n % 12 == 1 || n % 12 == 5)){ + prime[n] = !prime[n]; + } + } + + void step2(LL x, LL y){ + LL n = (3 * x * x) + (y * y); + if(n <= limit && n % 12 == 7){ + prime[n] = !prime[n]; + } + } + + void step3(LL x, LL y){ + LL n = (3 * x * x) - (y * y); + if(x > y && n <= limit && n % 12 == 11){ + prime[n] = !prime[n]; + } + } + + void loop_y(LL x){ + LL y = 1; + while(y * y < limit){ + step1(x, y); + step2(x, y); + step3(x, y); + y += 1; + } + } + + void loop_x(){ + LL x = 1; + while(x * x < limit){ + loop_y(x); + x += 1; + } + } + + void calc(){ + loop_x(); + omit_squares(); + } +}; + +Node *generate_trie(std::vector l){ + Node *root = new Node(); + for(LL el : l){ + Node *head = root; + std::string s = std::to_string(el); + for(char ch : s){ + if(head->children.find(ch) == head->children.end()){ + head->children[ch] = new Node(); + } + head = head->children[ch]; + } + head->terminal = true; + } + return root; +} + +std::vector find(LL upper_bound, LL prefix){ + Sieve *sieve = new Sieve(upper_bound); + sieve->calc(); + std::string str_prefix = std::to_string(prefix); + Node *head = generate_trie(sieve->to_list()); + for(char ch : str_prefix){ + if(head->children.find(ch) == head->children.end()){ + return std::vector(); + } + head = head->children[ch]; + } + + std::queue> q; + std::vector result; + q.push(std::make_pair(head, str_prefix)); + while(!q.empty()){ + std::pair top = q.front(); + q.pop(); + if(top.first->terminal){ + result.push_back(std::stoll(top.second)); + } + for(std::pair p : top.first->children){ + q.push(std::make_pair(p.second, top.second + p.first)); + } + } + + std::sort(result.begin(), result.end()); + return result; +} + +void verify(){ + std::vector left = {2, 23, 29}; + std::vector right = find(100, 2); + if(left != right){ + std::cout << "left != right" << std::endl; + exit(1); + } +} + + +int main(){ + const LL UPPER_BOUND = 5000000; + const LL PREFIX = 32338; + + verify(); + std::vector results = find(UPPER_BOUND, PREFIX); + std::vector expected = {323381, 323383, 3233803, 3233809, 3233851, 3233863, 3233873, 3233887, 3233897}; + if(results != expected){ + std::cout << "results != expected" << std::endl; + exit(1); + } + return 0; +} \ No newline at end of file diff --git a/docs/performance.md b/docs/performance.md index 175ab040..2a730c7f 100644 --- a/docs/performance.md +++ b/docs/performance.md @@ -134,6 +134,7 @@ These are the results of the primes benchmark on Intel i5-12400F, WSL (Ubuntu 20 | name | version | time | file | | ---- | ---- | ---- | ---- | +| c++ | gnu++11 | `0.104s ■□□□□□□□□□□□□□□□` | [benchmarks/primes.cpp](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.cpp) | | lua | 5.3.3 | `1.576s ■■■■■■■■■□□□□□□□` | [benchmarks/primes.lua](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.lua) | | pkpy | 1.2.7 | `2.385s ■■■■■■■■■■■■■□□□` | [benchmarks/primes.py](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.py) | | cpython | 3.8.10 | `2.871s ■■■■■■■■■■■■■■■■` | [benchmarks/primes.py](https://github.com/blueloveTH/pocketpy/blob/3d332a694f99ae2d327e732e7f3e3215bedcb069/benchmarks/primes.py) |