Hektor
Hektor

Reputation: 35

How can I do in javacard a power of 2 with a floating exponent?

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

Answers (2)

Rudy Velthuis
Rudy Velthuis

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);
  } 

Your example:

quotient: 31 / 4 --> 7
remainder: 31 % 4 --> 3
factor: factors[3] --> 110218
result: ((1 << 7) * 110218) >> 16 --> 128 * 110218 / 65536 --> 215. 

Upvotes: 4

Patricia Shanahan
Patricia Shanahan

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

Related Questions