views:

67

answers:

4

I have a scenario where I'm working with large integers (e.g. 160 bit), and am trying to create the biggest possible unsigned integer that can be represented with an n bit number at run time. The exact value of n isn't known until the program has begun executing and read the value from a configuration file. So for example, n might be 160, or 128, or 192, etcetera...

Initially what I was thinking was something like:

BigInteger.valueOf((long)Math.pow(2, n));

but then I realized, the conversion to long that takes place sort of defeats the purpose, given that long is not comprised of enough bits in the first place to store the result. Any suggestions?

+2  A: 

I think there is pow method directly in BigInteger. You can use it for your purpose

Ankit
Can't believe I overlooked the pow method. So for reference I'm now using BigInteger.valueOf(2L).pow(n).subtract(BigInteger.ONE), which is effectively 2^n - 1, which as pointed out by Dean is the largest number that can be represented with n bits.
Bryce Thomas
Good to hear that it works... :). I never tried it by myself.
Ankit
A: 

The quickest way I can think of doing this is by using the constructor for BigInteger that takes a byte[].

BigInteger(byte[] val) constructs the BigInteger Object from an array of bytes. You are, however, dealing with bits, and so creating a byte[] that might consist of {127, 255, 255, 255, 255} for a 39 bit integer representing 2^40 - 1 might be a little tedious.

You could also use the constructor BigInteger(String val, int radix) - which might be readily more apparently what's going on in your code if you don't mind a performance hit for parsing a String. Then you could generate a string like val = "111111111111111111111111111111111111111" and then call BigInteger myInt = new BigInteger(val, 2); - resulting in the same 39 bit integer.

The first option will require some thinking about how to represent your number. That particular constructor expects a two's-compliment, big-endian representation of the number. The second will likely be marginally slower, but much clearer.

EDIT: Corrected numbers. I thought you meant represent 2^n, and didn't correctly read the largest value n bits could store.

JBirch
+3  A: 

Just to clarify you want the largest n bit number (ie, the one will all n-bits set). If so, the following will do that for you:

BigInteger largestNBitInteger = BigInteger.ZERO.setBit(n).subtract(BigInteger.ONE);

Which is mathematically equivalent to 2^n - 1. Your question has how you do 2^n which is actually the smallest n+1 bit number. You can of course do that with:

BigInteger smallestNPlusOneBitInteger = BigInteger.ZERO.setBit(n);
Dean Povey
Wouldn't using setBit(n) on BigInteger.ZERO only set one (the high order or low order I'm not sure) bit out of n bits? e.g. for a 160 bit number you'd have one bit set to 1 and 159 bits still set to 0, resulting in a number much smaller than the largest n bit number? Or is my interpretation of how setBit works wrong?
Bryce Thomas
@Bryce - that's why he subtracted one ...
Stephen C
@Stephen - does setBit set the high or low order bit? If it's low order bit, subtracting one would give you the integer 0 wouldn't it (bits 00000...0)? And if it was high order bit, subtracting one would take you from a number like 10000...0 to 01111...1, which is still only approximately half the largest number 11111....1?
Bryce Thomas
@Bryce - you can read the javadoc for yourself here - http://download.oracle.com/javase/6/docs/api/java/math/BigInteger.html#setBit(int)
Stephen C
Right I think I understand it now. When I read the javadoc initially I was ignoring the shift and logical OR operator description, which turns out to be more useful than the sentence description.
Bryce Thomas
+4  A: 

On the largest n-bit unsigned number

Let's first take a look at what this number is, mathematically.

In an unsigned binary representation, the largest n-bit number would have all bits set to 1. Let's take a look at some examples:

1(2)= 1 =21 - 1
11(2)= 3 =22 - 1
111(2)= 7 =23 - 1
:
1………1(2)=2n -1
   n

Note that this is analogous in decimal too. The largest 3 digit number is:

103- 1 = 1000 - 1 = 999

Thus, a subproblem of finding the largest n-bit unsigned number is computing 2n.


On computing powers of 2

Modern digital computers can compute powers of two efficiently, due to the following pattern:

20= 1(2)
21= 10(2)
22= 100(2)
23= 1000(2)
:
2n= 10………0(2)
       n

That is, 2n is simply a number having its bit n set to 1, and everything else set to 0 (remember that bits are numbered with zero-based indexing).


Solution

Putting the above together, we get this simple solution using BigInteger for our problem:

final int N = 5;
BigInteger twoToN   = BigInteger.ZERO.setBit(N);
BigInteger maxNbits = twoToN.subtract(BigInteger.ONE);

System.out.println(maxNbits); // 31

If we were using long instead, then we can write something like this:

// for 64-bit signed long version, N < 64
System.out.println(
    (1L << N) - 1
); // 31

There is no "set bit n" operation defined for long, so traditionally bit shifting is used instead. In fact, a BigInteger analog of this shifting technique is also possible:

System.out.println(
    BigInteger.ONE.shiftLeft(N).subtract(BigInteger.ONE)
); // 31

See also


Additional BigInteger tips

BigInteger does have a pow method to compute non-negative power of any arbitrary number. If you're working in a modular ring, there are also modPow and modInverse.

You can individually setBit, flipBit or just testBit. You can get the overall bitCount, perform bitwise and with another BigInteger, and shiftLeft/shiftRight, etc.

As bonus, you can also compute the gcd or check if the number isProbablePrime.

ALWAYS remember that BigInteger, like String, is immutable. You can't invoke a method on an instance, and expect that instance to be modified. Instead, always assign the result returned by the method to your variables.

polygenelubricants
Great answer. The part about using setBit to set the bit at position n where everything has a ZERO based index clarified this for me. I'd been thinking about setBit as setting the nth bit, where as with the zero based indexing, it's really the n+1th bit (at index n) in a line of bits getting set.
Bryce Thomas