100

このコード:

System.out.println(Math.abs(Integer.MIN_VALUE));

戻り値-2147483648

絶対値を次のように返さないで2147483648ください。

4

8 に答える 8

114

Integer.MIN_VALUEはです-2147483648が、32ビット整数に含めることができる最大値はです+2147483647。32ビット整数で表現しようとすると+2147483648、効果的にに「ロールオーバー」され-2147483648ます。これは、符号付き整数を使用する場合、との2の補数の2進表現が同一である+2147483648ためです。ただし、範囲外と見なされるため-2147483648、これは問題ではありません。+2147483648

この問題についてもう少し詳しく知りたい場合は、2の補数に関するウィキペディアの記事を確認してください。

于 2011-03-26T19:11:47.077 に答える
44

あなたが指摘する振る舞いは、確かに直感に反しています。ただし、この動作はjavadocでMath.abs(int)指定されている動作です。

引数が負でない場合は、引数が返されます。引数が負の場合、引数の否定が返されます。

つまりMath.abs(int)、次のJavaコードのように動作する必要があります。

public static int abs(int x){
    if (x >= 0) {
        return x;
    }
    return -x;
}

つまり、負の場合、-x

JLSセクション15.15.4によると、-xはに等しく(~x)+1~はビット単位の補数演算子です。

これが正しいかどうかを確認するために、例として-1を取り上げましょう。

整数値は、Javaでは16進数の-1ように記録できます(または他の方法でこれを確認してください)。このように取ると:0xFFFFFFFFprintln-(-1)

-(-1) = (~(0xFFFFFFFF)) + 1 = 0x00000000 + 1 = 0x00000001 = 1

だから、それは動作します。

で試してみましょうInteger.MIN_VALUE。最小の整数は、で表すことができることを知っています0x80000000。つまり、最初のビットを1に設定し、残りの31ビットを0に設定すると、次のようになります。

-(Integer.MIN_VALUE) = (~(0x80000000)) + 1 = 0x7FFFFFFF + 1 
                     = 0x80000000 = Integer.MIN_VALUE

Math.abs(Integer.MIN_VALUE)そして、これがリターンの理由Integer.MIN_VALUEです。また、それ0x7FFFFFFFInteger.MAX_VALUEです。

とはいえ、将来、この直感に反する戻り値による問題をどのように回避できるでしょうか。

  • @Bombeが指摘しているようintに、以前にsをキャストすることができlongます。しかし、私たちはどちらかでなければなりません

    • それらをsにキャストし直しますがint、これは機能しないため Integer.MIN_VALUE == (int) Math.abs((long)Integer.MIN_VALUE)です。
    • または、もあるので、に等しい値でlong呼び出されないことを期待して、sを続行します。Math.abs(long)Long.MIN_VALUEMath.abs(Long.MIN_VALUE) == Long.MIN_VALUE
  • BigIntegersはどこでも使用できます。これBigInteger.abs()は、実際には常に正の値を返すためです。これは良い代替手段ですが、生の整数型を操作するよりも少し遅くなります。

  • 次のように、の独自のラッパーを作成できますMath.abs(int)

/**
 * Fail-fast wrapper for {@link Math#abs(int)}
 * @param x
 * @return the absolute value of x
 * @throws ArithmeticException when a negative value would have been returned by {@link Math#abs(int)}
 */
public static int abs(int x) throws ArithmeticException {
    if (x == Integer.MIN_VALUE) {
        // fail instead of returning Integer.MAX_VALUE
        // to prevent the occurrence of incorrect results in later computations
        throw new ArithmeticException("Math.abs(Integer.MIN_VALUE)");
    }
    return Math.abs(x);
}
  • 整数のビット単位のANDを使用して上位ビットをクリアし、結果が負でないことを確認します:(基本的にからではなくからにint positive = value & Integer.MAX_VALUEオーバーフローします)Integer.MAX_VALUE0Integer.MIN_VALUE

最後に、この問題はしばらくの間知られているようです。たとえば、対応するfindbugsルールについてはこのエントリを参照してください。

于 2013-06-22T23:01:57.687 に答える
13

javadocのMath.abs()についてJavadocが言っていることは次のとおりです。

引数が最も負の表現可能なint値であるInteger.MIN_VALUEの値と等しい場合、結果は同じ値であり、負であることに注意してください。

于 2011-03-26T19:13:15.590 に答える
6

期待する結果を確認するには、次のコマンドにキャストInteger.MIN_VALUElongます。

System.out.println(Math.abs((long) Integer.MIN_VALUE));
于 2011-03-26T19:16:05.667 に答える
1

2147483648はjavaに整数で格納できません。そのバイナリ表現は、-2147483648と同じです。

于 2011-03-26T19:14:35.963 に答える
1

これに対する修正がJava15にあり、intおよびlongのメソッドになります。彼らはクラスに出席します

java.lang.Math and java.lang.StrictMath

メソッド。

public static int absExact(int a)
public static long absExact(long a)

合格した場合

Integer.MIN_VALUE

また

Long.MIN_VALUE

例外がスローされます。

https://bugs.openjdk.java.net/browse/JDK-8241805

Long.MIN_VALUEまたはInteger.MIN_VALUEのいずれかが渡されたかどうかを確認したいのですが、正の値が返され、例外ではありませんが。

于 2020-04-20T14:54:07.417 に答える
0

しかし(int) 2147483648L == -2147483648 、正の数に相当するものがない負の数が1つあるため、正の値はありません。Long.MAX_VALUEでも同じ動作が見られます。

于 2011-03-26T19:15:46.700 に答える
-3

Math.absは、大きな数では常に機能するわけではありません。7歳のときに学んだこの小さなコードロジックを使用しています。

if(Num < 0){
  Num = -(Num);
} 
于 2019-11-11T21:51:18.857 に答える