File Coverage

prime_powers.c
Criterion Covered Total %
statement 133 133 100.0
branch 154 180 85.5
condition n/a
subroutine n/a
pod n/a
total 287 313 91.6


line stmt bran cond sub pod time code
1             #include
2             #include
3             #include
4              
5             #include "ptypes.h"
6             #include "constants.h"
7             #include "prime_powers.h"
8             #define FUNC_ctz 1
9             #define FUNC_log2floor 1
10             #define FUNC_ipow 1
11             #include "util.h"
12             #include "sort.h"
13             #include "cache.h"
14             #include "sieve.h"
15             #include "primality.h"
16             #include "prime_counts.h"
17             #include "inverse_interpolate.h"
18              
19             /******************************************************************************/
20             /* PRIME POWERS */
21             /******************************************************************************/
22              
23 23257           int prime_power(UV n, UV* prime)
24             {
25 23257           int power = 0;
26             uint32_t root;
27              
28 23257 100         if (n < 2) return 0;
29             /* Check for small divisors */
30 23250 100         if (!(n&1)) {
31 6326 100         if (n & (n-1)) return 0;
32 20 100         if (prime) *prime = 2;
33 20 50         return ctz(n);
34             }
35 16924 100         if ((n%3) == 0) {
36             /* if (UVCONST(12157665459056928801) % n) return 0; */
37 3354 100         do { n /= 3; power++; } while (n > 1 && (n%3) == 0);
    100          
38 2137 100         if (n != 1) return 0;
39 30 100         if (prime) *prime = 3;
40 30           return power;
41             }
42 14787 100         if ((n%5) == 0) {
43 3640 100         do { n /= 5; power++; } while (n > 1 && (n%5) == 0);
    100          
44 2859 100         if (n != 1) return 0;
45 22 100         if (prime) *prime = 5;
46 22           return power;
47             }
48 11928 100         if ((n%7) == 0) {
49 1975 100         do { n /= 7; power++; } while (n > 1 && (n%7) == 0);
    100          
50 1638 100         if (n != 1) return 0;
51 18 100         if (prime) *prime = 7;
52 18           return power;
53             }
54 10290 100         if (is_prob_prime(n))
55 3683 100         { if (prime) *prime = n; return 1; }
56             /* Composite. Test for perfect power with prime root. */
57 6607           power = powerof_ret(n, &root);
58 6607 100         if (power) {
59 132 100         if (is_prob_prime(root))
60 114 100         { if (prime) *prime = root; }
61             else
62 18           power = 0;
63             }
64 6607           return power;
65             }
66              
67              
68 54           UV next_prime_power(UV n)
69             {
70             UV i, bit;
71              
72 54 100         if (n < 2) return 2;
73 51 50         if (n >= MPU_MAX_PRIME) return 0; /* Overflow (max power = max prime) */
74              
75             #if 0
76             /* Straightforward loop */
77             for (i = n+1; !is_prime_power(i); i++)
78             ;
79             return i;
80             #else
81             /* Skip evens */
82 51 50         bit = UVCONST(1) << log2floor(n);
83 59 100         for (i = n+1+(n&1); i & bit; i += 2)
84 46 100         if (is_prime_power(i))
85 38           return i;
86 13           return i-1; /* We went past a power of two */
87             #endif
88             }
89              
90 56           UV prev_prime_power(UV n)
91             {
92             UV i, bit;
93 56 100         if (n <= 2) return 0;
94              
95             #if 0
96             for (i = n-1; !is_prime_power(i); i--)
97             ;
98             return i;
99             #else
100 52           n--;
101 52 50         bit = UVCONST(1) << log2floor(n);
102 57 100         for (i = n-!(n&1); i & bit; i -= 2)
103 42 100         if (is_prime_power(i))
104 37           return i;
105 15           return i+1; /* We went past a power of two */
106             #endif
107             }
108              
109             /* The prime powers without the primes */
110 47           UV prime_power_sieve2(UV** list, UV lo, UV hi) {
111 47           UV k, log2n, *powers, np = 0, npmax = 0;
112              
113 47 50         if (hi < 2 || lo > hi) { *list = 0; return 0; }
    50          
114              
115             /* Bound on how many powers we'll have */
116 47 50         log2n = log2floor(hi);
117 220 100         for (k = 2; k <= log2n; k++) {
118 173           npmax += prime_count_upper(rootint(hi,k));
119 173 100         if (lo > 2) npmax -= prime_count_lower(rootint(lo-1,k));
120             }
121              
122 47 50         New(0, powers, npmax, UV);
123              
124             /* Find all powers and add to list */
125 220 100         for (k = 2; k <= log2n; k++) {
126 715 50         START_DO_FOR_EACH_PRIME(2, rootint(hi,k)) {
    50          
    100          
    100          
    100          
    100          
    100          
    50          
    100          
    50          
    100          
127 542           UV pk = ipow(p,k);
128 542 100         if (pk >= lo) powers[np++] = pk;
129             } END_DO_FOR_EACH_PRIME
130             }
131              
132             /* Sort them and return */
133 47           sort_uv_array(powers, np);
134 47           *list = powers;
135 47           return np;
136             }
137              
138             /* The prime powers with the primes */
139 47           UV prime_power_sieve(UV** list, UV lo, UV hi) {
140             UV npower, nprime, ipower, iprime, ntotal, i, *powers, *primes, *tot;
141              
142 47 50         if (hi < 2 || lo > hi) { *list = 0; return 0; }
    50          
143              
144             /* For better performance / memory:
145             * 1) realloc primes, use reverse merge to add powers in with one pass
146             * 2) sieve the primes here and merge the powers in.
147             */
148              
149 47           npower = prime_power_sieve2(&powers, lo, hi);
150 47           nprime = range_prime_sieve(&primes, lo, hi);
151              
152             /* The powers get sparse, so this isn't impossible. */
153 47 100         if (npower == 0) { Safefree(powers); *list = primes; return nprime; }
154              
155 46           ipower = 0;
156 46           iprime = 0;
157 46           ntotal = nprime + npower;
158 46 50         New(0, tot, ntotal, UV);
159 825 100         for (i = 0; i < ntotal; i++) {
160 779 100         if (ipower == npower) tot[i] = primes[iprime++];
161 709 100         else if (iprime == nprime) tot[i] = powers[ipower++];
162 689 100         else tot[i] = (primes[iprime] < powers[ipower]) ? primes[iprime++] : powers[ipower++];
163             }
164 46           Safefree(powers);
165 46           Safefree(primes);
166 46           *list = tot;
167 46           return ntotal;
168             }
169              
170              
171 206           UV prime_power_count_range(UV lo, UV hi) {
172 206 100         if (hi < 2 || hi < lo) return 0;
    50          
173 198 100         return prime_power_count(hi) - ((lo <= 2) ? 0 : prime_power_count(lo-1));
174             }
175              
176             /* n A025528; 10^n A267712 */
177 485           UV prime_power_count(UV n) {
178             uint32_t k, log2n;
179             UV sum;
180              
181 485 100         if (n <= 5) return (n==0) ? 0 : n-1;
    50          
182              
183 435           sum = prime_count(n);
184 435 50         log2n = log2floor(n);
185 2405 100         for (k = 2; k <= log2n; k++)
186 1970           sum += prime_count(rootint(n,k));
187 435           return sum;
188             }
189              
190 326           UV prime_power_count_lower(UV n) {
191             uint32_t k, log2n;
192             UV sum;
193              
194 326 100         if (n <= 5) return (n==0) ? 0 : n-1;
    100          
195              
196 320           sum = prime_count_lower(n);
197 320 50         log2n = log2floor(n);
198 4650 100         for (k = 2; k <= log2n; k++)
199 4330           sum += prime_count_lower(rootint(n,k));
200 320           return sum;
201             }
202 333           UV prime_power_count_upper(UV n) {
203             uint32_t k, log2n;
204             UV sum;
205              
206 333 100         if (n <= 5) return (n==0) ? 0 : n-1;
    100          
207              
208 327           sum = prime_count_upper(n);
209 327 50         log2n = log2floor(n);
210 4831 100         for (k = 2; k <= log2n; k++)
211 4504           sum += prime_count_upper(rootint(n,k));
212 327           return sum;
213             }
214 792           UV prime_power_count_approx(UV n) {
215             uint32_t k, log2n;
216             UV sum;
217              
218 792 100         if (n <= 5) return (n==0) ? 0 : n-1;
    100          
219              
220 786           sum = prime_count_approx(n);
221 786 50         log2n = log2floor(n);
222 9538 100         for (k = 2; k <= log2n; k++)
223 8752           sum += prime_count_approx(rootint(n,k));
224 786           return sum;
225             }
226              
227 167           static UV _simple_nth_prime_power_lower(UV n) {
228 167 100         if (n <= 100) return n+1;
229 74           return (0.98 * nth_prime_lower(n)) - 400;
230             }
231 167           static UV _simple_nth_prime_power_upper(UV n) {
232 167           return nth_prime_upper(n);
233             }
234              
235 40           UV nth_prime_power_lower(UV n) {
236             UV lo, hi;
237 40 100         if (n <= 7) return (n==0) ? 0 : n+1+(n/5);
    50          
238 35           lo = _simple_nth_prime_power_lower(n);
239 35           hi = _simple_nth_prime_power_upper(n);
240 35           return inverse_interpolate(lo, hi, n, &prime_power_count_upper, 0);
241             }
242 40           UV nth_prime_power_upper(UV n) {
243             UV lo, hi;
244 40 100         if (n <= 7) return (n==0) ? 0 : n+1+(n/5);
    50          
245 35           lo = _simple_nth_prime_power_lower(n);
246 35           hi = _simple_nth_prime_power_upper(n);
247 35           return inverse_interpolate(lo, hi, n, &prime_power_count_lower, 0);
248             }
249 102           UV nth_prime_power_approx(UV n) {
250             UV lo, hi;
251 102 100         if (n <= 7) return (n==0) ? 0 : n+1+(n/5);
    50          
252 97           lo = _simple_nth_prime_power_lower(n);
253 97           hi = _simple_nth_prime_power_upper(n);
254 97           return inverse_interpolate(lo, hi, n, &prime_power_count_approx, 0);
255             }
256 69           UV nth_prime_power(UV n) {
257 69 100         if (n <= 7) return (n==0) ? 0 : n+1+(n/5);
    50          
258 62 50         if (n >= MPU_MAX_PRIME_IDX) return MPU_MAX_PRIME;
259              
260             #if 0 /* Bilinear interpolation. Not bad, but not great. */
261             UV lo, hi, pp;
262             if (n <= 7) return (n==0) ? 0 : n+1+(n/5);
263              
264             lo = nth_prime_power_lower(n);
265             hi = nth_prime_power_upper(n);
266             pp = inverse_interpolate(lo, hi, n, &prime_power_count, 10000);
267             return prev_prime_power(pp+1);
268             #endif
269              
270             #if 0 /* Approximating interpolation. Very good, but prefer simpler. */
271             UV g, count;
272             g = interpolate_with_approx(n, &count, 500,
273             &nth_prime_power_approx, &prime_power_count,
274             0);
275             if (g > MPU_MAX_PRIME)
276             g = MPU_MAX_PRIME;
277              
278             if (count >= n) {
279             for (g = prev_prime_power(g+1); count > n; count--)
280             g = prev_prime_power(g);
281             } else {
282             for (; count < n; count++)
283             g = next_prime_power(g);
284             }
285             return g;
286             #endif
287              
288             /* Interpolation using functions for approximate nth and exact count.
289             * This works quite well, and uses the is_prime_power() function to get
290             * the exact result. Our next/prev functions save negligible time. */
291 62           return interpolate_with_approx(n, 0, 800,
292             &nth_prime_power_approx, &prime_power_count,
293             &is_prime_power);
294             }