File Coverage

powerful.c
Criterion Covered Total %
statement 137 158 86.7
branch 220 304 72.3
condition n/a
subroutine n/a
pod n/a
total 357 462 77.2


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4              
5             #include "ptypes.h"
6             #define FUNC_isqrt 1
7             #define FUNC_ctz 1
8             #define FUNC_gcd_ui 1
9             #define FUNC_ipow 1
10             #include "util.h"
11             #include "sort.h"
12             #include "sieve.h"
13             #include "cache.h"
14             #include "constants.h"
15             #include "inverse_interpolate.h"
16             #include "factor.h"
17              
18 1233           bool is_powerful(UV n, UV k) {
19             UV pk;
20             int res;
21              
22 1233 100         if (n <= 1) return (n==1);
23 1196 100         if (k <= 1) return 1;
24              
25 1134 100         if (!(n&1)) { /* Check and remove all multiples of 2 */
26 588 100         if (n & ((UVCONST(1) << k)-1)) return 0;
27 240 50         n >>= ctz(n);
28 240 100         if (n == 1) return 1;
29             }
30              
31 766 50         if (k > MPU_MAX_POW3) return 0;
32             /* if (k > logint(n,3)) return 0; */
33              
34             /* Quick checks */
35 766 100         if (k == 2) {
36 470 100         if ( (!(n % 3) && (n % 9))
    100          
37 384 100         || (!(n % 5) && (n % 25))
    100          
38 338 100         || (!(n % 7) && (n % 49))
    100          
39 306 100         || (!(n % 11) && (n % 121))
    100          
40 470 100         || (!(n % 13) && (n % 169)) ) return 0;
    100          
41 296 100         } else if (k == 3) {
42 123 100         if ( (!(n % 3) && (n % 27))
    100          
43 117 100         || (!(n % 5) && (n % 125))
    100          
44 114 100         || (!(n % 7) && (n % 343))
    100          
45 123 100         || (!(n % 11) && (n % 1331)) ) return 0;
    100          
46             } else {
47 173 100         if ( (!(n % 3) && (n % 81))
    50          
48 119 100         || (!(n % 5) && (n % 625))
    50          
49 101 100         || (!(n % 7) && (n % 2401))
    50          
50 173 100         || (!(n % 11) && (n % 14641)) ) return 0;
    50          
51             }
52              
53             #if 0 /* Full factoring. Very simple and reasonably efficient. */
54             {
55             factored_t nf = factorint(n);
56             uint32_t i;
57             for (i = 0; i < nf.nfactors; i++)
58             if (nf.k[i] < k)
59             return 0;
60             return 1;
61             }
62             #endif
63              
64             /* Rather than full factoring, we'll use trial division. For k=2, we
65             * only need to check up to the fourth root of n, and k=3 to the sixth.
66             * Even for k=2 this is faster than full factoring on average. */
67              
68             /* At every checkpoint (new prime p) for k=2 either:
69             * 1) N < p^4 and N=1, p^2, q^2, p^3, or q^3. (q>p). Return 1.
70             * 2) N < p^4 otherwise, N cannot be powerful. Return 0;
71             * 3) N = p^4 is_square caught this and returned 1.
72             * So the next possibility is p^2 * q^2 where q = next_prime(p).
73             * Check n < p^4 before each new prime, and condition 1 after modifying n.
74             */
75              
76 457 50         if (n == 1 || powerof(n) >= k) return 1;
    100          
77              
78             #define LCHECK_POWERFUL(n, p, k) \
79             pk = ipow(p,k); \
80             if (n < pk*pk) { res = 0; break; } \
81             if (!(n%p)) { \
82             if (n%pk) { res = 0; break; } \
83             for (n /= pk; (n%p) == 0; n /= p) ; \
84             if (n == 1 || powerof(n) >= k) { res = 1; break; } \
85             }
86             #define CHECK_POWERFUL(n, p, k) \
87             do { LCHECK_POWERFUL(n, p, k); } while (0); \
88             if (res != -1) return res;
89              
90 320           res = -1;
91 350 100         CHECK_POWERFUL(n, 3, k); if (k >= 14 || n < ipow( 5,2*k)) return 0;
    100          
    50          
    100          
    50          
    50          
    100          
    50          
    100          
92 88 50         CHECK_POWERFUL(n, 5, k); if (k >= 12 || n < ipow( 7,2*k)) return 0;
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
93 62 50         CHECK_POWERFUL(n, 7, k); if (k >= 10 || n < ipow(11,2*k)) return 0;
    100          
    50          
    100          
    50          
    50          
    50          
    50          
    100          
94              
95 150 50         START_DO_FOR_EACH_PRIME(11, rootint(n,2*k)) {
    50          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    50          
    100          
96 113 100         LCHECK_POWERFUL(n, p, k);
    100          
    50          
    50          
    50          
    50          
97             } END_DO_FOR_EACH_PRIME
98 41           return (res == 1);
99             }
100              
101              
102 15370           static UV _pcr(UV n, UV k, unsigned char* isf, UV m, UV r) {
103 15370           UV i, sum = 0, lim = rootint(n/m, r);
104              
105 15370 50         if (r <= k) return lim;
106              
107 15370 100         if (r-1 == k) {
108 21436 100         for (i = 1; i <= lim; i++)
109 15934 100         if (isf[i] && gcd_ui(m,i) == 1)
    100          
110 10143           sum += rootint(n/(m*ipow(i,r)),k);
111             } else {
112 29197 100         for (i = 1; i <= lim; i++)
113 19329 100         if (isf[i] && gcd_ui(m,i) == 1)
    100          
114 14970           sum += _pcr(n, k, isf, m * ipow(i,r), r-1);
115             }
116 15370           return sum;
117             }
118              
119 293           UV powerful_count(UV n, UV k) {
120 293           UV i, r, lim, sum = 0;
121             unsigned char *isf;
122              
123 293 100         if (k <= 1 || n <= 1) return n;
    100          
124 232 50         if (k >= BITS_PER_WORD) return 1;
125              
126 232           lim = rootint(n, k+1);
127 232           isf = range_issquarefree(0, lim); /* in util.c */
128              
129 232 100         if (k == 2) {
130 86891 100         for (i = 1; i <= lim; i++)
131 86837 100         if (isf[i])
132 52851           sum += isqrt(n/(i*i*i));
133             } else {
134             /* sum = _pcr(n, k, isf, 1, 2*k-1); */
135 178           r = 2*k-1;
136 178           lim = rootint(n, r);
137 668 100         for (i = 1; i <= lim; i++)
138 490 100         if (isf[i])
139 400           sum += _pcr(n, k, isf, ipow(i,r), r-1);
140             }
141              
142 232           Safefree(isf);
143 232           return sum;
144             }
145              
146             /* We want:
147             * k=0 turned into k=2 in XS (0 here ok)
148             * n=0 undef in XS (0 here ok)
149             * k=1 => n
150             * n=1 => 1
151             * n=2 => 1<
152             * overflow here should return 0
153             */
154 3           UV nth_powerful(UV n, UV k) {
155             static unsigned char const mink[20+1] = {0,0,1,2,4,6,7,9,11,12,14,16,18,19,21,23,24,26,28,30,31};
156             #if BITS_PER_WORD == 64
157             static UV const maxpow[11] = {0,UV_MAX,9330124695,11938035,526402,85014,25017,10251,5137,2903,1796};
158             #else
159             static UV const maxpow[11] = {0,UV_MAX,140008,6215,1373,536,281,172,115,79,57};
160             #endif
161             UV lo, hi, max;
162             double nc, npow, nest, dlo, dhi;
163              
164 3 50         if (k == 0 || k >= BITS_PER_WORD) return 0;
    50          
165 3 50         if (k == 1 || n <= 1) return n;
    50          
166              
167 3 100         max = (k <= 10) ? maxpow[k] : powerful_count(UV_MAX,k);
168 3 50         if (n > max) return 0;
169              
170 3 100         if (n <= 20 && k >= mink[n]) return UVCONST(1) << (k+(n-2));
    50          
171             /* Now k >= 2, n >= 4 */
172              
173 3           nc = pow(n, 2) / pow(2.1732543125195541, 2);
174              
175 3 100         if (k == 2) { /* From Mincu and Panaitopol 2009 */
176 1           npow = pow(n, 5.0/3.0);
177 1           dlo = nc + 0.3 * npow;
178 1           dhi = nc + 0.5 * npow;
179 1           lo = (UV) dlo;
180 1 50         hi = (n < 170) ? 8575 : (dhi >= UV_MAX) ? UV_MAX : 1 + (UV) dhi;
    0          
181 2 50         } else if (k == 3) {
182             /* Splitting the range is hacky but overall this isn't bad */
183 0 0         if (n < 84000) {
184 0           nest = .06003 * pow(n, 2.865);
185 0           dlo = 0.96 * (nc + nest);
186 0           dhi = 1.08 * (nc + nest);
187             } else {
188 0           nest = .02209 * pow(n, 2.955);
189 0           dlo = 0.987 * (nc + nest);
190 0           dhi = 1.020 * (nc + nest);
191             }
192 0           lo = (UV) dlo;
193 0 0         if (n < 900) dhi *= 1.3;
194 0 0         if (n < 160) dhi = 1.3 * dhi + 600;
195 0 0         hi = (dhi >= UV_MAX) ? UV_MAX : 1 + (UV) dhi;
196 2 100         } else if (k <= 10) {
197             /* Slopppy but better than linear. 4 <= k <= 10. */
198 1 50         if (n < 200) {
199 1           npow = pow(n, 3.031 + 0.460*(k-4));
200 1           nest = (.5462 / pow(1.15, k-4)) * npow;
201 1           dlo = 0.51 * (nc + nest);
202 1           dhi = 1.86 * (nc + nest);
203             } else {
204 0           npow = pow(n, 3.690 + 0.665*(k-4));
205 0           nest = (.01275 / pow(4.11, k-4)) * npow;
206 0           dlo = 0.70 * (nc + nest);
207 0           dhi = 4.3 * (nc + nest);
208             }
209 1           lo = (UV) dlo;
210 1 50         hi = (dhi >= UV_MAX) ? UV_MAX : 1 + (UV) dhi;
211             } else {
212 1           lo = (UVCONST(1) << (k+1))+1;
213 1           hi = UV_MAX;
214             /* Linear from min to max rather than a nice power fit as above */
215 1 50         if (n < max) hi = lo + (((double)n / (double)max) * (UV_MAX-lo) + 1);
216             /* Alternately hi=0 which makes interpolation routine handle it. */
217             }
218              
219 3           return inverse_interpolate_k(lo, hi, n, k, &powerful_count, 0);
220             }
221              
222              
223 21879           static UV _sumpowerful(UV m, UV r, UV n, UV k, unsigned char* isf) {
224             UV i, rootdiv, sum;
225              
226 21879 50         if (r < k) return m;
227              
228 21879           rootdiv = rootint(n/m, r);
229              
230 21879 100         if (r == k) return m * powersum(rootdiv, r);
231              
232 43201 100         for (sum = 0, i = 1; i <= rootdiv; i++)
233 31504 100         if (isf[i] && gcd_ui(i,m) == 1)
    100          
234 21706           sum += _sumpowerful(m * ipow(i,r), r-1, n, k, isf);
235              
236 11697           return sum;
237             }
238 179           UV sumpowerful(UV n, UV k)
239             {
240             UV lim, sum;
241             unsigned char *isf;
242              
243             #if BITS_PER_WORD == 64
244             static UV const maxpow[41] = {0,6074000999,8676161894447,263030040471727,
245             1856371767674975,6768543273131775,17199267839999999,35098120384607510,
246             62985599999999999,104857599999999999,157641800537109374,246512345193381887,
247             312499999999999999,406381963906121727,499999999999999999,592297667290202111,
248             701982420492091391,935976560656121855,1184595334580404223,1350851717672992088,
249             1579460446107205631,2105947261476274175,2369190669160808447,
250             4052555153018976266,4738381338321616895,7450580596923828124,
251             7450580596923828124,7450580596923828124,
252             UVCONST(9223372036854775807),UVCONST(9223372036854775807),
253             UVCONST(9223372036854775807),UVCONST(9223372036854775807),
254             UVCONST(9223372036854775807),UVCONST(9223372036854775807),
255             UVCONST(9223372036854775807),UVCONST(9223372036854775807),
256             UVCONST(9223372036854775807),UVCONST(9223372036854775807),
257             UVCONST(9223372036854775807),UVCONST(9223372036854775807),
258             UVCONST(12157665459056928800)};
259              
260 179 100         if (k == 0 || n == 0) return 0;
    50          
261 178 50         if (k >= 64) return 1;
262 178 50         if (k < 41 && n > maxpow[k]) return 0;
    100          
263             #else
264             static UV const maxpow[21] = {0,92681,3367224,18224999,48599999,102036671,161243135,244140624,362797055,536870911,725594111,1088391167,1220703124,1220703124,2147483647,2147483647,2147483647,2147483647,2147483647,2147483647,3486784400U};
265              
266             if (k == 0 || n == 0) return 0;
267             if (k >= 32) return 1;
268             if (k < 21 && n > maxpow[k]) return 0;
269             #endif
270              
271 175 100         if (k == 1) return (n+1)/2 * (n|1);
272              
273 173           lim = rootint(n, k+1);
274 173           isf = range_issquarefree(0, lim);
275 173           sum = _sumpowerful(1, 2*k-1, n, k, isf);
276 173           Safefree(isf);
277 173           return sum;
278             }
279              
280 610           static void _pcg(UV lo, UV hi, UV k, UV m, UV r, UV *pn, UV *npn)
281             {
282 610           UV v, *pnptr = pn + *npn, beg = 1, end = rootint(hi/m,r);
283 610 100         if (r > k) {
284 1198 100         for (v = beg; v <= end; v++) {
285 979 100         if (gcd_ui(m,v) == 1 && is_square_free(v))
    100          
286 602           _pcg(lo, hi, k, m*ipow(v,r), r-1, pn, npn);
287             }
288             } else {
289 391 100         if (lo > m) {
290 370           UV lom = (lo/m)+!!(lo%m); /* ceildiv(lo,m) */
291 370           beg = rootint(lom, r);
292 370 100         if (ipow(beg,r) != lom) beg++;
293             }
294 468 100         for (v = beg; v <= end; v++)
295 77           *pnptr++ = m * ipow(v,r);
296 391           *npn += end-beg+1;
297             }
298 610           }
299              
300 10           UV* powerful_numbers_range(UV* npowerful, UV lo, UV hi, UV k)
301             {
302             UV *pn, npn, i;
303              
304             /* For small ranges it is faster to test each number vs generate. */
305 10           UV const single_thresh = ( (lo < 500000U) ? 30
306 10 100         : (lo < 400000000U) ? 160 : 600 )
    50          
307 10 100         * ((k <= 2) ? 1 : 4);
308              
309             /* Like powerful_count, we ignore 0. */
310 10 100         if (lo < 1) lo = 1;
311              
312 10 50         if (hi < lo) {
313 0           pn = 0;
314 0           npn = 0;
315 10 100         } else if (k <= 1) {
316 2           npn = hi-lo+1;
317 2 50         New(0, pn, npn, UV);
318 26 100         for (i = lo; i <= hi; i++)
319 24           pn[i-lo] = i;
320 8 50         } else if ((lo+single_thresh) > hi || lo > (UV_MAX-single_thresh)) {
    50          
321 0 0         New(0, pn, hi-lo+1, UV);
322 0 0         for (i = lo, npn = 0; i <= hi && i != 0; i++)
    0          
323 0 0         if (is_powerful(i,k))
324 0           pn[npn++] = i;
325             } else {
326 8 100         npn = powerful_count(hi,k) - ((lo <= 1) ? 0 : powerful_count(lo-1,k));
327 8 50         New(0, pn, npn, UV);
328 8           i = 0;
329 8           _pcg(lo, hi, k, 1, 2*k-1, pn, &i);
330 8 50         MPUassert(i == npn, "Number of powerful numbers generated != count");
331 8           sort_uv_array(pn, npn);
332             }
333 10           *npowerful = npn;
334 10           return pn;
335             }