[libmath-prime-util-perl] 43/181: Use faster bit counting for sieve part of nth prime
Partha P. Mukherjee
ppm-guest at moszumanska.debian.org
Thu May 21 18:51:04 UTC 2015
This is an automated email from the git hooks/post-receive script.
ppm-guest pushed a commit to annotated tag v0.36
in repository libmath-prime-util-perl.
commit fe1f92c8e9cc8d1d5dbc28f132e73f226f74d9b7
Author: Dana Jacobsen <dana at acm.org>
Date: Tue Dec 24 23:47:53 2013 -0800
Use faster bit counting for sieve part of nth prime
---
util.c | 33 ++++++++++++++++++++++++---------
1 file changed, 24 insertions(+), 9 deletions(-)
diff --git a/util.c b/util.c
index ad7f273..ed85656 100644
--- a/util.c
+++ b/util.c
@@ -70,8 +70,12 @@ static int _call_gmp = 0;
void _XS_set_callgmp(int v) { _call_gmp = v; }
int _XS_get_callgmp(void) { return _call_gmp; }
+/* GCC 3.4 - 4.1 has broken 64-bit popcount.
+ * GCC 4.2+ can generate awful code when it doesn't have asm (GCC bug 36041).
+ * When the asm is present (e.g. compile with -march=native on a platform that
+ * has them, like Nahelem+), then it is almost as fast as the direct asm. */
#if BITS_PER_WORD == 64
- #if defined(__GNUC__) && (__GNUC__> 4 || (__GNUC__== 4 && __GNUC_MINOR__> 1))
+ #if defined(__POPCNT__) && defined(__GNUC__) && (__GNUC__> 4 || (__GNUC__== 4 && __GNUC_MINOR__> 1))
#define popcnt(b) __builtin_popcountll(b)
#else
static UV popcnt(UV b) {
@@ -91,9 +95,9 @@ int _XS_get_callgmp(void) { return _call_gmp; }
#endif
#if defined(__GNUC__)
- #define word_aligned(m,wordsize) ((uintptr_t)m & (wordsize-1))
+ #define word_unaligned(m,wordsize) ((uintptr_t)m & (wordsize-1))
#else /* uintptr_t is part of C99 */
- #define word_aligned(m,wordsize) ((unsigned int)m & (wordsize-1))
+ #define word_unaligned(m,wordsize) ((unsigned int)m & (wordsize-1))
#endif
@@ -111,7 +115,7 @@ static UV count_zero_bits(const unsigned char* m, UV nbytes)
UV count = 0;
#if BITS_PER_WORD == 64
if (nbytes >= 16) {
- while ( word_aligned(m,sizeof(UV)) && nbytes--)
+ while ( word_unaligned(m,sizeof(UV)) && nbytes--)
count += byte_zeros[*m++];
if (nbytes >= 8) {
UV* wordptr = (UV*)m;
@@ -318,7 +322,7 @@ UV _XS_prev_prime(UV n)
* (2) we hit maxcount: set position to the index of the maxcount'th prime
* and return count (which will be equal to maxcount).
*/
-static UV count_segment_maxcount(const unsigned char* sieve, UV nbytes, UV maxcount, UV* pos)
+static UV count_segment_maxcount(const unsigned char* sieve, UV base, UV nbytes, UV maxcount, UV* pos)
{
UV count = 0;
UV byte = 0;
@@ -331,11 +335,22 @@ static UV count_segment_maxcount(const unsigned char* sieve, UV nbytes, UV maxco
if ( (nbytes == 0) || (maxcount == 0) )
return 0;
+ /* Do fixed-length word counts to start, with possible overcounting */
+ while ((count+64) < maxcount && sieveptr < maxsieve) {
+ UV top = base + 3*maxcount;
+ UV div = (top < 8000) ? 8 : /* 8 cannot overcount */
+ (top < 1000000) ? 4 :
+ (top < 10000000) ? 3 : 2;
+ UV minbytes = (maxcount-count)/div;
+ if (minbytes > (maxsieve-sieveptr)) minbytes = maxsieve-sieveptr;
+ count += count_zero_bits(sieveptr, minbytes);
+ sieveptr += minbytes;
+ }
/* Count until we reach the end or >= maxcount */
while ( (sieveptr < maxsieve) && (count < maxcount) )
count += byte_zeros[*sieveptr++];
- /* If we went one too far, back up. Count will always be < maxcount */
- if (count >= maxcount)
+ /* If we went too far, back up. */
+ while (count >= maxcount)
count -= byte_zeros[*--sieveptr];
/* We counted this many bytes */
byte = sieveptr - sieve;
@@ -687,7 +702,7 @@ UV _XS_nth_prime(UV n)
segment_size = get_prime_cache(upper_limit, &cache_sieve) / 30;
/* Count up everything in the cached sieve. */
if (segment_size > 0)
- count += count_segment_maxcount(cache_sieve, segment_size, target, &p);
+ count += count_segment_maxcount(cache_sieve, 0, segment_size, target, &p);
release_prime_cache(cache_sieve);
} else {
/* A binary search on RiemannR is nice, but ends up either often being
@@ -740,7 +755,7 @@ UV _XS_nth_prime(UV n)
}
/* Count up everything in this segment */
- count += count_segment_maxcount(segment, segment_size, target-count, &p);
+ count += count_segment_maxcount(segment, 30*segbase, segment_size, target-count, &p);
if (count < target)
segbase += segment_size;
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libmath-prime-util-perl.git
More information about the Pkg-perl-cvs-commits
mailing list