简体   繁体   English

重现行为MAX_VALUE和MIN_VALUE

[英]Reproduce behavior MAX_VALUE and MIN_VALUE

The following also applied to other MIN_VALUE and MAX_VALUE , but let's only focus on Integer for now. 以下内容也适用于其他MIN_VALUEMAX_VALUE ,但现在我们仅关注Integer I know that in Java integers are 32-bit, with Integer.MAX_VALUE = 2147483647 (2 31 -1) and Integer.MIN_VALUE = -2147483648 (-2 31 ). 我知道Java中的整数是32位,其中Integer.MAX_VALUE = 2147483647 (2 31 -1)和Integer.MIN_VALUE = -2147483648 (-2 31 )。 When calculating with these values when you go beyond their bounds, the number wraps around / overflows. 当使用这些值进行计算时,如果超出范围,则数字会环绕/溢出。 So when you do something like Integer.MAX_VALUE + 1 , the result is the same as Integer.MIN_VALUE . 因此,当您执行类似Integer.MAX_VALUE + 1 ,结果与Integer.MIN_VALUE相同。

Here are some basic arithmetic calculations with MIN_VALUE and MAX_VALUE : 以下是一些使用MIN_VALUEMAX_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

Or more in general (iff MIN == -MAX-1 ): 或更多一般而言(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

My question is: how can I reproduce all basic arithmetic operations ( +-*/ ) above manually? 我的问题是:如何手动重现上面的所有基本算术运算( +-*/ )?

The first thing that came to mind was the modulo operator. 首先想到的是模运算符。 So I tried a simple method like this: 所以我尝试了一个简单的方法,像这样:

long reproduceMinMaxFromLongToInt(long n){
  if(n > 2147483647L){
    return n % 2147483648L;
  }
  if(n < -2147483648L){
    return n % -2147483648L;
  }
  return n;
}

Which is correct for most of them, but not all. 这对大多数人是正确的,但不是全部。 (To reduce the question size, here is a TIO link with test code, instead of a copy-paste here.) The ones that are incorrect: (为了减小问题的大小, 这里是带有测试代码的TIO链接 ,而不是此处的复制粘贴。)不正确的内容:

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

The others are correct. 其他是正确的。

How can I modify the reproduceMinMaxFromLongToInt method so it gives the correct result for all basic arithmetic calculations (ignoring calculations like Power, Modulo, Root, and such for now)? 如何修改reproduceMinMaxFromLongToInt方法,以便为所有基本算术计算提供正确的结果(暂时忽略Power,Modulo,Root等计算)?
I know I should probably look at bit-wise operands for the most part, but is it possible to reproduce this behavior without bit-wise operands, using basic arithmetic operands (including modulo) only? 我知道我大概应该在大多数情况下看一下按位操作数,但是是否可以仅使用基本算术操作数(包括模)不使用按位操作数来重现此行为?

EDIT: Note: The Integer is just used as an example. 编辑:注意: Integer仅用作示例。 Of course I could just cast to int in this case. 在这种情况下,我当然可以转换为int But I'm trying to figure out the more general algorithm which also applied to other min / max , like min=-100; max=99 但是我试图找出更通用的算法,该算法也适用于其他min / max ,例如min=-100; max=99 min=-100; max=99 for example. 例如, min=-100; max=99

Here's one without bitwise operations (I'm not counting the constant-generation, they could be written out but it would obscure their meaning) or casts, as you can see it's more complicated than it should be, and it would be worse without Java 8: 这是一个没有按位运算的运算符(我不计算常数代,它们可以写出来,但是会掩盖其含义)或强制转换,因为您会看到它比应有的更加复杂,而且如果没有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);
}

Implementing other pairs of min/max this way is probably a strange thing to do. 用这种方式实现其他的最小/最大对可能是一件奇怪的事情。 A more reasonable approach, probably, is to work only with positive numbers (in Java) modulo the length of the range, and interpret the upper range of them as being negative. 可能更合理的方法是仅使用正数(在Java中)以模数范围的长度为模,并将它们的较高范围解释为负数。

For example if the range was -2 through 2, you could bring them all into 0..4 by mapping them modulo (actual modulo, not Java-style remainder) 5. Then the usual mod-5 arithmetic will act reasonably. 例如,如果范围是-2到2,则可以通过以模(实际模,而不是Java风格的余数)映射它们来将它们全部变成0..4。然后,通常的mod-5算术将合理地起作用。 In the end just map them back to the original range, by interpreting 4 as -1 (which is, in mod-5 arithmetic, a reasonable thing to say) and 3 as -2. 最后,只需将4解释为-1(在mod-5算术中,这是很合理的话),将3解释为-2,即可将它们映射回原始范围。

You could interpret the code above as doing that, but there is the weird issue that (due to the range involved) it had to work with signed numbers as if they were unsigned, so Long.remainderUnsigned made an appearance. 您可以将上面的代码解释为这样做,但是存在一个奇怪的问题(由于涉及的范围),它必须使用带符号的数字,就像它们是无符号的一样,因此Long.remainderUnsigned出现了。 For small ranges that wouldn't be a problem. 对于小范围,这不是问题。

A solution, though perhaps not the one you want is to convert the numbers to int , and then do the arithmetic operation on ints. 一种解决方案(尽管可能不是您想要的一种)是将数字转换为int ,然后对ints进行算术运算。 You'd finally convert back to long to keep the contract of your method. 您最终将转换回long以保持方法的约定。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM