Reputation: 35
I need to do a power of 2 with a floating exponent in Java Card. As you probably know, float
type is forbidden in the Java Card specification. I need to do an operation like this:
short n = 2 ^ (float) (31/4)
The expected n
is n = 215
.
Somebody knows how can I calculate this?
Upvotes: 0
Views: 356
Reputation: 28826
As Patricia said, it makes sense to calculate (2^a)^(1/b)
. From your comments I see that b
is always 4. Then it becomes a lot simpler.
Because you always have a power of 2, and always need the quad root, you can divide the number a up in portions of 4 (i.e. 2^4
) and a rest. There can only be 4 values for the rest, and for that, you can use a lookup table. I would code that as fixed point value, e.g. scaled by 2^16
.
So, in fact, if quotient = a // 4
and remainder = a % 4
you calculate: 2^(quotient) * (2^(remainder / 4) * 65536) // 65536
, where //
denotes integer division and /
denotes float division (I know this is not valid Java, but I use different operators to show the difference).
This should be much faster and easier than using Newton-Raphson to calculate a square root repeatedly.
I don't know Java very well, so please excuse if the syntax is not correct, but it should look more or less like this:
public class MyClass
{
public static int[] factors;
public static void initfactors()
{
factors = new int[4];
factors[0] = 65536; // 2^(0/4) * 65536
factors[1] = 77936; // 2^(1/4) * 65536
factors[2] = 92682; // 2^(2/4) * 65536
factors[3] = 110218; // 2^(3/4) * 65536
}
// Returns 2^(a/4) as integer
public static int calc(int a)
{
int quotient = a / 4;
int remainder = a % 4; // a == 4 * quotient + remainder
int factor = factors[remainder];
// calculate 2^(a/4) * (2^(remainder/4) * 65536) / 65536
return ((1 << quotient) * factor) >> 16;
}
The factors can be found like this: you simply use a calculator to calculate 2^0
, 2^0.25
, 2^0.5
, 2^0.75
and multiply the results by 65536
(2^16
), preferrably rounding up so the shift does not result in a number slightly below the value you want.
Usage example:
public static void main(String[] args)
{
initfactors();
int result = calc(31);
System.out.println(result);
}
quotient: 31 / 4 --> 7
remainder: 31 % 4 --> 3
factor: factors[3] --> 110218
result: ((1 << 7) * 110218) >> 16 --> 128 * 110218 / 65536 --> 215.
Upvotes: 4
Reputation: 26185
To expand on my comment, and give a partial answer, consider calculating 2^(a/b)
as (2^a)^(1/b)
.
Raising 2
to an integer power is easy: 1 << a
. Depending on the numbers involved, you may need some form of extended precision, such as manually using two int
variables.
That leaves computing the bth root of an integer. If b
is a power of two, it can be done by repeated square root operations, using e.g. Newton-Raphson for each square root. If b
can be any positive integer, you need more sophisticated methods.
One possible approach to the bth root part of the problem is a binary search. The root must be between 1 and 2^ceil(a/2)
.
Upvotes: 4