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 u64
s.
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.