Computation of the sum of prime numbers in different languages
computing
Description
The project allows to see the difference of speed of program’s execution between multiple languages with one algorithm which computes the sum of prime numbers. Also, the goal is to use native libraries for each language.
Here is the source of the algorithm
Code
import math
from time import perf_counter
def chrono(function):
def inner(*args):
= perf_counter()
start = function(*args)
result = perf_counter() - start
duration print("%0.3f x 10e(-3) seconds" % (duration * 1_000))
return result
return inner
# @chrono
def P10(n):
= int(n ** 0.5)
r assert r * r <= n and (r + 1) ** 2 > n
= [n // i for i in range(1, r + 1)]
V += list(range(V[-1] - 1, 0, -1))
V = {i: i * (i + 1) // 2 - 1 for i in V}
S for p in range(2, r + 1):
if S[p] > S[p - 1]: # p is prime
= S[p - 1] # sum of primes smaller than p
sp = p * p
p2 for v in V:
if v < p2:
break
-= p * (S[v // p] - sp)
S[v] return S[n]
def _format(dist, value):
return value + " " * (dist - len(value))
print("Power | Time (µs) | Resultat")
print("========================================")
for i in range(1, 9):
= perf_counter()
start = P10(10 ** i)
result = int((perf_counter() - start) * 1_000_000)
duration print(_format(5, str(i)) + " | " + _format(9, str(duration)) + " | " + str(result))
use std::collections::HashMap;
use std::time::Instant;
type Dict = HashMap<u64, u128>;
fn get_keys(n: u64, half_size: u64) -> Vec<u64> {
// Calculation of keys used in the HashMap
let mut v: Vec<u64> = Vec::new();
for i in 0..half_size + 1 {
.push(n / (i + 1));
v}
let v_max = v[half_size as usize];
for i in (1..v_max).rev() {
.push(i);
v}
v}
fn get_sums(keys: &[u64]) -> Dict {
// Initialisation du hashmap
let mut hmap = HashMap::new();
for key in keys.iter() {
let big_key = *key as u128;
let value = (big_key * (big_key + 1)) / 2 - 1;
.insert(*key, value);
hmap}
hmap}
fn calculate_sums(mut hmap: Dict, keys: &[u64], square_n: u64) -> Dict {
for p in 2..square_n + 1 {
let current_sum = hmap[&(p - 1)];
if hmap[&p] > current_sum {
let p_square = p * p;
for key in keys.iter() {
if *key < p_square {
break;
}
let new_value = hmap[&key] - (p as u128) * (hmap[&(key / p)] - current_sum);
.insert(*key, new_value);
hmap}
}
}
hmap}
fn primes(n: u64) -> u128 {
let square_n = (n as f64).sqrt() as u64;
assert!(square_n * square_n <= n && (square_n + 1).pow(2) > n);
let half_size = square_n - 1;
let keys = get_keys(n, half_size);
let p_keys = &keys;
let mut all_sums = get_sums(p_keys);
= calculate_sums(all_sums, p_keys, square_n);
all_sums &n]
all_sums[}
fn format(dist: usize, value: &String) -> String {
let mut v: String = value.to_string();
for _ in 1..(dist - (*value).len()) {
+= &" ";
v }
return v;
}
fn main() {
println!("Power | Time (µs) | Resultat");
println!("========================================");
for i in 1..9 {
let now = Instant::now();
let n: u64 = (10_u64).pow(i);
let value: u128 = primes(n);
let new_now = Instant::now();
println!(
"{} | {} | {}",
6, &(i.to_string())),
format(10, &(new_now.duration_since(now).as_micros().to_string())),
format(
value;
)}
}
#include <iostream>
#include <cstdio>
#include <cmath>
#include <assert.h>
#include <stdlib.h>
#include <unordered_map>
#include <chrono>
#include <string>
using namespace std::chrono;
using namespace std;
typedef unordered_map<long, long long> umap;
void generate_key_array(long long key_array[], long long n, long half_size){
// generation of a key array which serves for the dictionary all_sums
long long value;
for(long index = 0; index <= half_size+1; index++){
= (long long) n / (index + 1);
value [index] = value;
key_array}
for(long index = half_size + 1; index < 2 * half_size + 1; index++){
= key_array[index - 1] - 1;
value [index] = value;
key_array}
}
void generate_all_sums(umap& all_sums, long long key_array[], long size){
// generation of dictionary all_sums
long long value;
for(long index = 0; index < size; index++){
= key_array[index];
value // storing sum of numbers for 1 to key
[value] = ((long long) (value*(value + 1))/2) - 1;
all_sums}
}
void calculate_new_sums(umap& all_sums, long long key_array[], long long square_root){
// core of the program for calculate the sum of prime numbers
long long current_sum;
long long p_square;
long index;
long long key;
long long second_key;
for(long p = 2; p <= square_root; p++){
= all_sums[p - 1];
current_sum if(all_sums[p] > current_sum){ //if p is prime
= p * p;
p_square = 0;
index = key_array[index];
key
// while the key is lower than p * p
while(key >= p_square){
= key / p;
second_key // updating the sum of the key 'key'
[key] -= p * (all_sums[second_key] - current_sum);
all_sums++;
index= key_array[index];
key }
}
}
}
long long P10(long long n){
long long square_root = (long long) sqrt(n);
//check if the program will work
assert ((square_root*square_root <= n) && ((square_root + 1) * (square_root + 1) > n));
long long final_sum;
long half_size = square_root - 1;
long long* key_array = new long long [half_size * 2 + 1];
(key_array, n, half_size);
generate_key_array
long size = 2 * half_size + 1;
// dictionary of sums
;
umap all_sums(all_sums, key_array, size);
generate_all_sums(all_sums, key_array, square_root);
calculate_new_sums
= all_sums[n];
final_sum delete key_array;
.clear();
all_sums
return final_sum;
}
(int dist, string value){
string format= "";
string hole for(int _=0; _<=(dist-(int)(value).size()); _++){
+=" ";
hole}
return value + hole;
}
int main(){
// Goal: 100 000 000 000
// Awaited result: 201 467 077 743 744 681 014
auto start = high_resolution_clock::now();
long long value;
<< "Power | Time (µs) | Result" << endl;
cout << "========================================" << endl;
cout for(int i=1; i<=8; i++){
// cout << "Power: " << i << endl;
= P10(pow(10,i));
value auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop - start);
// cout << value << endl;
// cout << "Time taken by function: " << duration.count() << " x 10e(-3) seconds" << endl;
<< format(4, std::to_string(i)) << " | " << format(8, to_string(duration.count())) << " | " << value << endl;
cout }
return 0;
}
defmodule Primes do
@spec sqrt(integer) :: integer
defp sqrt(n) do
(:math.sqrt(n))
truncend
@spec head_keys(integer, integer) :: [integer]
defp head_keys(n, root_n) do
1..(root_n + 1)
|> Enum.map(&div(n, &1))
end
@spec tail_keys(integer, integer) :: [integer]
defp tail_keys(n, root_n) do
Enum.to_list(div(n, root_n)..1)
end
@spec generate_keys(integer, integer) :: [integer]
defp generate_keys(n, root_n) do
(n, root_n) ++ tail_keys(n, root_n)
head_keysend
@spec n_sums(integer) :: {integer}
defp n_sums(i) do
{i, div(i * (i + 1), 2) - 1}
end
@spec generate_sums([integer]) :: %{integer => integer}
defp generate_sums(keys) do
Enum.into(keys, %{}, &n_sums(&1))
end
@spec small(integer, %{integer => integer}, integer, integer) :: {integer}
defp small(v, dict, p, sp) do
{v, dict[v] - p * (dict[div(v, p)] - sp)}
end
@spec calculate(%{integer => integer}, [integer], integer, integer) :: %{integer => integer}
defp calculate(sums, keys, p, limit) when p < limit do
= sums[p - 1]
sum_p
if sums[p] > sum_p do
Enum.take_while(keys, &(&1 >= p * p))
|> Enum.into(%{}, &small(&1, sums, p, sum_p))
|> (&Map.merge(sums, &1)).()
|> calculate(keys, p + 1, limit)
else
(sums, keys, p + 1, limit)
calculateend
end
@spec calculate(%{integer => integer}, [integer], integer, integer) :: %{integer => integer}
defp calculate(sums, _, p, limit) when p >= limit do
sumsend
@spec sum_up_to(integer) :: integer
def sum_up_to(n) do
= sqrt(n)
root_n = generate_keys(n, root_n)
keys = generate_sums(keys)
sums (sums, keys, 2, root_n + 1)[n]
calculateend
@spec measure(function) :: integer
def measure(function) do
function|> :timer.tc()
|> elem(0)
# divide by 1_000 for milliseconds
|> Kernel./(1)
end
end
defmodule Formatter do
@spec add_space(integer, charlist) :: charlist
defp add_space(0, string) do
stringend
@spec add_space(integer, charlist) :: charlist
defp add_space(i, string) do
(i - 1, string <> " ")
add_spaceend
@spec format(integer, integer) :: charlist
defp format(dist, value) do
= "#{value}"
string_v (dist - String.length(string_v), string_v)
add_spaceend
@spec format_all(integer, integer, integer) :: nil
def format_all(power, time, value) do
IO.puts("#{format(5, power)} | #{format(9, time)} | #{value}")
end
end
IO.puts("Power | Time (µs) | Result")
IO.puts("=========================================")
Primes.sum_up_to(100)
1..8
|> Enum.map(fn exp ->
= Primes.measure(fn -> Primes.sum_up_to(:math.pow(10, exp) |> round) end)
f Formatter.format_all(exp, f |> round, Primes.sum_up_to(:math.pow(10, exp) |> round))
end)
import java.util.HashMap;
import java.util.Vector;
import java.lang.Math;
public class Main{
static Vector<Integer> get_keys(Integer n, Integer half_size){
Vector<Integer> V = new Vector<>();
for (Integer i = 0; i < half_size; i++){
.add(n / (i + 1));
V}
Integer vmax = V.get(V.size() - 1) - 1;
for (Integer i = vmax; i > 0; i--){
.add(i);
V}
return V;
}
static HashMap<Integer, Long> get_sums(Vector<Integer> keys){
HashMap<Integer, Long> hmap = new HashMap<>();
for (int key: keys){
long big_key = key;
long value = (big_key * (big_key + 1)) / 2 - 1;
.put(key, value);
hmap}
return hmap;
}
static HashMap<Integer, Long> calculate_sums(HashMap<Integer, Long> hmap, Vector<Integer> keys, int square_n){
for (Integer p = 2; p < square_n + 1; p++){
long current_sum = hmap.get(p - 1);
if (hmap.get(p) > current_sum){
long p_square = p * p;
for (int key: keys){
if (key < p_square){
break;
}
long new_value = hmap.get(key) - (long)p * (hmap.get(key / p) - current_sum);
.put(key, new_value);
hmap}
}
}
return hmap;
}
static long primes(int n){
int square_n = (int) Math.sqrt(n);
assert square_n * square_n <= n && (square_n + 1) * (square_n + 1) > n;
int half_size = square_n - 1;
Vector<Integer> keys = Main.get_keys(n, half_size);
HashMap<Integer, Long> all_sums = Main.get_sums(keys);
= Main.calculate_sums(all_sums, keys, square_n);
all_sums return all_sums.get(n);
}
static String format(int dist, String value){
return value + " ".repeat(dist - value.length());
}
public static void main(String[] args){
= new Main();
Main App System.out.println("Power | Time (µs) | Resultat");
System.out.println("========================================");
primes(100);
for (int i = 1; i < 9; i++){
long start = System.nanoTime();
long result = primes((int) Math.pow(10, i));
long duration = (System.nanoTime() - start) / 1_000;
System.out.println(
.format(5, String.valueOf(i)) + " | " +
Main.format(9, String.valueOf(duration)) + " | " +
MainString.valueOf(result)
);
}
}
}
function P10(n)
r = math.floor(n^0.5)
assert(r * r <= n and (r + 1)^2 > n)
V = {}
for i = 1, r + 1, 1 do
table.insert(V, n // i)
end
for i = V[#V] - 1, 1, -1 do
table.insert(V, i)
end
S = {}
for _, i in ipairs(V) do
S[i] = i * (i + 1) // 2 - 1
end
for p = 2, r, 1 do
if S[p] > S[p - 1] then
sp = S[p - 1]
p2 = p * p
for _, v in ipairs(V) do
if v < p2 then
break
end
S[v] = S[v] - p * (S[v // p] - sp)
end
end
end
return S[n]
end
function format(dist, value)
return value .. string.rep(" ", (dist - string.len(value)))
end
print("Power | Time (µs) | Resultat")
print("========================================")
for i = 1, 8, 1 do
start = os.clock()
result = P10(math.floor(10^i))
duration = math.floor((os.clock() - start) * 10^6)
print(format(5, tostring(i)) .. " | " .. format(9, tostring(duration)) .. " | " .. tostring(result))
end
const {performance} = require("perf_hooks");
function P10(n){
var r = Math.floor(n ** 0.5);
console.assert(r * r <= n && Math.pow(r + 1, 2) > n);
var V = [];
for (let i = 1; i < r + 1; i++){
.push(Math.floor(n / i));
V
}for (let i = V[V.length - 1] - 1; i > 0; i--){
.push(i);
V
}var S = V.reduce((S, i) => {
= Math.floor(i * (i + 1) / 2) - 1
S[i] return S;
, {});
}var length = V.length;
for (let p = 2; p < r + 1; p++){
if (S[p] > S[p - 1]) {
var sp = S[p - 1];
var p2 = p * p;
for (let index = 0; index < length; index++){
let v = V[index];
if (v < p2){
break;
}-= p * (S[Math.floor(v / p)] - sp);
S[v]
}
}
}return S[n];
}
function format(dist, value){
return value + " ".repeat(dist - value.length)
}
console.log("Power | Time (µs) | Resultat")
console.log("========================================")
P10(100)
for (let i=1; i<9; i++){
var start = performance.now();
var result = P10(Math.floor(Math.pow(10, i)));
var duration = Math.floor((performance.now() - start) * 1_000);
console.log(format(5, String(i)) + " | " + format(9, String(duration)) + " | " + String(result));
}
import scala.collection.mutable.HashMap
import scala.collection.immutable.Vector
import scala.math.sqrt
import scala.math.pow
import scala.math.BigInt
def get_keys(n: Long, half_size:Long): Vector[Long] =
var v = Vector.range(0L, half_size + 1L).map(i => n / (i + 1))
val vmax = v(half_size.asInstanceOf[Int])
++ Vector.range(1L, vmax).reverse
v
def get_sums(keys: Vector[Long]) : HashMap[Long, BigInt] =
var hmap = HashMap.empty[Long, BigInt]
for key <- keys do
val k = BigInt(key)
val value = (k * (k + 1)) / 2 - 1
.put(key, value)
hmap
hmap
def calculate_sums(hmap: HashMap[Long, BigInt], keys: Vector[Long], square_n: Long): HashMap[Long, BigInt] =
var cmap = hmap.clone()
for p <- (2L to square_n) do
val current_sum = cmap(p - 1)
if (cmap(p) > current_sum) {
val p_square = p * p
for key <- keys.takeWhile(p => p >= p_square) do
val new_value = cmap(key) - p * (cmap(key / p) - current_sum)
.update(key, new_value)
cmap}
cmap
def primes(n: Long): BigInt =
val square_n = sqrt(n.asInstanceOf[Float]).asInstanceOf[Long]
val half_size = square_n - 1
val keys = get_keys(n, half_size)
var all_sums = get_sums(keys)
= calculate_sums(all_sums, keys, square_n)
all_sums all_sums(n)
def add_space(i:Int, string:String) : String =
if (i == 0){
return string
} else {
return add_space(i - 1, string.concat(" "))
}
def format(dist:Int, string: String): String =
add_space(dist - string.length(), string)
def main() =
@main val result = primes(10)
println("Power | Time (µs) | Resultat")
println("========================================")
for power <- (1 to 8) do
val start = System.nanoTime
val n = pow(10.0, power.asInstanceOf[Double]).asInstanceOf[Long]
val result = primes(n)
val duration = ((System.nanoTime - start) / 1e3d).asInstanceOf[Int]
println(s"${format(5, s"$power")} | ${format(9, s"$duration")} | $result")
Graph
The first graph is the execution time (in \(\mu s\)) given the power of \(10^x\). The second graph is the execution time (in \(\log(\mu s)\)) after the application of the logarithm function given the power of \(10^x\). You can interact with the legend (for instance, click on elixir
).
Notes
The idea comes from the challenge Euler problem n°245 where one part of the problem involves to compute the sum of prime numbers up to \(10^{11}\).