java 如何获得负值的log值?

b5buobof  于 2023-06-28  发布在  Java
关注(0)|答案(2)|浏览(140)

我有一个下表的函数。
| 输入:e|输出:1 << e|
| - -----|- -----|
| 0| 1|
| 1| 2|
| ……|……|
| 31| -2147483648|

static int value(int exponent) {
    return 1 << exponent;
}

现在,如何从value中获取exponent
我尝试了下面的代码,它在-2147483648的最后一个条目失败。

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

我把它修好了。

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

有没有更好的/合适的方法来做这件事?

zdwk9cvp

zdwk9cvp1#

你可以使用Integer.numberOfLeadingZeros来实现。根据JavaDoc:
请注意,此方法与以2为底的对数密切相关。对于所有正整数值x:

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

要实现exponent方法,只需复制JavaDoc的建议:

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

请注意,在您的情况下,这也适用于负数,即使没有为非正数定义对数:对于所有负数,由于它们在二的补码中的表示,最左边的位将是1。因此,对于任何负值,Integer.numberOfLeadingZeros返回0,因此exponent方法计算31
另外请注意,如果value == 0,则exponent返回-1,这是您可能需要注意的情况。例如,您可以抛出IllegalArgumentException,因为0的对数未定义。

nzkunb0c

nzkunb0c2#

使用Integer.numberOfLeadingZeros()作为 * Alex R * 在他们的答案中建议的,对于正输入是完全可以的,但是对于任何负数都可以

31 - Integer.numberOfLeadingZeros(value)

将被评估为31,因为每个负数的第一位是1
这个结果(31的指数)对于-2147483648是有意义的,因为2^31 = 2147483648(正如 * Alex R * 在他们的回答中所说的那样),但对于-1-16-256等没有意义。
要获得负输入的正确结果,您需要使用给定输入的绝对值。
为了处理给定值为Integer.MIN_VALUE(在int类型中没有正等价值,因为Integer.MAX_VALUE小1)而不需要额外检查的情况,可以使用long
下面是使用按位逻辑实现它的方法之一:

public static int exponent(int value) {
    if (value == 0) throw new IllegalArgumentException();
    
    long mod = Math.abs((long) value);
    
    long mask = 1;
    int exp = 31;
    
    while ((mask << exp & mod) == 0) { // until left bit is not 1, decrement the exponent
        exp--;
    }
    
    return exp;
}

简单演示:

public static void main(String[] args) {
    System.out.println("value: 1" + "\texponent: " + exponent(1));
    System.out.println("value: 2" + "\texponent: " + exponent(2));
    System.out.println("value: 8" + "\texponent: " + exponent(8));
    System.out.println("value: 32" + "\texponent: " + exponent(32));
    System.out.println("value: 64" + "\texponent: " + exponent(64));
    System.out.println("value: 256" + "\texponent: " + exponent(256));
    System.out.println("value: " + Integer.MAX_VALUE + "\texponent: " + exponent(Integer.MAX_VALUE));
    
    System.out.println("value: -1" + "\texponent: " + exponent(-1));
    System.out.println("value: -2" + "\texponent: " + exponent(-2));
    System.out.println("value: -8" + "\texponent: " + exponent(-8));
    System.out.println("value: -32" + "\texponent: " + exponent(-32));
    System.out.println("value: -64" + "\texponent: " + exponent(-64));
    System.out.println("value: -256" + "\texponent: " + exponent(-256));
    System.out.println("value: " + Integer.MIN_VALUE + "\texponent: " + exponent(Integer.MIN_VALUE));
}

输出:

value: 1    exponent: 0
value: 2    exponent: 1
value: 8    exponent: 3
value: 32   exponent: 5
value: 64   exponent: 6
value: 256  exponent: 8
value: 2147483647   exponent: 30

value: -1   exponent: 0
value: -2   exponent: 1
value: -8   exponent: 3
value: -32  exponent: 5
value: -64  exponent: 6
value: -256 exponent: 8
value: -2147483648  exponent: 31

相关问题