关于数学:Java算术int与long

 2020-05-24 

Java arithmetic int vs. long

我已经在Google上进行了一些搜索,但似乎找不到我想要的东西。 我试图找出有关Java中算术工作方式的详细信息。 例如,如果您将两个long累加在一起,这是否使用了将两个int累加在一起时使用的同一加法运算符? 同样,当您将long和int混合在这样的算术表达式中时,到底发生了什么:

1
2
3
4
5
long result;
long operand a = 1;
int operand b = 999999999;

result = a + b;

如果有人能对此有所启发或发布指向相关文章的链接,那将是很棒的。 谢谢!

编辑:感谢到目前为止的答复。 另外,只要您将表达式赋值给表达式中最宽泛的原始类型的变量,对不同的原始进行算术运算是否安全?


当混合类型时,int会自动加长到一个long,然后将两个long相加以产生结果。 Java语言规范说明了包含不同基本类型的操作的过程。

具体来说,以下是每个基本体将扩展为的类型,而无需强制转换:

  • 字节到short,int,long,float或double
  • 短至int,long,float或double
  • char转换为int,long,float或double
  • int转换为long,float或double
  • 长时间漂浮或翻倍
  • 浮动到两倍


另请:转化和促销

据此,您的int被提升为long,然后被评估。

例如,int + double和其他原语也会发生同样的情况。即。

1
System.out( 1 + 2.0 );// prints 3.0 a double

至于加法运算符,我几乎是一样的,但是我没有任何参考。

快速查看编译器的源代码可以发现它们是不同的。

iadd用于int加法,ladd用于长加法:

请参见以下示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
$cat Addition.java
public class Addition {
    public static void main( String [] args ) {
        int  a  = Integer.parseInt(args[0]);
        long b = Long.parseLong(args[0]);
        // int addition
        int  c  = a + a;
        // long addition
        long d = a + b;
    }
}
$javac Addition.java
$

编译时生成的字节码是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$javap -c Addition
Compiled from"Addition.java"
public class Addition extends java.lang.Object{
public Addition();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   iconst_0
   2:   aaload
   3:   invokestatic    #2; //Method java/lang/Integer.parseInt:(Ljava/lang/String;)I
   6:   istore_1
   7:   aload_0
   8:   iconst_0
   9:   aaload
   10:  invokestatic    #3; //Method java/lang/Long.parseLong:(Ljava/lang/String;)J
   13:  lstore_2
   14:  iload_1
   15:  iload_1
   16:  iadd
   17:  istore  4
   19:  iload_1
   20:  i2l
   21:  lload_2
   22:  ladd
   23:  lstore  5
   25:  return

}

查看第16行,它说:iadd(用于int加法),而第22行说ladd(用于长加法)

Also, is it safe to perform arithmetic with different primitives so long as you are assigning into a variable of the widest primitive type in your expression?

是的,以较小的尺寸执行算术也是"安全的",从某种意义上说,它们不会破坏程序,只会丢失信息。

例如,尝试将Integer.MAX_VALUE添加到Integer.MAX_VALUE以查看会发生什么,或者int x = ( int ) ( Long.MAX_VALUE - 1 );


这称为算术提升。有关详细信息,请访问http://www.cafeaulait.org/course/week2/22.html


Also, is it safe to perform arithmetic with different primitives so long as you are assigning into a variable of the widest primitive type in your expression?

这取决于您所指的安全。当然,这不会避免您需要考虑溢出的可能性。


1
2
3
4
int a=5;  
long b=10;  
a+=b;  
System.out.println(a);

主要区别在于,使用a = a + b时,不会进行类型转换,因此编译器会因为不进行类型转换而对您感到生气。
但是对于a += b,它真正要做的是将b类型转换为与a兼容的a类型。


这个简单的示例可以清除在Java中进行算术运算时对数据类型转换的疑问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    byte a = 1;
    short b = 1;
    System.out.println(a+b);                     //Output = 2
    Object o = a+b;                              //Object becomes int
    System.out.println(o.getClass().getName());  //Output = java.lang.Integer

    int c = 1;
    System.out.println(a+b+c);                   //Output = 3
    o = a+b+c;                                   //Object becomes int
    System.out.println(o.getClass().getName());  //Output = java.lang.Integer

    long d = 1l;
    System.out.println(a+b+c+d);                 //Output = 4
    o = a+b+c+d;                                 //Object becomes long
    System.out.println(o.getClass().getName());  //Output = java.lang.Long

    float e = 1.0f;
    System.out.println(a+b+c+d+e);               //Output = 5.0
    o = a+b+c+d+e;                               //Object becomes float
    System.out.println(o.getClass().getName());  //Output = java.lang.Float

    double f = 1.0;
    System.out.println(a+b+c+d+e+f);             //Output = 6.0
    o = a+b+c+d+e+f;                             //Object becomes double
    System.out.println(o.getClass().getName());  //Output = java.lang.Double

以下是根据Java中范围的数据类型顺序:

1
    byte<short<int<long<float<double

这是扩展发生的顺序。

注意:float的范围比long长,但大小较小。


答案指出了算术提升。但是考虑到这一点,我陷入了以下陷阱(我感到羞耻),在这里我要指出:
如果对我来说有两个以上的操作数,则似乎计算是从左到右执行的,并且如果焦点上的实际两个操作数具有不同的类型,则会进行算术提升。
因此,以下代码对s1和s2产生不同的结果。我对此的解释是:
在计算s1时,首先将a和b作为两个整数相加(并且发生溢出),然后将其与c的结果(一个long)相加。
在计算s2时,首先将c和b相加(一样长),然后将a相加(一样长地提升),因此不会发生溢出。

1
2
3
4
5
6
final int a = Integer.MAX_VALUE;
final int b = 1;
final long c = 1L;
final long s1 = a + b + c;
final long s2 = c + b + a;
System.out.println("s1=" + s1 +", s2=" + s2);

输出将是:
s1=-2147483647, s2=2147483649