是Java整型原始类型转换“封顶”的铸造型的MAX_INT?(Are Java integer-ty

2019-07-29 11:01发布

我试图跟踪了一些非常奇怪的Java行为。 我有一个涉及到双重的公式,但“保证”给一个整数答案 - 具体而言,一个无符号的32位整数(其中,唉,Java没有做得很好)。 不幸的是,我的答案是不正确有时。

最后,我发现这个问题,但行为还是很奇怪,对我说:一个double直接投给int似乎在被加盖MAX_INT对于有符号整数,而double投的long ,然后将其转换为一个int让我期望答案(-1;表示为带符号的32位整数无符号的32位整数的MAX INT)。

我写了一个小测试程序:

public static void main(String[] args) {
    // This is the Max Int for a 32-bit unsigned integer
    double maxUIntAsDouble = 4294967295.00;
    long maxUintFromDoubleAsLong = (long)maxUIntAsDouble;
    long maxUintFromDoubleAsInt = (int)maxUIntAsDouble;
    int formulaTest = (int) (maxUintFromDoubleAsLong * 1.0);
    int testFormulaeWithDoubleCast =  (int)((long) (maxUintFromDoubleAsLong * 1.0));
    // This is a more-or-less random "big number"
    long longUnderTest = 4123456789L;
    // Max int for a 32-bit unsigned integer
    long longUnderTest2 = 4294967295L;
    int intFromLong = (int) longUnderTest;
    int intFromLong2 = (int) longUnderTest2;
    System.out.println("Long is: " + longUnderTest);
    System.out.println("Translated to Int is:" + intFromLong);
    System.out.println("Long 2 is: " + longUnderTest2);
    System.out.println("Translated to Int is:" + intFromLong2);
    System.out.println("Max UInt as Double: " + maxUIntAsDouble);
    System.out.println("Max UInt from Double to Long: " + maxUintFromDoubleAsLong);
    System.out.println("Max UInt from Double to Int: " + maxUintFromDoubleAsInt);
    System.out.println("Formula test: " + formulaTest);
    System.out.println("Formula Test with Double Cast: " + testFormulaeWithDoubleCast);
}

当我运行这个小程序,我得到:

Long is: 4123456789
Translated to Int is:-171510507
Long 2 is: 4294967295
Translated to Int is:-1
Max UInt as Double: 4.294967295E9
Max UInt from Double to Long: 4294967295
Max UInt from Double to Int: 2147483647
// MAX INT for an unsigned int
Formula test: 2147483647
// Binary: all 1s, which is what I expected
Formula Test with Double Cast: -1

底部两行是我想了解的。 双投给我的预期“-1”; 但直投给了我一个32位有符号整数MAX_INT。 从C ++背景的,我想,如果它给了我一个“奇数”,而不是预期的-1(又称“幼稚铸造”)了解到,但这我茫然不知所措。

所以,接下来的问题:在Java的这种“预期”的行为(例如,任何double直接施放到int将被“封端”以MAX_INT )? 请问铸件任何意外的类型做到这一点? 我希望它是类似shortbyte ,例如; 但什么是“正常现象”铸造一个超大的双浮动的时候?

谢谢!

Answer 1:

这是预期行为。 请记住,没有原始的无符号长或者int类型的Java和Java语言规范 (Java 7中)为基本收缩转换(5.1.3)指出,铸有“过小或过大的”浮点值(无论是双或浮动),以一个整体int类型的或长会使用最低或符号整型(重点煤矿)的最大值:

一个浮点数为整型T的缩小变换需要两个步骤:

  1. 在第一步骤中,浮点数会被转换成一个长,如果T是长,或者为int,如果T是字节,短,炭或int,如下所示:

    • 如果浮点数是NaN(§4.2.3),转换的第一步的结果是一个int或长0。
    • 否则,如果浮点数不是无穷大,浮点值舍入为一个整数值V,使用IEEE 754取朝向零模式(§4.2.3)向零舍入。 然后有两种情况:

      • 一个。 如果T是长,并且该整数值可表示为第一步骤中的长,那么结果是长值V.
      • 湾 否则,如果该整数的值可以被表示为一个int,则第一步骤的结果是int值V.
    • 否则,以下两种情况之一必须是真实的:

      • 一个。 该值必须是太小(大的幅度或负无穷大的负值),并且所述第一步骤的结果是int类型或长的最小可表示值。
      • 该值必须是过大(大的幅度或正无穷大的正的值),并且所述第一步骤的结果是int类型或长的最大可表示值。 *
  2. 在第二步骤中:*如果T是int或长时,转换的结果是,第一步骤的结果。 *如果T是字节,char或短,转换的结果是一个缩小转换的结果为T类型(§5.1.3)第一步骤的结果的。

实施例5.1.3-1。 基本收缩转换

 class Test { public static void main(String[] args) { float fmin = Float.NEGATIVE_INFINITY; float fmax = Float.POSITIVE_INFINITY; System.out.println("long: " + (long)fmin + ".." + (long)fmax); System.out.println("int: " + (int)fmin + ".." + (int)fmax); System.out.println("short: " + (short)fmin + ".." + (short)fmax); System.out.println("char: " + (int)(char)fmin + ".." + (int)(char)fmax); System.out.println("byte: " + (byte)fmin + ".." + (byte)fmax); } } 

此程序产生的输出:

 long: -9223372036854775808..9223372036854775807 int: -2147483648..2147483647 short: 0..-1 char: 0..65535 byte: 0..-1 

对于char,int和长的结果是令人吃惊,产生最小和的类型的表示的最大值。

对于字节和有关的符号和数值的大小,也短暂丢失信息的结果丢失精度。 结果可以通过检查最小和最大INT的低阶位来理解。 最小int是,在十六进制0x80000000的,并且最大int是0x7FFFFFFF的。 这解释了短的结果,这是这些值的低16位,即0×0000和0xFFFF; 它解释了炭的结果,这也是这些值,即,“\ u0000的”和“\ uffff”的低16位; 它解释了字节的结果,这是这些值,即,0×00到0xff的低8位。

第一种情况下int formulaTest = (int) (maxUintFromDoubleAsLong * 1.0); 从而促进maxUintFromDoubleAsLong经由乘法双重,然后将其投射到一个int。 由于该值过大,无法表示为带符号的整数,其值变为2147483647(Integer.MAX_VALUE的)或0x7FFFFFFF的。

至于后者情况下:

带符号的整数的收缩转换为整数类型T简单地丢弃所有,但n个最低阶位,其中n是用于表示类型T.除了的信息有关的数值的大小的可能损失的比特数,这可能导致所得到的值的符号,以从所述输入值的符号不同。

所以int testFormulaeWithDoubleCast = (int)((long) (maxUintFromDoubleAsLong * 1.0)); 第一促进maxUintFromDoubleAsLong翻一番,回长(静止嵌合),然后到一个int。 在最后一次石膏,多余的位被简单地丢弃,让你为0xFFFFFFFF,这是-1时,解释为一个有符号整数。



Answer 2:

这仅仅是语言规范的书写方式。 转换浮点到整数类型,如果该值是目标则最大值被取代的过大。 在从一个整数类型收缩转换到一个较小的一个,所述高位比特将被丢弃。

见JLS 5.1.3。 基本收缩转换

所以,答案在标题的问题是“是”。



文章来源: Are Java integer-type primitive casts “capped” at the MAX_INT of the casting type?