Java 中 int 或 long 的 Math.signum(double) 的等效函数
Equivalent function for Math.signum(double) for int or long in Java
在Java 用于其他原始数字,如 int 或 long。我不想写像
这样的代码
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;第一位是符号),向右移动 signed:1100 >> 1
是 1110
(-2)。做除法,但保留标志。
因此,如果我们移位 31 次,我们将丢弃数字的最后 31 位,将符号位移动到最低有效位置并保留原始符号。或者简单地说,取 31 位,将其置于 0 位置并丢弃其他所有内容。
0 00000 ..... 11111
x --------------->0 // x is kept
ignore
第二部分 -x >>> 31
是 unsigned 移位,这意味着我们移位时 not 保留符号。
例如 0100 >>> 1
(+4) 会给你 0010
(+2)。到目前为止,与 signed 转变和上面的示例没有什么不同。当数字为负数时,有趣的部分出现了:
1100
(-4) 我们尝试将它移动一次:1100 >>> 1
,因为符号 not 保留,我们将零放入最高有效位并向右移动,因此我们得到:0110
(+6!)。
现实中,取32位到图片中。 -4 == 1111...111100
然后我们将它向右移动:符号为零,其他所有内容都向右移动,因此:0111...11110
或 Integer.MAX_VALUE - 1
.
System.out.println(-4 >>> 1);
System.out.println(Integer.MAX_VALUE - 1);
因此 x >>> 31
部分会将符号位移动到最低有效位置,将其他所有内容清零。无论你给它多少,你总是会得到 1
或 0
。
1 00000 ..... 11111
x --------------->1 // x is "zeroed also"
ignore
并且将 -x
添加到 x >>> 31
只是为了 |
能够正确地满足我们需要的结果。
在Java 用于其他原始数字,如 int 或 long。我不想写像
这样的代码 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;第一位是符号),向右移动 signed:1100 >> 1
是 1110
(-2)。做除法,但保留标志。
因此,如果我们移位 31 次,我们将丢弃数字的最后 31 位,将符号位移动到最低有效位置并保留原始符号。或者简单地说,取 31 位,将其置于 0 位置并丢弃其他所有内容。
0 00000 ..... 11111
x --------------->0 // x is kept
ignore
第二部分 -x >>> 31
是 unsigned 移位,这意味着我们移位时 not 保留符号。
例如 0100 >>> 1
(+4) 会给你 0010
(+2)。到目前为止,与 signed 转变和上面的示例没有什么不同。当数字为负数时,有趣的部分出现了:
1100
(-4) 我们尝试将它移动一次:1100 >>> 1
,因为符号 not 保留,我们将零放入最高有效位并向右移动,因此我们得到:0110
(+6!)。
现实中,取32位到图片中。 -4 == 1111...111100
然后我们将它向右移动:符号为零,其他所有内容都向右移动,因此:0111...11110
或 Integer.MAX_VALUE - 1
.
System.out.println(-4 >>> 1);
System.out.println(Integer.MAX_VALUE - 1);
因此 x >>> 31
部分会将符号位移动到最低有效位置,将其他所有内容清零。无论你给它多少,你总是会得到 1
或 0
。
1 00000 ..... 11111
x --------------->1 // x is "zeroed also"
ignore
并且将 -x
添加到 x >>> 31
只是为了 |
能够正确地满足我们需要的结果。