I found over the weekend a few places in the code giving me arithmetic overflow errors on certain inputs. I’ve updated the code to eliminate the problems, but I don’t see why they existed (I thought I accounted for their possibilities, but guess I didn’t).
Here are the gists again to the updated code.
twinprimes_ssoz
cousinprimes_ssoz
Here’s the nature of the problem.
I was testing for values at the upper 64-bit range, (2^64 -1 = 18446744073709551615)
When running the code with these inputs it gives the correct results (need 16GB of mem).
CRYSTAL_WORKERS=16 ./twinprimes_ssoz 18436744073709551615 18436744073709000000
threads = 16
using Prime Generator parameters for P5
segment size = 18388 resgroups for seg bitarray
twinprime candidates = 55167; resgroups = 18389
each of 3 threads has nextp[2 x 331650] array
setup time = 14.445965 secs
perform twinprimes ssoz sieve
3 of 3 twinpairs done
sieve time = 0.00788 secs
total time = 14.453845 secs
last segment = 18389 resgroups; segment slices = 1
total twins = 395; last twin = 18436744073709550662+/-1
But when I used values at the absolute upper limit I got arithmetic overflow errors.
CRYSTAL_WORKERS=16 ./twinprimes_ssoz 18446744073709551615 18446744073709000000
threads = 16
using Prime Generator parameters for P5
segment size = 18388 resgroups for seg bitarray
twinprime candidates = 55164; resgroups = 18388
prime = 555829Unhandled exception: Arithmetic overflow (OverflowError)
from crystal/share/crystal/src/kernel.cr:25:1 in 'twinprimes_ssoz'
from twinprimes_ssozgist.cr:284:1 in '__crystal_main'
from crystal/share/crystal/src/crystal/main.cr:115:5 in 'main'
from /lib64/libc.so.6 in '??'
from /lib64/libc.so.6 in '__libc_start_main'
from ../sysdeps/x86_64/start.S:117 in '_start'
from ???
That error message was of no help, but I eventually placed some puts lines on certain values in places and figured it out.
The first place causing an error was in the routine sozpg, which generates sieving primes.
n, rem = start_num.divmod prime
primes << prime if (res_0 <= prime <= val) && (prime &* (n + 1) <= end_num || rem == 0)
^
Adding the & eliminated that overflow, but I don’t see why it was occurring, because both prime and end_num are u64 values.
The other overflow came in twins_sieve, where again, adding &s fixed the overflows.
ki += 1 if ((ki &* modpg) &+ r_hi - 2) < start_num
k_max -= 1 if ((k_max - 1) &* modpg &+ r_hi) > end_num
Again ki, k_max, start|end_num are all u64s.
1: Can someone explain why these overflows occur.
2: Will 1.5.0 fix having to explicitly put these & operations in the code?
After the fixes the code runs correctly for these inputs.
CRYSTAL_WORKERS=16 ./twinprimes_ssoz 18446744073709551615 18446744073709000000
threads = 16
using Prime Generator parameters for P5
segment size = 18388 resgroups for seg bitarray
twinprime candidates = 55164; resgroups = 18388
each of 3 threads has nextp[2 x 203280218] array
setup time = 18.342097 secs
perform twinprimes ssoz sieve
3 of 3 twinpairs done
sieve time = 5.344191 secs
total time = 23.686288 secs
last segment = 18388 resgroups; segment slices = 1
total twins = 361; last twin = 18446744073709550772+/-1
FYI: 18446744073709550772+/-1 is the largest twin prime within 2^64.