Skip to content

Commit

Permalink
Made primes test more consistent by using unordered hashmaps and expl…
Browse files Browse the repository at this point in the history
…icit sorts. (#426)
  • Loading branch information
nuald authored Oct 11, 2022
1 parent e653aa9 commit ff31ca3
Show file tree
Hide file tree
Showing 15 changed files with 61 additions and 44 deletions.
50 changes: 28 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -362,32 +362,38 @@ Testing:
- generating primes using the optimized [sieve of Atkin](https://www.geeksforgeeks.org/sieve-of-atkin/);
- prefix search for their decimal numbers using Trie data structure.

Notes:

- All languages but V and Python use unordered hashmaps (V and Python don't provide those out of box, and
their hashmaps use keys in the insertion order);
- The results are always sorted (could be unstable or stable though).

[Primes](primes)

| Language | Time, s | Memory, MiB | Energy, J |
| :----------------------- | ---------------------: | ------------------------------------------------: | ----------------------: |
| Zig | 0.059<sub>±0.000</sub> | 0.92<sub>±00.02</sub> + 49.27<sub>±00.13</sub> | 2.41<sub>±00.02</sub> |
| Rust | 0.094<sub>±0.000</sub> | 0.93<sub>±00.01</sub> + 78.38<sub>±00.06</sub> | 3.79<sub>±00.02</sub> |
| Crystal | 0.122<sub>±0.000</sub> | 2.99<sub>±00.05</sub> + 90.76<sub>±00.15</sub> | 5.52<sub>±00.01</sub> |
| C++/g++ | 0.132<sub>±0.000</sub> | 3.57<sub>±00.05</sub> + 85.38<sub00.39</sub> | 5.38<sub>±00.06</sub> |
| C++/clang++ | 0.140<sub>±0.000</sub> | 1.67<sub>±00.01</sub> + 76.83<sub>±00.03</sub> | 5.49<sub>±00.04</sub> |
| V/clang | 0.147<sub>±0.000</sub> | 0.90<sub>±00.02</sub> + 265.66<sub>±00.38</sub> | 6.08<sub>±00.02</sub> |
| V/gcc | 0.150<sub>±0.000</sub> | 0.89<sub>±00.01</sub> + 259.63<sub00.45</sub> | 6.24<sub>±00.07</sub> |
| Java | 0.157<sub>±0.002</sub> | 37.73<sub>±00.17</sub> + 153.30<sub04.68</sub> | 8.82<sub>±00.11</sub> |
| Node.js | 0.251<sub>±0.001</sub> | 40.02<sub>±00.08</sub> + 176.44<sub>±00.42</sub> | 12.63<sub>±00.08</sub> |
| Lua/luajit | 0.338<sub>±0.002</sub> | 2.59<sub>±00.05</sub> + 156.86<sub01.28</sub> | 13.24<sub>±00.08</sub> |
| Scala | 0.360<sub>±0.004</sub> | 67.32<sub>±00.11</sub> + 243.01<sub06.35</sub> | 18.56<sub>±00.08</sub> |
| Nim/clang | 0.423<sub>±0.001</sub> | 1.94<sub>±00.01</sub> + 1163.25<sub02.84</sub> | 16.58<sub>±00.10</sub> |
| Nim/gcc | 0.432<sub>±0.000</sub> | 1.67<sub>±00.06</sub> + 1170.86<sub01.80</sub> | 16.62<sub>±00.14</sub> |
| Julia | 0.604<sub>±0.001</sub> | 245.48<sub>±00.27</sub> + 376.33<sub00.44</sub> | 23.40<sub>±00.14</sub> |
| Python/pypy | 0.882<sub>±0.001</sub> | 63.60<sub>±00.05</sub> + 250.82<sub>±00.53</sub> | 34.48<sub>±00.19</sub> |
| Ruby/truffleruby (--jvm) | 1.396<sub>±0.036</sub> | 348.32<sub03.87</sub> + 486.92<sub22.89</sub> | 91.61<sub02.10</sub> |
| Ruby (--jit) | 1.445<sub>±0.003</sub> | 270.51<sub>±00.03</sub> + 147.09<sub>±00.07</sub> | 58.62<sub>±00.50</sub> |
| Lua | 1.483<sub>±0.005</sub> | 2.27<sub>±00.03</sub> + 283.81<sub>±00.55</sub> | 57.70<sub>±00.54</sub> |
| Ruby/truffleruby | 1.513<sub>±0.014</sub> | 297.33<sub>±00.99</sub> + 420.61<sub05.97</sub> | 84.26<sub>±00.90</sub> |
| Ruby/jruby | 1.991<sub>±0.045</sub> | 183.52<sub>±01.96</sub> + 523.52<sub>±28.85</sub> | 103.87<sub>±03.74</sub> |
| Ruby | 2.057<sub>±0.001</sub> | 13.89<sub>±00.04</sub> + 147.04<sub>±00.02</sub> | 82.72<sub>±00.75</sub> |
| Python | 4.979<sub>±0.045</sub> | 10.53<sub>±00.05</sub> + 234.86<sub>±00.90</sub> | 193.43<sub>±02.10</sub> |
| Zig | 0.059<sub>±0.000</sub> | 0.92<sub>±00.01</sub> + 48.53<sub>±00.03</sub> | 2.45<sub>±00.02</sub> |
| Crystal | 0.122<sub>±0.000</sub> | 2.98<sub>±00.03</sub> + 90.71<sub>±00.17</sub> | 5.52<sub>±00.08</sub> |
| Rust | 0.140<sub>±0.000</sub> | 0.94<sub>±00.01</sub> + 74.26<sub>±00.07</sub> | 5.35<sub>±00.05</sub> |
| Java | 0.159<sub>±0.002</sub> | 38.27<sub>±00.10</sub> + 153.79<sub03.78</sub> | 8.89<sub>±00.06</sub> |
| C++/g++ | 0.189<sub>±0.000</sub> | 2.70<sub>±00.90</sub> + 116.66<sub>±00.81</sub> | 7.76<sub>±00.05</sub> |
| C++/clang++ | 0.198<sub>±0.000</sub> | 1.66<sub>±00.02</sub> + 87.96<sub>±00.02</sub> | 7.79<sub>±00.09</sub> |
| V/clang | 0.212<sub>±0.001</sub> | 1.91<sub>±00.05</sub> + 203.15<sub01.44</sub> | 8.46<sub>±00.06</sub> |
| Node.js | 0.227<sub>±0.002</sub> | 39.10<sub>±00.03</sub> + 150.29<sub00.26</sub> | 11.37<sub>±00.12</sub> |
| V/gcc | 0.240<sub>±0.001</sub> | 2.28<sub>±00.14</sub> + 219.14<sub>±00.67</sub> | 9.66<sub>±00.12</sub> |
| Nim/clang | 0.297<sub>±0.001</sub> | 2.07<sub>±00.01</sub> + 601.73<sub02.96</sub> | 11.72<sub>±00.09</sub> |
| Lua/luajit | 0.338<sub>±0.002</sub> | 1.20<sub>±00.02</sub> + 157.12<sub01.04</sub> | 13.22<sub>±00.05</sub> |
| Nim/gcc | 0.352<sub>±0.003</sub> | 1.68<sub>±00.07</sub> + 614.62<sub00.26</sub> | 13.48<sub>±00.20</sub> |
| Scala | 0.362<sub>±0.006</sub> | 67.43<sub>±00.09</sub> + 248.88<sub11.36</sub> | 18.63<sub>±00.35</sub> |
| Julia | 0.597<sub>±0.001</sub> | 246.42<sub>±00.24</sub> + 374.41<sub01.06</sub> | 23.23<sub>±00.15</sub> |
| Python/pypy | 0.880<sub>±0.002</sub> | 63.32<sub>±00.09</sub> + 250.27<sub>±00.06</sub> | 34.53<sub>±00.42</sub> |
| Ruby/truffleruby (--jvm) | 1.381<sub>±0.026</sub> | 354.60<sub10.97</sub> + 552.99<sub34.23</sub> | 90.57<sub01.36</sub> |
| Ruby (--jit) | 1.442<sub>±0.004</sub> | 270.43<sub>±00.06</sub> + 147.02<sub>±00.05</sub> | 59.14<sub>±00.99</sub> |
| Lua | 1.478<sub>±0.004</sub> | 2.28<sub>±00.01</sub> + 283.04<sub>±00.48</sub> | 57.46<sub>±00.33</sub> |
| Ruby/truffleruby | 1.506<sub>±0.007</sub> | 294.80<sub>±00.82</sub> + 410.90<sub26.05</sub> | 84.20<sub>±00.88</sub> |
| Ruby/jruby | 1.990<sub>±0.057</sub> | 182.28<sub>±01.67</sub> + 538.37<sub>±28.70</sub> | 102.14<sub>±03.48</sub> |
| Ruby | 2.057<sub>±0.005</sub> | 13.87<sub>±00.07</sub> + 147.07<sub>±00.04</sub> | 82.80<sub>±00.47</sub> |
| Python | 5.022<sub>±0.024</sub> | 10.49<sub>±00.04</sub> + 234.72<sub>±00.26</sub> | 196.62<sub>±02.52</sub> |

# Tests Execution

Expand Down
2 changes: 2 additions & 0 deletions primes/Primes.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
Expand Down Expand Up @@ -131,6 +132,7 @@ private static Iterable<Integer> find(int upperBound, int prefix) {
));
}
}
Collections.sort(result);
return result;
}

