factor: simpler isqrt
function old new delta isqrt_odd 102 87 -15 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
c804d4ec5c
commit
c6476dca54
@ -47,33 +47,37 @@ typedef unsigned long half_t;
|
|||||||
/* Returns such x that x+1 > sqrt(N) */
|
/* Returns such x that x+1 > sqrt(N) */
|
||||||
static inline half_t isqrt(wide_t N)
|
static inline half_t isqrt(wide_t N)
|
||||||
{
|
{
|
||||||
wide_t x;
|
wide_t mask_2bits;
|
||||||
unsigned c;
|
half_t x;
|
||||||
|
|
||||||
// Never called with N < 1
|
// Never called with N < 1
|
||||||
// if (N == 0)
|
// if (N == 0)
|
||||||
// return 0;
|
// return 0;
|
||||||
//
|
|
||||||
/* Count leading zeros */
|
|
||||||
c = 0;
|
|
||||||
while (!(N & TOPMOST_WIDE_BIT)) {
|
|
||||||
c++;
|
|
||||||
N <<= 1;
|
|
||||||
}
|
|
||||||
N >>= c;
|
|
||||||
|
|
||||||
/* Make x > sqrt(n) */
|
/* First approximation x > sqrt(N) - half as many bits:
|
||||||
x = (wide_t)1 << ((WIDE_BITS + 1 - c) / 2);
|
* 1xxxxx -> 111 (six bits to three)
|
||||||
dbg("x:%llx", x);
|
* 01xxxx -> 111
|
||||||
|
* 001xxx -> 011
|
||||||
|
* 0001xx -> 011 and so on.
|
||||||
|
*/
|
||||||
|
x = HALF_MAX;
|
||||||
|
mask_2bits = TOPMOST_WIDE_BIT | (TOPMOST_WIDE_BIT >> 1);
|
||||||
|
while (mask_2bits && !(N & mask_2bits)) {
|
||||||
|
x >>= 1;
|
||||||
|
mask_2bits >>= 2;
|
||||||
|
}
|
||||||
|
dbg("x:%"HALF_FMT"x", x);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
wide_t y = (x + N/x) / 2;
|
half_t y = (x + N/x) / 2;
|
||||||
dbg("y:%llx y^2:%llx (y+1)^2:%llx]", y, y*y, (y+1)*(y+1));
|
dbg("y:%x y^2:%llx", y, (wide_t)y * y);
|
||||||
if (y >= x) {
|
/*
|
||||||
/* Handle degenerate case N = 0xffffffffff...fffffff */
|
* "real" y may be one bit wider: 0x100000000 and get truncated to 0.
|
||||||
if (y == (wide_t)HALF_MAX + 1)
|
* In this case, "real" y is > x. The first check below is for this case:
|
||||||
y--;
|
*/
|
||||||
dbg("isqrt(%llx)=%llx"HALF_FMT, N, y);
|
if (y == 0 || y >= x) {
|
||||||
return y;
|
dbg("isqrt(%llx)=%"HALF_FMT"x", N, x);
|
||||||
|
return x;
|
||||||
}
|
}
|
||||||
x = y;
|
x = y;
|
||||||
}
|
}
|
||||||
@ -92,6 +96,8 @@ static NOINLINE void factorize(wide_t N)
|
|||||||
half_t factor;
|
half_t factor;
|
||||||
half_t max_factor;
|
half_t max_factor;
|
||||||
unsigned count3;
|
unsigned count3;
|
||||||
|
unsigned count5;
|
||||||
|
unsigned count7;
|
||||||
|
|
||||||
if (N < 4)
|
if (N < 4)
|
||||||
goto end;
|
goto end;
|
||||||
@ -103,6 +109,8 @@ static NOINLINE void factorize(wide_t N)
|
|||||||
|
|
||||||
max_factor = isqrt_odd(N);
|
max_factor = isqrt_odd(N);
|
||||||
count3 = 3;
|
count3 = 3;
|
||||||
|
count5 = 6;
|
||||||
|
count7 = 9;
|
||||||
factor = 3;
|
factor = 3;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/* The division is the most costly part of the loop.
|
/* The division is the most costly part of the loop.
|
||||||
@ -123,12 +131,19 @@ static NOINLINE void factorize(wide_t N)
|
|||||||
* ^ ^ ^ ^ ^ ^ ^ _ ^ ^ _ ^ ^ ^ ^
|
* ^ ^ ^ ^ ^ ^ ^ _ ^ ^ _ ^ ^ ^ ^
|
||||||
* (^ = primes, _ = would-be-primes-if-not-divisible-by-5)
|
* (^ = primes, _ = would-be-primes-if-not-divisible-by-5)
|
||||||
*/
|
*/
|
||||||
--count3;
|
count7--;
|
||||||
if (count3 == 0) {
|
count5--;
|
||||||
|
count3--;
|
||||||
|
if (count3 && count5 && count7)
|
||||||
|
continue;
|
||||||
|
if (count3 == 0)
|
||||||
count3 = 3;
|
count3 = 3;
|
||||||
|
if (count5 == 0)
|
||||||
|
count5 = 5;
|
||||||
|
if (count7 == 0)
|
||||||
|
count7 = 7;
|
||||||
goto next_factor;
|
goto next_factor;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
end:
|
end:
|
||||||
if (N > 1)
|
if (N > 1)
|
||||||
printf(" %llu", N);
|
printf(" %llu", N);
|
||||||
|
Loading…
Reference in New Issue
Block a user