このコード:
System.out.println(Math.abs(Integer.MIN_VALUE));
戻り値-2147483648
絶対値を次のように返さないで2147483648ください。
このコード:
System.out.println(Math.abs(Integer.MIN_VALUE));
戻り値-2147483648
絶対値を次のように返さないで2147483648ください。
Integer.MIN_VALUEはです-2147483648が、32ビット整数に含めることができる最大値はです+2147483647。32ビット整数で表現しようとすると+2147483648、効果的にに「ロールオーバー」され-2147483648ます。これは、符号付き整数を使用する場合、との2の補数の2進表現が同一である+2147483648ためです。ただし、範囲外と見なされるため-2147483648、これは問題ではありません。+2147483648
この問題についてもう少し詳しく知りたい場合は、2の補数に関するウィキペディアの記事を確認してください。
あなたが指摘する振る舞いは、確かに直感に反しています。ただし、この動作は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です。また、それ0x7FFFFFFFはInteger.MAX_VALUEです。
とはいえ、将来、この直感に反する戻り値による問題をどのように回避できるでしょうか。
@Bombeが指摘しているようintに、以前にsをキャストすることができlongます。しかし、私たちはどちらかでなければなりません
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_VALUEBigIntegersはどこでも使用できます。これ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);
}
int positive = value & Integer.MAX_VALUEオーバーフローします)Integer.MAX_VALUE0Integer.MIN_VALUE最後に、この問題はしばらくの間知られているようです。たとえば、対応するfindbugsルールについてはこのエントリを参照してください。
javadocのMath.abs()についてJavadocが言っていることは次のとおりです。
引数が最も負の表現可能なint値であるInteger.MIN_VALUEの値と等しい場合、結果は同じ値であり、負であることに注意してください。
期待する結果を確認するには、次のコマンドにキャストInteger.MIN_VALUEしlongます。
System.out.println(Math.abs((long) Integer.MIN_VALUE));
2147483648はjavaに整数で格納できません。そのバイナリ表現は、-2147483648と同じです。
これに対する修正が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のいずれかが渡されたかどうかを確認したいのですが、正の値が返され、例外ではありませんが。
しかし(int) 2147483648L == -2147483648 、正の数に相当するものがない負の数が1つあるため、正の値はありません。Long.MAX_VALUEでも同じ動作が見られます。
Math.absは、大きな数では常に機能するわけではありません。7歳のときに学んだこの小さなコードロジックを使用しています。
if(Num < 0){
Num = -(Num);
}