簡體   English   中英

Java中原始整數類型的不一致行為

[英]Inconsistent behaviour of primitive integer types in Java

有人可以解釋一下,為什么我在Java中為表示整數的四種基本類型中的兩種獲得不同的行為? AFAIK全部四個都是簽名的,它們都使用最重要的位作為符號位,那么為什么字節和短行為正常,而int和long行為,好吧,奇怪? oracle文檔的片段解釋這將是完美的。

byte a = (byte) (Math.pow(2, 7)-1); //127 - as expected
short b = (short) (Math.pow(2, 15)-1); //32767 - as expected
int c = (int) (Math.pow(2, 31)-1); //2147483647 - as expected
long d = (long) (Math.pow(2, 63)-1); //9223372036854775807 - as expected

a = (byte) (Math.pow(2, 7)); //-128 - as expected
b = (short) (Math.pow(2, 15)); //-32768 - as expected
c = (int) (Math.pow(2, 31)); //2147483647 - why not '-2147483648'?
d = (long) (Math.pow(2, 63)); //9223372036854775807 - why not '-9223372036854775808'?

a = (byte) (Math.pow(2, 8)); //0 - as expected
b = (short) (Math.pow(2, 16)); //0 - as expected
c = (int) (Math.pow(2, 32)); //2147483647 - why not '0'?
d = (long) (Math.pow(2, 64)); //9223372036854775807 - why not '0'?

我正在使用Oracle的Java SE 1.7 for Windows。 操作系統是Windows 7 Professional SP1

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

在閱讀完所有答案並調整我的代碼后編輯。
總而言之,我發現獲得預期值的唯一方法是使用BigInteger。 Shift運算符適用於字節,短路和整數,但是當涉及到longs時,我會在一次故障時使用它。

byte a = (byte) ((1l << 7) - 1); //127 - as expected
short b = (short) ((1l << 15) - 1); //32767 - as expected
int c = (int) (1l << 31) - 1; //2147483647 - as expected
long d = (1l << 63) - 1; //9223372036854775807 - as expected

a = (byte) (1l << 7); //-128 - as expected
b = (short) (1l << 15); //-32768 - as expected
c = (int) 1l << 31; //-2147483648 - as expected
d = 1l << 63; //-9223372036854775808 - as expected

a = (byte) (1l << 8); //0 - as expected
b = (short) (1l << 16); //0 - as expected
c = (int) (1l << 32); //0 - as expected
d = 1l << 64; //1 instead of 0, probably because of the word length limitation      

使用BigInteger,一切都可以完美運行

byte a = (byte) (new BigInteger("2").pow(7).longValue() - 1); //127 - as expected
short b = (short) (new BigInteger("2").pow(15).longValue() - 1); //32767 - as expected
int c = (int) (new BigInteger("2").pow(31).longValue() - 1); //2147483647 - as expected
long d = (new BigInteger("2").pow(63).longValue() - 1); //9223372036854775807 - as expected

a = (byte) (new BigInteger("2").pow(7).longValue()); //-128 - as expected
b = (short) (new BigInteger("2").pow(15).longValue()); //-32768 - as expected
c = (int) new BigInteger("2").pow(31).longValue(); //-2147483648 - as expected
d = new BigInteger("2").pow(63).longValue(); //-9223372036854775808 - as expected

a = (byte) (new BigInteger("2").pow(8).longValue()); //0 - as expected
b = (short) (new BigInteger("2").pow(16).longValue()); //0 - as expected
c = (int) (new BigInteger("2").pow(32).longValue()); //0 - as expected
d = new BigInteger("2").pow(64).longValue(); //0 - as expected

謝謝大家的幫助!

JLS的5.1.3節討論了演員使用的縮小基元轉換的行為

否則,以下兩種情況之一必須為真:

該值必須太小(大幅度或負無窮大的負值),第一步的結果是int或long類型的最小可表示值。

該值必須太大(大幅度或正無窮大的正值),第一步的結果是int或long類型的最大可表示值

(強調我的)

這就是為什么(int) (Math.pow(2, 32)); 變為Integer.MAX_VALUE(long) (Math.pow(2, 64)) Long.MAX_VALUE (long) (Math.pow(2, 64))變為Long.MAX_VALUE

Math.pow()返回一個double ,然后在轉換為整數類型時進行舍入。 在使它們溢出所需的精度下, double顯然是圓形的。

指導:

public class PowTest {
    public static void main(String[] argv) {
        double powResult = Math.pow(2.0,31.0);
        int powInt = (int) powResult;
        long powLong = (long) powResult;
        int longInt = (int) powLong;
        System.out.println("Double = " + powResult + ", int = " + powInt + ", long = " + powLong + ", longInt = " + longInt);
    }
}

結果:

C:\JavaTools>java PowTest
Double = 2.147483648E9, int = 2147483647, long = 2147483648, longInt = -2147483648

double - > int轉換是四舍五入的。 long - > int轉換被截斷。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM