171 lines
5.2 KiB
C
171 lines
5.2 KiB
C
// Computes an integer power by modular exponentiation.
|
|
//
|
|
// From https://gist.github.com/orlp/3551590, in turn optimized from
|
|
// https://stackoverflow.com/a/101613.
|
|
//
|
|
// Adapted.
|
|
#ifndef ACED_CONTRIB_ORLP_IPOW_H_
|
|
#define ACED_CONTRIB_ORLP_IPOW_H_
|
|
|
|
#include <stdint.h>
|
|
|
|
int64_t ipow(int64_t base, uint8_t exp) {
|
|
static const uint8_t highest_bit_set[] = {
|
|
0, 1, 2, 2, 3, 3, 3, 3,
|
|
4, 4, 4, 4, 4, 4, 4, 4,
|
|
5, 5, 5, 5, 5, 5, 5, 5,
|
|
5, 5, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 255, // anything past 63 is a guaranteed overflow with base > 1
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
};
|
|
|
|
int64_t result = 1;
|
|
|
|
switch (highest_bit_set[exp]) {
|
|
case 255: // we use 255 as an overflow marker and return 0 on overflow/underflow
|
|
if (base == 1) {
|
|
return 1;
|
|
}
|
|
|
|
if (base == -1) {
|
|
return 1 - 2 * (exp & 1);
|
|
}
|
|
|
|
return 0;
|
|
case 6:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 5:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 4:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 3:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 2:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 1:
|
|
if (exp & 1) result *= base;
|
|
// fall through
|
|
default:
|
|
return result;
|
|
}
|
|
}
|
|
|
|
uint64_t upow(uint64_t base, uint8_t exp) {
|
|
static const uint8_t highest_bit_set[] = {
|
|
0, 1, 2, 2, 3, 3, 3, 3,
|
|
4, 4, 4, 4, 4, 4, 4, 4,
|
|
5, 5, 5, 5, 5, 5, 5, 5,
|
|
5, 5, 5, 5, 5, 5, 5, 5,
|
|
6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 6,
|
|
6, 6, 6, 6, 6, 6, 6, 255, // anything past 63 is a guaranteed overflow with base > 1
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
255, 255, 255, 255, 255, 255, 255, 255,
|
|
};
|
|
|
|
uint64_t result = 1;
|
|
|
|
switch (highest_bit_set[exp]) {
|
|
case 255: // we use 255 as an overflow marker and return 0 on overflow/underflow
|
|
if (base == 1) {
|
|
return 1;
|
|
}
|
|
return 0;
|
|
case 6:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 5:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 4:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 3:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 2:
|
|
if (exp & 1) result *= base;
|
|
exp >>= 1;
|
|
base *= base;
|
|
// fall through
|
|
case 1:
|
|
if (exp & 1) result *= base;
|
|
// fall through
|
|
default:
|
|
return result;
|
|
}
|
|
}
|
|
|
|
#endif |