Skip to content

Commit d999fed

Browse files
authored
Merge pull request #191 from czurnieden/bn_ilogb
New function: ilogb, integer logarithm to integer base
2 parents 96ece82 + 35311ae commit d999fed

File tree

12 files changed

+789
-66
lines changed

12 files changed

+789
-66
lines changed

bn_mp_ilogb.c

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
#include "tommath_private.h"
2+
#ifdef BN_MP_ILOGB_C
3+
/* LibTomMath, multiple-precision integer library -- Tom St Denis */
4+
/* SPDX-License-Identifier: Unlicense */
5+
6+
/* Compute log_{base}(a) */
7+
static mp_word s_pow(mp_word base, mp_word exponent)
8+
{
9+
mp_word result = 1uLL;
10+
while (exponent) {
11+
if ((exponent & 0x1) == 1) {
12+
result *= base;
13+
}
14+
exponent >>= 1;
15+
base *= base;
16+
}
17+
18+
return result;
19+
}
20+
21+
static mp_digit s_digit_ilogb(mp_digit base, mp_digit n)
22+
{
23+
mp_word bracket_low = 1uLL, bracket_mid, bracket_high, N;
24+
mp_digit ret, high = 1uL, low = 0uL, mid;
25+
26+
if (n < base) {
27+
return (mp_digit)0uL;
28+
}
29+
if (n == base) {
30+
return (mp_digit)1uL;
31+
}
32+
33+
bracket_high = (mp_word) base ;
34+
N = (mp_word) n;
35+
36+
while (bracket_high < N) {
37+
low = high;
38+
bracket_low = bracket_high;
39+
high <<= 1;
40+
bracket_high *= bracket_high;
41+
}
42+
43+
while (((mp_digit)(high - low)) > 1uL) {
44+
mid = (low + high) >> 1;
45+
bracket_mid = bracket_low * s_pow(base, mid - low) ;
46+
47+
if (N < bracket_mid) {
48+
high = mid ;
49+
bracket_high = bracket_mid ;
50+
}
51+
if (N > bracket_mid) {
52+
low = mid ;
53+
bracket_low = bracket_mid ;
54+
}
55+
if (N == bracket_mid) {
56+
return (mp_digit) mid;
57+
}
58+
}
59+
60+
if (bracket_high == N) {
61+
ret = high;
62+
} else {
63+
ret = low;
64+
}
65+
66+
return ret;
67+
}
68+
69+
/* TODO: output could be "int" because the output of mp_radix_size is int, too,
70+
as is the output of mp_bitcount.
71+
With the same problem: max size is INT_MAX * MP_DIGIT not INT_MAX only!
72+
*/
73+
int mp_ilogb(mp_int *a, mp_digit base, mp_int *c)
74+
{
75+
int err, cmp;
76+
unsigned int high, low, mid;
77+
mp_int bracket_low, bracket_high, bracket_mid, t, bi_base;
78+
mp_digit tmp;
79+
80+
err = MP_OKAY;
81+
if (a->sign == MP_NEG) {
82+
return MP_VAL;
83+
}
84+
if (IS_ZERO(a)) {
85+
return MP_VAL;
86+
}
87+
88+
if (base < 2) {
89+
return MP_VAL;
90+
} else if (base == 2) {
91+
cmp = mp_count_bits(a) - 1;
92+
mp_set_int(c, (unsigned long)cmp);
93+
return err;
94+
} else if (a->used == 1) {
95+
tmp = s_digit_ilogb(base, a->dp[0]);
96+
mp_set(c, tmp);
97+
return err;
98+
}
99+
100+
101+
cmp = mp_cmp_d(a, base);
102+
103+
if (cmp == MP_LT) {
104+
mp_zero(c);
105+
return err;
106+
} else if (cmp == MP_EQ) {
107+
mp_set(c, (mp_digit)1uL);
108+
return err;
109+
}
110+
111+
if ((err =
112+
mp_init_multi(&bracket_low, &bracket_high,
113+
&bracket_mid, &t, &bi_base, NULL)) != MP_OKAY) {
114+
return err;
115+
}
116+
117+
low = 0uL;
118+
mp_set(&bracket_low, 1uL);
119+
high = 1uL;
120+
121+
mp_set(&bracket_high, base);
122+
123+
/*
124+
A kind of Giant-step/baby-step algorithm.
125+
Idea shamelessly stolen from https://programmingpraxis.com/2010/05/07/integer-logarithms/2/
126+
The effect is asymptotic, hence needs benchmarks to test if the Giant-step should be skipped
127+
for small n.
128+
*/
129+
while (mp_cmp(&bracket_high, a) == MP_LT) {
130+
low = high;
131+
if ((err = mp_copy(&bracket_high, &bracket_low)) != MP_OKAY) {
132+
goto LBL_ERR;
133+
}
134+
high <<= 1;
135+
if ((err = mp_sqr(&bracket_high, &bracket_high)) != MP_OKAY) {
136+
goto LBL_ERR;
137+
}
138+
}
139+
mp_set(&bi_base, base);
140+
141+
while ((high - low) > 1) {
142+
mid = (high + low) >> 1;
143+
/* Difference can be larger then the type behind mp_digit can hold */
144+
if ((mid - low) > (unsigned int)(MP_MASK)) {
145+
err = MP_VAL;
146+
goto LBL_ERR;
147+
}
148+
if ((err = mp_expt_d(&bi_base, (mid - low), &t)) != MP_OKAY) {
149+
goto LBL_ERR;
150+
}
151+
if ((err = mp_mul(&bracket_low, &t, &bracket_mid)) != MP_OKAY) {
152+
goto LBL_ERR;
153+
}
154+
cmp = mp_cmp(a, &bracket_mid);
155+
if (cmp == MP_LT) {
156+
high = mid;
157+
mp_exch(&bracket_mid, &bracket_high);
158+
}
159+
if (cmp == MP_GT) {
160+
low = mid;
161+
mp_exch(&bracket_mid, &bracket_low);
162+
}
163+
if (cmp == MP_EQ) {
164+
mp_set_int(c, (unsigned long)mid);
165+
goto LBL_END;
166+
}
167+
}
168+
169+
if (mp_cmp(&bracket_high, a) == MP_EQ) {
170+
mp_set_int(c, (unsigned long)high);
171+
} else {
172+
mp_set_int(c, (unsigned long)low);
173+
}
174+
175+
LBL_END:
176+
LBL_ERR:
177+
mp_clear_multi(&bracket_low, &bracket_high, &bracket_mid,
178+
&t, &bi_base, NULL);
179+
return err;
180+
}
181+
182+
183+
#endif

0 commit comments

Comments
 (0)