0

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?

Peter O.
  • 32,158
  • 14
  • 82
  • 96

2 Answers2

4

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).

Patricia Shanahan
  • 25,849
  • 4
  • 38
  • 75
  • 1
    Hey, an FP guru on Java Card topic, welcome :) As your answer may require integers (which are generally not present on Java Card) it is possible to use my [XMas Special answer: JCInteger](http://stackoverflow.com/a/14027143/589259) for the calculations. – Maarten Bodewes Jul 13 '14 at 11:16
  • My knowledge of Java Card is currently limited to having read one article about it. I do understand floating point, algorithms, and Java. Yes - I'm assuming use of an arithmetic type wide enough to contain the intermediate results. That seems so useful to me that I assumed if it were not built in someone would have written it. – Patricia Shanahan Jul 13 '14 at 13:58
  • Well, there is *optional* support for `int` and *optional* support for `javacardx.framework.math.BigNumber` (which is really limited). Neither of them are usually available. It is presumed in Java Card that cryptographic operations should be implemented by the OS (also due to side channel attacks etc) so there is not that much need for bigger numbers for those kind of solutions. Otherwise there is [BigNat](http://www.sos.cs.ru.nl/ovchip/api/ds/ov2/bignat/Bignat.html) but it seems to be a horrible library to me. So the choice is rather limited. – Maarten Bodewes Jul 13 '14 at 14:16
4

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. 
Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94