Expand Down
6 changes: 3 additions & 3 deletions primes/primes.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#include <algorithm>
#include <iostream>
#include <map>
#include <memory>
#include <queue>
#include <sstream>
#include <unordered_map>
#include <vector>

#include <libnotify.h>
Expand All @@ -18,7 +18,7 @@ static const auto UPPER_BOUND = 5'000'000;
static const auto PREFIX = 32'338;

struct Node {
std::map<char, std::shared_ptr<Node>> children{};
std::unordered_map<char, std::shared_ptr<Node>> children{};
bool terminal = false;
};

Expand Down Expand Up @@ -127,6 +127,7 @@ std::vector<int> find(int upper_bound, int prefix) {
queue.push(std::make_pair(v, prefix + ch));
}
}
std::sort(result.begin(), result.end());
return result;
}

Expand All @@ -148,7 +149,6 @@ std::string to_string(const std::vector<int>& a) {
void verify() {
std::vector<int> left({2, 23, 29});
auto right = find(100, 2);
std::sort(right.begin(), right.end());
if (left != right) {
std::cerr << to_string(left) << " != " << to_string(right) << std::endl;
exit(EXIT_FAILURE);
Expand Down
1 change: 1 addition & 0 deletions primes/primes.cr
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ def find(upper_bound, prefix)
queue.insert(0, {v, prefix + ch})
end
end
result.sort!
result
end

Expand Down
3 changes: 2 additions & 1 deletion primes/primes.jl
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ function find(upper_bound::Int64, search_prefix::Int64)::Vector
end
end

return sort(result)
sort!(result)
return result
end


Expand Down
13 changes: 7 additions & 6 deletions primes/primes.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const PREFIX = 32338;

class Node {
constructor() {
this.children = new Map();
this.children = new Object();
this.terminal = false;
}
}
Expand Down Expand Up @@ -89,10 +89,10 @@ function generateTrie(l) {
for (const el of l) {
let head = root;
for (const ch of el.toString()) {
if (!head.children.has(ch)) {
head.children.set(ch, new Node());
if (!Object.hasOwn(head.children, ch)) {
head.children[ch] = new Node();
}
head = head.children.get(ch);
head = head.children[ch];
}
head.terminal = true;
}
Expand All @@ -105,7 +105,7 @@ function find(upperBound, prefix) {
let head = generateTrie(primes.toList());

for (const ch of strPrefix) {
head = head.children.get(ch);
head = head.children[ch];
if (typeof head === 'undefined') {
return null;
}
Expand All @@ -117,10 +117,11 @@ function find(upperBound, prefix) {
if (top.terminal) {
result.push(toInt(prefix));
}
for (const [ch, v] of top.children) {
for (const [ch, v] of Object.entries(top.children)) {
queue.splice(0, 0, [v, prefix + ch]);
}
}
result.sort();
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion primes/primes.lua
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ local function generate_trie(l)
end

local function dump(arr)
table.sort(arr)
return "[" .. table.concat(arr, ", ") .. "]"
end

Expand All @@ -173,6 +172,7 @@ local function find(upper_bound, prefix)
queue.push({v, prefix .. ch})
end
end
table.sort(result)
return result
end

Expand Down
6 changes: 4 additions & 2 deletions primes/primes.nim
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import deques
import net
import posix
import std/algorithm
import strformat, strutils, sequtils
import tables


const UPPER_BOUND: int = 5_000_000
const PREFIX: int = 32_338

type
NodeRef = ref Node
Node = object
children: OrderedTable[char, NodeRef]
children: Table[char, NodeRef]
terminal: bool
Sieve = object
limit: int
Expand Down Expand Up @@ -102,6 +102,8 @@ proc find(upperBound: int, prefix: int): seq[int] =
for (ch, node) in pair.node.children.pairs():
queue.addFirst(Pair(node: node, str: pair.str & $ch))

result.sort()

proc notify(msg: string) =
let sock = net.dial("127.0.0.1", Port(9001))
defer: sock.close()
Expand Down
2 changes: 2 additions & 0 deletions primes/primes.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ def find(upper_bound, prefix):
result.append(int(prefix))
for ch, v in top.children.items():
queue.insert(0, (v, prefix + ch))

result.sort()
return result


Expand Down
5 changes: 2 additions & 3 deletions primes/primes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,10 +110,9 @@ def find(upper_bound, prefix)
until queue.empty?
(top, prefix) = queue.pop
result.push(prefix.to_i) if top.terminal
top.children.each do |ch, v|
queue.insert(0, [v, prefix + ch])
end
top.children.each { |ch, v| queue.insert(0, [v, prefix + ch]) }
end
result.sort!
result
end

Expand Down
10 changes: 5 additions & 5 deletions primes/primes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::{BTreeMap, VecDeque};
use std::collections::{HashMap, VecDeque};
use std::io::Write;
use std::net::TcpStream;
use std::process;
Expand All @@ -8,14 +8,14 @@ const PREFIX: i32 = 32_338;

#[derive(Debug)]
struct Node {
children: BTreeMap<char, Box<Node>>,
children: HashMap<char, Box<Node>>,
terminal: bool,
}

impl Node {
fn new() -> Node {
Node {
children: BTreeMap::new(),
children: HashMap::new(),
terminal: false,
}
}
Expand Down Expand Up @@ -142,6 +142,7 @@ fn find(upper_bound: usize, prefix: i32) -> Vec<i32> {
queue.push_back((v, new_prefix));
}
}
result.sort_unstable();
result
}

Expand All @@ -153,8 +154,7 @@ fn notify(msg: &str) {

fn verify() {
let left = vec![2, 23, 29];
let mut right = find(100, 2);
right.sort_unstable();
let right = find(100, 2);
if left != right {
eprintln!("{:?} != {:?}", left, right);
process::exit(-1);
Expand Down
1 change: 1 addition & 0 deletions primes/primes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ object Primes {
queue += ((v, prefix + ch))
}
}
scala.util.Sorting.stableSort(result)
Some(result)
}
case None => None
Expand Down
1 change: 1 addition & 0 deletions primes/primes.v
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ fn find(upper_bound usize, prefix int) []int {
queue.insert(0, Pair{v, pair.p_prefix + ch.ascii_str()})
}
}
result.sort()
return result
}

Expand Down
1 change: 1 addition & 0 deletions primes/primes.zig
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ fn find(alloc: std.mem.Allocator, upper_bound: i32, prefix: i32) std.ArrayList(i
queue.prepend(elem);
}
}
std.sort.sort(i32, result.items, {}, comptime std.sort.asc(i32));
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion primes/primes_jit.lua
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,11 @@ local function find(upper_bound, prefix)
queue.push({v, prefix .. ch})
end
end
table.sort(result)
return result
end

local function dump(arr)
table.sort(arr)
return "[" .. table.concat(arr, ", ") .. "]"
end

Expand Down

0 comments on commit ff31ca3

Please sign in to comment.