File Coverage

perfect_powers.c
Criterion Covered Total %
statement 91 96 94.7
branch 83 104 79.8
condition n/a
subroutine n/a
pod n/a
total 174 200 87.0


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 "perfect_powers.h"
8             #define FUNC_log2floor 1
9             #define FUNC_ipow 1
10             #include "util.h"
11             #include "inverse_interpolate.h"
12              
13             /******************************************************************************/
14             /* PERFECT POWERS */
15             /******************************************************************************/
16              
17 113           bool is_perfect_power(UV n) {
18 113 100         return (n <= 1 || powerof(n) > 1);
    100          
19             }
20 100           bool is_perfect_power_neg(UV n) {
21 100           uint32_t k = powerof(n);
22             /* An exponent other than 0,1,2,4,8,16,... is ok */
23 100 100         return (n <= 1 || (k > 2 && (k & (k-1)) != 0));
    100          
    100          
24             }
25 0           bool is_perfect_power_iv(IV n) {
26 0 0         if (n < -1) {
27 0           uint32_t k = powerof(-n);
28 0 0         return (k > 2 && (k & (k-1)) != 0);
    0          
29             }
30 0 0         return (n <= 1 || powerof(n) > 1);
    0          
31             }
32              
33 106           static UV _next_perfect_power(UV n, bool only_oddpowers) {
34             uint32_t k, kinit, kinc, log2n;
35             UV best;
36              
37 106 100         if (n == 0) return 1;
38 103 100         if (n == 1) return only_oddpowers ? 8 : 4;
    100          
39 98 100         if (n >= MPU_MAX_PERFECT_POW) return 0; /* Overflow */
40             /* Should check for n >= max odd-power perfect power */
41              
42 97 50         log2n = log2floor(n);
43 97 100         kinit = only_oddpowers ? 3 : 2;
44 97 100         kinc = only_oddpowers ? 2 : 1;
45              
46 97           best = ipow( rootint(n,kinit)+1, kinit);
47 680 100         for (k = kinit+kinc; k <= 1+log2n; k += kinc) {
48 583           UV c = ipow( rootint(n,k)+1, k);
49 583 100         if (c < best && c > n) best = c;
    100          
50             }
51 97           return best;
52             }
53 114           static UV _prev_perfect_power(UV n, bool only_oddpowers) {
54             uint32_t k, kinit, kinc, log2n;
55             UV best;
56              
57 114 100         if (n <= 4) return (n > 1) - (n == 0); /* note possible -1 return */
58 99 100         if (n <= 8) return only_oddpowers ? 1 : 4;
    100          
59              
60 84 50         log2n = log2floor(n);
61 84 100         kinit = only_oddpowers ? 3 : 2;
62 84 100         kinc = only_oddpowers ? 2 : 1;
63              
64 84           best = 8;
65 1371 100         for (k = kinit; k <= log2n; k += kinc) {
66 1287           UV r = rootint(n,k);
67 1287           UV c = ipow(r,k);
68 1287 100         if (c >= n) c = ipow(r-1,k);
69 1287 100         if (c > best && c < n) best = c;
    50          
70             }
71 84           return best;
72             }
73              
74 89           UV next_perfect_power(UV n)
75             {
76 89           return _next_perfect_power(n, 0);
77             }
78 17           UV next_perfect_power_neg(UV n)
79             {
80 17           return _prev_perfect_power(n, 1);
81             }
82              
83 97           UV prev_perfect_power(UV n)
84             {
85 97           return _prev_perfect_power(n, 0);
86             }
87 17           UV prev_perfect_power_neg(UV n)
88             {
89 17           return _next_perfect_power(n, 1);
90             }
91              
92             /* Should we have a generator / sieve? This is a common exercise using PQs. */
93              
94 59           UV perfect_power_count_range(UV lo, UV hi) {
95 59 100         if (hi < 1 || hi < lo) return 0;
    50          
96 58 100         return perfect_power_count(hi) - ((lo <= 1) ? 0 : perfect_power_count(lo-1));
97             }
98              
99             static const signed char _moebius[65] = {0,1,-1,-1,0,-1,1,-1,0,0,1,-1,0,-1,1,1,0,-1,0,-1,0,1,1,-1,0,0,1,0,0,-1,-1,-1,0,1,1,1,0,-1,1,1,0,-1,-1,-1,0,0,1,-1,0,0,0,1,0,-1,0,1,0,1,1,-1,0,-1,1,0,0};
100              
101             /* n A069623; 10^n A070428 */
102 240           UV perfect_power_count(UV n) {
103             uint32_t k, log2n;
104             UV sum;
105              
106 240 100         if (n < 8) return 0+(n>=1)+(n>=4);
107              
108 225 50         log2n = log2floor(n);
109 2215 100         for (sum = 1, k = 2; k <= log2n; k++)
110 1990 100         if (_moebius[k])
111 1346           sum -= _moebius[k] * (rootint(n, k) - 1);
112 225           return sum;
113             }
114              
115             /* About 50 ns per call for exact, so not really worth truncation. */
116              
117 57           UV perfect_power_count_lower(UV n) { return perfect_power_count(n); }
118              
119 57           UV perfect_power_count_upper(UV n) { return perfect_power_count(n); }
120              
121 3           UV perfect_power_count_approx(UV n) { return perfect_power_count(n); }
122              
123              
124 57           UV nth_perfect_power_lower(UV n) {
125             double pp;
126 57 100         if (n <= 1) return n;
127 56 50         if (n >= MPU_MAX_PERFECT_POW_IDX) return MPU_MAX_PERFECT_POW;
128              
129 56           pp = pow(n,2.) + (13./3.)*pow(n,4./3.) + (32./15.)*pow(n,16./15.);
130 56           pp += -2*pow(n, 5./ 3.) - 2*pow(n, 7./ 5.) - 2*pow(n, 9./ 7.) + 2*pow(n,12./10.);
131 56           pp += -2*pow(n,13./11.) - 2*pow(n,15./13.);
132 56           pp += 5.5;
133 56 50         if (pp >= UV_MAX) return UV_MAX;
134 56           return (UV)pp;
135             }
136 57           UV nth_perfect_power_upper(UV n) {
137             double pp;
138 57 100         if (n <= 1) return n;
139 56 50         if (n >= MPU_MAX_PERFECT_POW_IDX) return MPU_MAX_PERFECT_POW;
140              
141 56           pp = pow(n,2.) + (13./3.)*pow(n,4./3.) + (32./15.)*pow(n,16./15.);
142 56           pp += -2*pow(n, 5./ 3.) - 2*pow(n, 7./ 5.) - 2*pow(n, 9./ 7.) + 2*pow(n,12./10.);
143 56           pp += /* skip 11 and 13 */ 2*pow(n,16./14.);
144 56           pp -= 3.5;
145 56 50         if (pp >= UV_MAX) return UV_MAX;
146 56           return (UV)pp;
147             }
148 64           UV nth_perfect_power_approx(UV n) {
149             double pp;
150 64 50         if (n <= 1) return n;
151 64 50         if (n >= MPU_MAX_PERFECT_POW_IDX) return MPU_MAX_PERFECT_POW;
152              
153 64           pp = pow(n,2.) + (13./3.)*pow(n,4./3.) + (32./15.)*pow(n,16./15.);
154              
155             #if 0
156             uint32_t q;
157             for (q = 3; q <= 26; q++) {
158             int m = moebius(q);
159             if (m == 0 || q == 2 || q == 6 || q == 30) continue;
160             pp += m * 2.0 * pow(n, (double)(q+2)/(double)q);
161             }
162             #endif
163              
164 64           pp += -2*pow(n, 5./ 3.) - 2*pow(n, 7./ 5.) - 2*pow(n, 9./ 7.) + 2*pow(n,12./10.);
165 64           pp += -2*pow(n,13./11.) - 2*pow(n,15./13.) + 2*pow(n,16./14.) + 2*pow(n,17./15.);
166 64           pp -= 0.48 * pow(n,19.0/17.0);
167 64           pp -= 1.5;
168 64 100         if (pp >= UV_MAX) return UV_MAX;
169 62           return (UV)pp;
170             }
171              
172 63           UV nth_perfect_power(UV n) {
173             UV g, count;
174              
175 63 100         if (n <= 1) return n; /* 1,4,8,9,16,25,... */
176 62 100         if (n >= MPU_MAX_PERFECT_POW_IDX) return MPU_MAX_PERFECT_POW;
177              
178 61           g = interpolate_with_approx(n, &count, 1000,
179             &nth_perfect_power_approx, &perfect_power_count,
180             0);
181 61 100         if (g > MPU_MAX_PERFECT_POW)
182 2           g = MPU_MAX_PERFECT_POW;
183              
184 61 100         if (count >= n) {
185 52 100         for (g = prev_perfect_power(g+1); count > n; count--)
186 18           g = prev_perfect_power(g);
187             } else {
188 67 100         for (; count < n; count++)
189 40           g = next_perfect_power(g);
190             }
191 61           return g;
192             }