javalogarithmnatural-logarithm

How can I get log value of a negative value?


I have a function of the following table.

input: e output: 1 << e
0 1
1 2
... ...
31 -2147483648
static int value(int exponent) {
    return 1 << exponent;
}

Now, how can I get the exponent from a value?

I tried the following code and it fails for the last entry of -2147483648.

int exponent(int value) {
    return (int) (Math.log(value) / Math.log(2)); // -> NaN / Math.log(2)
}

And I managed to fix it like this.

int exponent(int value) {
    if (value == Integer.MIN_VALUE) {
       return (int) (Math.log(value - 1) / Math.log(2)) + 1;
    }
    return (int) (Math.log(value) / Math.log(2));
}

Is there any better/proper way to do this?


Solution

  • You can use Integer.numberOfLeadingZeros for that. According to its JavaDoc:

    Note that this method is closely related to the logarithm base 2. For all positive int values x:

    floor(log2(x)) = 31 - numberOfLeadingZeros(x)
    ceil(log2(x)) = 32 - numberOfLeadingZeros(x - 1)
    

    To implement your exponent method, simply copy what the JavaDoc suggests:

    int exponent(int value) {
        return 31 - Integer.numberOfLeadingZeros(value);
    }
    

    Note that this also works for negative numbers in your case, even though the logarithm is not defined for non-positive numbers: For all negative numbers, the left-most bit will be 1 due to their representation in the two's complement. Therefore, for any negative value, Integer.numberOfLeadingZeros returns 0, and hence your exponent method calculates 31.

    Also note, that if value == 0, then exponent returns -1 which is a case you might want to take care of. For example, you could throw an IllegalArgumentException since the logarithm is undefined for 0.