Hi guys. I know that all benchmarks are futile, but I would like to understand
why the C counterpart of the following Nim snippet to calculate the number of
primes in an interval is more than 3 times faster than Nim.
Nim version:
# bm_nim.nim
proc count_prime_numbers(n_low, n_high: int): int =
var nbr = n_low
if nbr mod 2 == 0: # make sure we start with an uneven number
nbr += 1
while nbr < n_high:
let limit = nbr div 2
var is_prim = true
for divisor in 2..<limit:
if nbr mod divisor == 0:
is_prim = false
break
if is_prim:
result += 1
nbr += 2
when isMainModule:
echo(count_prime_numbers(3, 200000))
C version:
// bm_c.c
#include <stdio.h>
int count_prime_numbers(int n_low, int n_high) {
int count_of_primes = 0;
int is_prim, zahl, divisor, limit;
zahl = n_low;
if (zahl % 2 == 0) {zahl += 1;}
while (zahl < n_high) {
is_prim = 1;
limit = zahl / 2;
for (divisor = 2; divisor < limit; divisor++) {
if (zahl % divisor == 0) {
is_prim = 0;
break;
}
}
if (is_prim == 1) {
count_of_primes++;
}
zahl += 2;
}
return count_of_primes;
}
int main(void)
{
printf("%d", count_prime_numbers(3, 200000));
return 0;
}
compiled and run with:
$ nim -d:release c bm_nim
# <compiler output omitted>
$ time ./bm_nim
17983
real 0m8.406s
user 0m8.404s
sys 0m0.000s
$ gcc bm_c.c -o bm_c -O3
$ time ./bm_c
17983
real 0m2.607s
user 0m2.604s
sys 0m0.000s
Some remarks:
* I know that this is not the most efficient way to calculate prime numbers,
I just wanted to compare performance in some nested loops.
* I know very little about C.
* Things I have tried (all without significant change of the performance of
the Nim snippet):
* replaced the for loop by a while loop
* re-implemented the modulo operator
* used uint8 instead of bool for is_prim
In these comparable programs, where does Nim lose performance over C? Are there
options I missed?
Loving Nim, keep up the great work! I tried Rust (again) over the last couple
of days, but Nim is way easier to use!
Kind regards,
Axel