以下内容也适用于其他MIN_VALUE
和MAX_VALUE
,但我们暂时只关注Integer
。我知道Java中的整数是32位,Integer.MAX_VALUE = 2147483647
(2 31 -1)和Integer.MIN_VALUE = -2147483648
(-2 31 )。当你超出它们的界限时使用这些值计算时,数字会回绕/溢出。因此,当您执行Integer.MAX_VALUE + 1
之类的操作时,结果与Integer.MIN_VALUE
相同。
以下是MIN_VALUE
和MAX_VALUE
的基本算术计算:
Integer.MAX_VALUE: 2147483647
Integer.MAX_VALUE + 1: -2147483648
Integer.MAX_VALUE - 1: 2147483646
Integer.MAX_VALUE * 2: -2
Integer.MAX_VALUE * 3: 2147483645
Integer.MAX_VALUE * 4: -4
Integer.MAX_VALUE * 5: 2147483643
Integer.MAX_VALUE / Integer.MAX_VALUE: 1
Integer.MAX_VALUE * Integer.MAX_VALUE: 1
Integer.MAX_VALUE / Integer.MIN_VALUE: 0
Integer.MAX_VALUE * Integer.MIN_VALUE: -2147483648
Integer.MAX_VALUE - Integer.MIN_VALUE: -1
Integer.MAX_VALUE + Integer.MIN_VALUE: -1
-Integer.MAX_VALUE: -2147483647
-Integer.MAX_VALUE - 1: -2147483648
-Integer.MAX_VALUE + 1: -2147483646
Integer.MIN_VALUE: -2147483648
Integer.MIN_VALUE + 1: -2147483647
Integer.MIN_VALUE - 1: 2147483647
Integer.MIN_VALUE * 2: 0
Integer.MIN_VALUE * 3: -2147483648
Integer.MIN_VALUE * 4: 0
Integer.MIN_VALUE * 5: -2147483648
Integer.MIN_VALUE / Integer.MAX_VALUE: -1
Integer.MIN_VALUE / Integer.MIN_VALUE: 1
Integer.MIN_VALUE * Integer.MIN_VALUE: 0
Integer.MIN_VALUE - Integer.MAX_VALUE: 1
-Integer.MIN_VALUE: -2147483648
-Integer.MIN_VALUE - 1: 2147483647
-Integer.MIN_VALUE + 1: -2147483647
或更多(iff MIN == -MAX-1
):
MAX: MAX
MAX + 1: MIN
MAX - 1: MAX - 1
MAX * 2: -2
MAX * 3: MAX - 2
MAX * 4: -4
MAX * 5: MAX - 4
MAX / MAX: 1
MAX * MAX: 1
MAX / MIN: 0
MAX * MIN: MIN
MAX - MIN: -1
MAX + MIN: -1
-MAX: MIN + 1
-MAX - 1: MIN
-MAX + 1 MIN + 2
MIN: MIN
MIN + 1: MIN + 1
MIN - 1: MAX
MIN * 2: 0
MIN * 3: MIN
MIN * 4: 0
MIN * 5: MIN
MIN / MAX: -1
MIN / MIN: 1
MIN * MIN: 0
MIN - MAX: 1
-MIN: MIN
-MIN - 1: MAX
-MIN + 1: MIN + 1
我的问题是:如何手动重现上述所有基本算术运算(+-*/
)?
首先想到的是模运算符。所以我尝试了一个这样简单的方法:
long reproduceMinMaxFromLongToInt(long n){
if(n > 2147483647L){
return n % 2147483648L;
}
if(n < -2147483648L){
return n % -2147483648L;
}
return n;
}
对大多数人来说这是正确的,但不是全部。 (要使用测试代码减少问题大小here is a TIO link,而不是在此处复制粘贴。)那些不正确的内容:
Calculation: Should be But is instead
MAX_VALUE + 1: -2147483648 0
MAX_VALUE * 2: -2 2147483646
MAX_VALUE * 4: -4 2147483644
MAX_VALUE * MIN_VALUE: -2147483648 0
MAX_VALUE - MIN_VALUE: -1 2147483647
MIN_VALUE - 1: 2147483647 -1
MIN_VALUE * 3: -2147483648 0
MIN_VALUE * 5: -2147483648 0
-MIN_VALUE - 1: 2147483647 2147483647
其他人都是正确的。
如何修改reproduceMinMaxFromLongToInt
方法,以便为所有基本算术计算提供正确的结果(忽略Power,Modulo,Root等计算)?
我知道我应该在大多数情况下考虑逐位操作数,但是如果没有逐位操作数,只能使用基本算术操作数(包括模数)来重现这种行为吗?
编辑:注意:Integer
仅用作示例。当然,在这种情况下我可以转换为int
。但我正在尝试找出更通用的算法,该算法也适用于其他min
/ max
,例如min=-100; max=99
。
答案 0 :(得分:1)
这里有一个没有按位操作(我不计算常数生成,它们可以被写出来,但它会模糊它们的意思)或演员表,你可以看到它的更多比它应该更复杂,如果没有Java 8,情况会更糟:
long reproduceMinMaxFromLongToInt(long n){
// reduce range
n = Long.remainderUnsigned(n, 1L << 32);
// sign-extend
if (n < (1L << 31))
return n;
else
return n - (1L << 32);
}
以这种方式实现其他对min / max可能是一件奇怪的事情。一种更合理的方法可能是仅使用正数(以Java为单位)模拟范围的长度,并将它们的上限解释为负数。
例如,如果范围是-2到2,你可以通过将它们模数映射(实际模数,而不是Java风格的余数)将它们全部带入0..4。然后通常的mod-5算法将合理地起作用。最后只需将它们映射回原始范围,将4解释为-1(即,在mod-5算术中,这是合理的说法),将3解释为-2。
你可以将上面的代码解释为这样做,但是有一个奇怪的问题(由于所涉及的范围)它必须使用带符号的数字,好像它们是无符号的,所以Long.remainderUnsigned
出现了。对于不会成为问题的小范围。
答案 1 :(得分:0)
一个解决方案,虽然可能不是您想要的解决方案,但是将数字转换为int
,然后对整数进行算术运算。您最终会转换回long
以保留您方法的合约。