Java整数类型原语是否在转换类型的MAX_INT处“加盖”?

时间:2012-05-17 18:36:57

标签: java casting int double

我试图追踪一些非常奇怪的Java行为。我有一个涉及double的公式,但是“保证”给出一个整数答案 - 具体来说,是一个无符号的32位整数(唉,Java不能很好)。不幸的是,我的回答有时是不正确的。

最终我发现了这个问题,但对我来说行为仍然非常奇怪:double直接投放到int似乎被限制在{{ 1}}对于有符号整数,而MAX_INT强制转换为double 然后强制转换为long会得到预期答案(-1;无符号32位整数的MAX INT,表示为带符号的32位整数。)

我写了一个小测试程序:

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);
}

底部两行是我想要了解的。双重演员给了我预期的“-1”;但直接转换为MAX_INT提供了一个32位有符号整数。来自C ++背景,我会理解它是否给了我一个“奇数”而不是预期的-1(又名“天真的演员”),但这让我感到困惑。

那么,接下来的问题是:Java中的这种“预期”行为(例如直接转移到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}}任何double会被“限制”为int)吗?对任何意外类型进行强制转换吗?例如,我希望MAX_INTshort类似;但是当把一个超大双倍的东西放到浮动状态时,“预期的行为”是什么?

谢谢!

2 个答案:

答案 0 :(得分:11)

这是预期的行为。请记住,Java中没有原始的unsigned long或int类型,并且用于Narrowing原始转换的Java Language Specification(Java 7)(5.1.3)声明抛出“太小或太大”的浮点值(是它是double或float)到整数类型的int或long将使用有符号整数类型的最小值或最大值(强调我的):

  

将浮点数转换为整数类型   T需要两个步骤:

     
      
  1. 在第一步中,浮点数转换为   一个long,如果T很长,或者一个int,如果T是byte,short,char或   int,如下:

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

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

           
          
      • 一个。该值必须太小(大幅度或负无穷大的负值),第一步的结果是   int或long类型的最小可表示值。
      •   
      • 湾该值必须太大(大幅度或正无穷大的正值),第一步的结果是   int或long类型的最大可表示值。 *
      •   
    •   
  2.   
  3. 在第二步中:*如果T为int或long,则转换结果是第一步的结果。 *如果T是byte,char或   简而言之,转换的结果是缩小的结果   转换为第一步结果的类型T(第5.1.3节)。

  4.         

    例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和long的结果并不令人惊讶,产生了   该类型的最小和最大可表示值。

         

    字节和短消息的结果会丢失有关标志和的信息   数值的大小也会失去精度。结果   可以通过检查最小值和低位的低位来理解   最大的int。最小的int是十六进制,0x80000000,和   最大int是0x7fffffff。这解释了短暂的结果   这些值的低16位,即0x0000和0xffff;它   解释了char结果,这些结果也是低16位   值,即'\ u0000'和'\ uffff';它解释了字节   结果,这些值的低8位,即0x00和   0xff的。

第一种情况int formulaTest = (int) (maxUintFromDoubleAsLong * 1.0);因此通过乘法将maxUintFromDoubleAsLong提升为double,然后将其强制转换为int。由于该值太大而无法表示为有符号整数,因此该值变为2147483647(Integer.MAX_VALUE)或0x7FFFFFFF。

至于后一种情况:

  

将有符号整数缩小转换为整数类型T只会丢弃除n个最低位之外的所有位,其中n是数字   用于表示类型T的位数。除了可能的丢失   有关数值大小的信息,这可能会导致   结果值的符号与输入符号不同   值。

所以int testFormulaeWithDoubleCast = (int)((long) (maxUintFromDoubleAsLong * 1.0));首先将maxUintFromDoubleAsLong提升为double,返回long(仍然适合)然后再提升为int。在最后一次转换中,多余的位被简单地删除,留下0xFFFFFFFF,当被解释为有符号整数时为-1。

答案 1 :(得分:3)

这就是语言规范的编写方式。将浮点数转换为整数类型,如果该值对于目标而言太大,则替换最大值。在从一个整数类型到较小整数类型的缩小转换中,高位比特被丢弃。

请参阅JLS 5.1.3. Narrowing Primitive Conversion

因此,标题中问题的答案是“是”。