|
6 | 6 | /* find the n'th root of an integer |
7 | 7 | * |
8 | 8 | * Result found such that (c)**b <= a and (c+1)**b > a |
9 | | - * |
10 | | - * This algorithm uses Newton's approximation |
11 | | - * x[i+1] = x[i] - f(x[i])/f'(x[i]) |
12 | | - * which will find the root in log(N) time where |
13 | | - * each step involves a fair bit. |
14 | 9 | */ |
| 10 | + |
15 | 11 | mp_err mp_root_n(const mp_int *a, int b, mp_int *c) |
16 | 12 | { |
17 | | - mp_int t1, t2, t3, a_; |
18 | | - int ilog2; |
19 | | - mp_err err; |
20 | | - |
21 | | - if (b < 0 || (unsigned)b > (unsigned)MP_DIGIT_MAX) { |
22 | | - return MP_VAL; |
23 | | - } |
24 | | - |
25 | | - /* input must be positive if b is even */ |
26 | | - if (((b & 1) == 0) && mp_isneg(a)) { |
27 | | - return MP_VAL; |
28 | | - } |
29 | | - |
30 | | - if ((err = mp_init_multi(&t1, &t2, &t3, NULL)) != MP_OKAY) { |
31 | | - return err; |
32 | | - } |
33 | | - |
34 | | - /* if a is negative fudge the sign but keep track */ |
35 | | - a_ = *a; |
36 | | - a_.sign = MP_ZPOS; |
37 | | - |
38 | | - /* Compute seed: 2^(log_2(n)/b + 2)*/ |
39 | | - ilog2 = mp_count_bits(a); |
40 | | - |
41 | | - /* |
42 | | - If "b" is larger than INT_MAX it is also larger than |
43 | | - log_2(n) because the bit-length of the "n" is measured |
44 | | - with an int and hence the root is always < 2 (two). |
45 | | - */ |
46 | | - if (b > INT_MAX/2) { |
47 | | - mp_set(c, 1uL); |
48 | | - c->sign = a->sign; |
49 | | - err = MP_OKAY; |
50 | | - goto LBL_ERR; |
51 | | - } |
52 | | - |
53 | | - /* "b" is smaller than INT_MAX, we can cast safely */ |
54 | | - if (ilog2 < b) { |
55 | | - mp_set(c, 1uL); |
56 | | - c->sign = a->sign; |
57 | | - err = MP_OKAY; |
58 | | - goto LBL_ERR; |
59 | | - } |
60 | | - ilog2 = ilog2 / b; |
61 | | - if (ilog2 == 0) { |
62 | | - mp_set(c, 1uL); |
63 | | - c->sign = a->sign; |
64 | | - err = MP_OKAY; |
65 | | - goto LBL_ERR; |
66 | | - } |
67 | | - /* Start value must be larger than root */ |
68 | | - ilog2 += 2; |
69 | | - if ((err = mp_2expt(&t2,ilog2)) != MP_OKAY) goto LBL_ERR; |
70 | | - do { |
71 | | - /* t1 = t2 */ |
72 | | - if ((err = mp_copy(&t2, &t1)) != MP_OKAY) goto LBL_ERR; |
73 | | - |
74 | | - /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */ |
75 | | - |
76 | | - /* t3 = t1**(b-1) */ |
77 | | - if ((err = mp_expt_n(&t1, b - 1, &t3)) != MP_OKAY) goto LBL_ERR; |
78 | | - |
79 | | - /* numerator */ |
80 | | - /* t2 = t1**b */ |
81 | | - if ((err = mp_mul(&t3, &t1, &t2)) != MP_OKAY) goto LBL_ERR; |
82 | | - |
83 | | - /* t2 = t1**b - a */ |
84 | | - if ((err = mp_sub(&t2, &a_, &t2)) != MP_OKAY) goto LBL_ERR; |
85 | | - |
86 | | - /* denominator */ |
87 | | - /* t3 = t1**(b-1) * b */ |
88 | | - if ((err = mp_mul_d(&t3, (mp_digit)b, &t3)) != MP_OKAY) goto LBL_ERR; |
89 | | - |
90 | | - /* t3 = (t1**b - a)/(b * t1**(b-1)) */ |
91 | | - if ((err = mp_div(&t2, &t3, &t3, NULL)) != MP_OKAY) goto LBL_ERR; |
92 | | - |
93 | | - if ((err = mp_sub(&t1, &t3, &t2)) != MP_OKAY) goto LBL_ERR; |
94 | | - |
95 | | - /* |
96 | | - Number of rounds is at most log_2(root). If it is more it |
97 | | - got stuck, so break out of the loop and do the rest manually. |
98 | | - */ |
99 | | - if (ilog2-- == 0) { |
100 | | - break; |
101 | | - } |
102 | | - } while (mp_cmp(&t1, &t2) != MP_EQ); |
103 | | - |
104 | | - /* result can be off by a few so check */ |
105 | | - /* Loop beneath can overshoot by one if found root is smaller than actual root */ |
106 | | - for (;;) { |
107 | | - mp_ord cmp; |
108 | | - if ((err = mp_expt_n(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR; |
109 | | - cmp = mp_cmp(&t2, &a_); |
110 | | - if (cmp == MP_EQ) { |
111 | | - err = MP_OKAY; |
112 | | - goto LBL_ERR; |
113 | | - } |
114 | | - if (cmp == MP_LT) { |
115 | | - if ((err = mp_add_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR; |
116 | | - } else { |
117 | | - break; |
118 | | - } |
119 | | - } |
120 | | - /* correct overshoot from above or from recurrence */ |
121 | | - for (;;) { |
122 | | - if ((err = mp_expt_n(&t1, b, &t2)) != MP_OKAY) goto LBL_ERR; |
123 | | - if (mp_cmp(&t2, &a_) == MP_GT) { |
124 | | - if ((err = mp_sub_d(&t1, 1uL, &t1)) != MP_OKAY) goto LBL_ERR; |
125 | | - } else { |
126 | | - break; |
127 | | - } |
128 | | - } |
129 | | - |
130 | | - /* set the result */ |
131 | | - mp_exch(&t1, c); |
132 | | - |
133 | | - /* set the sign of the result */ |
134 | | - c->sign = a->sign; |
135 | | - |
136 | | -LBL_ERR: |
137 | | - mp_clear_multi(&t1, &t2, &t3, NULL); |
138 | | - return err; |
| 13 | + return s_mp_root_n(a, b, c, NULL); |
139 | 14 | } |
140 | 15 |
|
141 | 16 | #endif |
0 commit comments