Java 中 int 或 long 的 Math.signum(double) 的等效函数

Equivalent function for Math.signum(double) for int or long in Java

在Java 用于其他原始数字,如 intlong。我不想写像

这样的代码
  int sign = (int) Math.signum((double) intValue);

当有更好的选择时。

你可以这样使用它:

Integer.signum(int i) and Long.signum(long l)

Link 到 javadoc:https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#signum-int-

只是一些实现细节的补充:

public static int signum(int i) {
    // HD, Section 2-7
    return (i >> 31) | (-i >>> 31);
}

Integer::signum 说:如果数字是负数,我会给你 -1,如果数字是零,我会给你 0,如果数字是正数,我会给你 1。例如,通过一些嵌套 if/else,这是相当微不足道的。

相反,JDK 使用了一种更奇特的解决方案。 (x >> 31) | (-x >>> 31)。看起来很容易吧?第一部分:x >> 31 有符号右移 ;它被称为 signed 是因为它在轮班后保留了符号。

假设我们生活在一个只存在 4 位数字的世界中(为简单起见)。

我们有 0100 (+4),单班 0100 >> 1 将使其成为 0010 (+2)。现在,如果我们的数字是 1100(-4;第一位是符号),向右移动 signed1100 >> 11110 (-2)。做除法,但保留标志。

因此,如果我们移位 31 次,我们将丢弃数字的最后 31 位,将符号位移动到最低有效位置并保留原始符号。或者简单地说,取 31 位,将其置于 0 位置并丢弃其他所有内容。

 0 00000 ..... 11111
 x --------------->0 // x is kept
        ignore

第二部分 -x >>> 31unsigned 移位,这意味着我们移位时 not 保留符号。

例如 0100 >>> 1 (+4) 会给你 0010 (+2)。到目前为止,与 signed 转变和上面的示例没有什么不同。当数字为负数时,有趣的部分出现了:

1100 (-4) 我们尝试将它移动一次:1100 >>> 1,因为符号 not 保留,我们将零放入最高有效位并向右移动,因此我们得到:0110(+6!)。

现实中,取32位到图片中。 -4 == 1111...111100 然后我们将它向右移动:符号为零,其他所有内容都向右移动,因此:0111...11110Integer.MAX_VALUE - 1.

System.out.println(-4 >>> 1);
System.out.println(Integer.MAX_VALUE - 1);

因此 x >>> 31 部分会将符号位移动到最低有效位置,将其他所有内容清零。无论你给它多少,你总是会得到 10

1 00000 ..... 11111
x --------------->1 // x is "zeroed also"
       ignore

并且将 -x 添加到 x >>> 31 只是为了 | 能够正确地满足我们需要的结果。