整型转长整型赋值

15

我一直在尝试将一个int变量分配给一个long变量进行转换。 代码如下:

public static void main(String []args){
    int i = 1024;
    long j = i;
    long k = i*i*i*i;
    System.out.println("j= " +j+ ", k= " +k);
}

因此,在打印j时,它只输出了1024。但是在打印k时,它显示了一个溢出(k=0)。我通过使用这种技术解决了这个问题,其中我将每个i显式转换为long。即:

public static void main(String []args){
    int i = 1024;
    long j = i;
    long k = ((long)i)*((long)i)*((long)i)*((long)i);
    System.out.println("j= " +j+ ", k= " +k);
}
现在,它展示了jk的正确值。 所以,我想知道为什么在第二种情况下需要将int转换为long,但在第一种情况下不需要。 k是一个long类型,在这个繁重的赋值之后可以保留这个值。但是,为什么没有被正确地分配呢?

将第一个 i 强制转换为 long 应该就足够了。 - Display Name
4
您所发现的缺陷模式——将可能导致溢出的整数乘法“太晚”转换为较大类型——在C#和Java中相对常见;我们发现每百万行代码分析中有五个以上的实例。一个相关的缺陷,具有类似的发现率,是两个整数除法并“太晚”转换为double;人们经常感到惊讶的是,三百除以五百并赋给double是零,而不是0.6。 - Eric Lippert
5个回答

19

原因是您的线路

long k = i*i*i*i;

可以被看作是

long k = ((i*i)*i)*i;

或者...

int k1 = i*i;
int k2 = k1*i;
int k3 = k2*i;
long k = k3;

当任何kn溢出时,就会出现错误。

当执行转换时,显然通过始终将long相乘来规避此问题。

当然,最简单的修改初始程序的方法是立即将i定义为long,而不是int

long i = 1024L;

@dav_i,k3会溢出,因为它是int变量,必须改为long - MajidTaheri

7
这个问题基于一个事实:不同类型使用不同数量的内存。int和long都是整数类型,区别在于int占用4字节,而long占用8字节。
让我们稍微修改一下你的代码:
public class Test {


  public static void main(String []args){
        int i = 1024;
        long j = i;
        long k = i*i*i;

        System.out.println("My multipliers are of type int:");
        System.out.println("j= " +j+ ", k= " +k);           
        System.out.println("Is k less than Integer.MAX_VALUE: "  + (k < Integer.MAX_VALUE? "YES" : "NO"));
        k = i*i*i*i;
        System.out.println("j= " +j+ ", k= " +k);

        //now multiplying with j instead of i
        System.out.println("\nNow Im working with a long type:");
        k = j*j*j;
        System.out.println("j= " +j+ ", k= " +k);           
        System.out.println("Is k less than Integer.MAX_VALUE: "  + (k < Integer.MAX_VALUE? "YES" : "NO"));
        k = j*j*j*j;
        System.out.println("j= " +j+ ", k= " +k);
        System.out.println("Is k less than Integer.MAX_VALUE: "  + (k < Integer.MAX_VALUE? "YES" : "NO"));
        k = j*j*j*j;

     }

}

上面的代码显示,当您将i乘以3次时,结果是一个比Integer.MAX_VALUE(即2147483647)小的值,而当您将其乘以4次时,结果为0,因为在这些乘数的可怜的4个字节中没有足够的空间。 :) 但是,当乘数(右侧,j)为long类型时,您可以看到正确的值被打印出来,最后一行打印显示语句k < Integer.MAX_VALUE为false,这就是您得到0的原因。 :)

谢谢您的回复。我很感激。 - Shashish Chandra

6

i*i*i*i 是整数相乘,所以结果仅为整数(在您的情况下会溢出)。如果要得到长结果,则只需要将其中一个转换为 long 即可。

long k = ((long)i)*i*i*i;

请尝试 @ShashishChandra - Sanjeev
1
我已经尝试过了,多亏了你,它成功了。我只是在问,这里有没有结合律的作用? - Shashish Chandra
是的,有的。尝试将最后一个转换为long而不是第一个,你会看到的。 - Sanjeev
1
所以,它是左结合的,只能按照这种方式工作。感谢您的回复,我非常感激。 - Shashish Chandra
1
是的,在这种情况下它会起作用。因为第四次乘以“i”将其超出了“Integer.MaxValue”。因此,两种方法都可以使用。但是,如果您选择更高的“i”,使得三个乘法超出了“Integer.MaxValue”,则会看到不同的行为。 - Sanjeev
显示剩余2条评论

2
在第一个例子中,i的值是int类型,整数乘法会发生,i*i*i*i的结果是整数,因此会出现整数溢出
而在第二个例子中,您明确地将结果设置为long

谢谢您的回复。非常有帮助。感激不尽。 - Shashish Chandra

2

1099511627776是乘法结果,因为它是整数乘法,所以i*i*i的值为1073741824,但是乘以1024后超出了范围,导致整数溢出,k将变为0。

  • 您可以将i之一转换为long
  • 1L乘以(1L*i*i*i*i),但不要用i*i*i*i*1L
  • 您还可以将i*i*i分配给long,然后像这样与i相乘:long k =(k=i*i*i)*i;

1
谢谢您的回复。我很感激。 - Shashish Chandra

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接