整数演算とオーバーフロー
整数の除算、剰余、オーバーフローの動作と、その検出方法を理解します。
「整数演算とオーバーフロー」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはJava Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Java Academyコースには全4レッスンが含まれています。
整数演算とオーバーフロー
Javaの整数には固定サイズがあります。計算結果が最大値または最小値を超えると、静かにラップアラウンドします。例外はスローされません。この仕組みを理解すると、見つけにくいバグを防げます。
整数の範囲
各整数型の範囲は、ビット幅によって決まります:
byte:-128~127short:-32,768~32,767int:-2,147,483,648~2,147,483,647long:-9.2 × 10^18~9.2 × 10^18
System.out.println(Integer.MAX_VALUE); // 2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648
System.out.println(Long.MAX_VALUE); // 9223372036854775807
System.out.println(Byte.MAX_VALUE); // 127オーバーフロー:静かなラップアラウンド
Integer.MAX_VALUEに1を加えると、Integer.MIN_VALUEにラップアラウンドします。これは2の補数演算です。Javaはオーバーフローを検出する保証をせず、例外もスローしません。
int max = Integer.MAX_VALUE;
System.out.println(max + 1); // -2147483648 (overflow!)
byte b = 127;
b++; // wraps to -128
System.out.println(b); // -128
// Real bug: counting votes in a large election with int
int votes = Integer.MAX_VALUE;
votes += 100; // silently wrong
System.out.println(votes); // negative number!Math.addExactによるオーバーフローの検出
Java 8以降では、Math.addExact()、multiplyExact()、subtractExact()が導入されました。これらは暗黙にラップアラウンドする代わりに、オーバーフロー時にArithmeticExceptionをスローします。
try {
int result = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
System.out.println("Overflow detected!"); // prints this
}
try {
long safe = Math.multiplyExact(100_000L, 100_000L);
System.out.println(safe); // 10000000000
} catch (ArithmeticException e) {
System.out.println("Multiply overflow");
}整数除算と剰余
整数除算はゼロ方向に切り捨てられます。%演算子は、被除数と同じ符号の余りを返します。ゼロ除算には注意してください。ArithmeticExceptionがスローされます。
System.out.println(10 / 3); // 3 (not 3.33)
System.out.println(10 % 3); // 1
System.out.println(-10 % 3); // -1 (sign follows dividend)
System.out.println(-10 % -3); // -1
try {
int x = 5 / 0; // ArithmeticException: / by zero
} catch (ArithmeticException e) {
System.out.println(e.getMessage()); // / by zero
}
// Float division by zero gives Infinity, not exception
System.out.println(5.0 / 0); // Infinity大きな数のためのlong演算
値がintの範囲を超える可能性がある場合は、longを使用します。代入前のオーバーフローを防ぐため、longリテラルには必ずLを付けてください。
// Bug: multiplication done as int, then widened
long wrong = 1_000_000 * 1_000_000; // overflows int!
System.out.println(wrong); // -727379968 (wrong!)
// Fix: one operand is long
long correct = 1_000_000L * 1_000_000L;
System.out.println(correct); // 1000000000000
// Or cast first
long alsOk = (long) 1_000_000 * 1_000_000;
System.out.println(alsOk); // 1000000000000ビットシフト演算子
ビットシフト演算子は、2の累乗による乗算や除算を高速に行う方法です:
n << k— 左シフト:2^kを掛けますn >> k— 符号付き右シフト:2^kで割りますn >>> k— 符号なし右シフト:0で埋めます
int n = 8;
System.out.println(n << 1); // 16 (8 * 2)
System.out.println(n << 2); // 32 (8 * 4)
System.out.println(n >> 1); // 4 (8 / 2)
System.out.println(n >> 2); // 2 (8 / 4)
// Check if number is power of 2
boolean isPow2 = n > 0 && (n & (n - 1)) == 0;
System.out.println(isPow2); // trueビット単位のAND、OR、XOR
ビット単位の演算子は個々のビットに対して動作し、権限、フラグ、低レベルプロトコルで使用されます。
int a = 0b1010; // 10
int b = 0b1100; // 12
System.out.println(Integer.toBinaryString(a & b)); // 1000 (AND = 8)
System.out.println(Integer.toBinaryString(a | b)); // 1110 (OR = 14)
System.out.println(Integer.toBinaryString(a ^ b)); // 0110 (XOR = 6)
System.out.println(Integer.toBinaryString(~a)); // ...11110101 (NOT)
// Permission flags example
int READ = 0b001;
int WRITE = 0b010;
int EXEC = 0b100;
int perms = READ | WRITE; // user has read+write
System.out.println((perms & EXEC) != 0); // false — no exec数値リテラル内のアンダースコア
Java 7以降では、読みやすさを向上させるために数値リテラル内でアンダースコアを使用できます。アンダースコアはコンパイラーによって無視されます。
int million = 1_000_000;
long creditCard = 4_111_1111_1111_1111L;
double pi = 3.141_592_653_589_793;
int hex = 0xFF_EC_D1_2E;
int binary = 0b0001_0101_0110;
System.out.println(million); // 1000000
System.out.println(creditCard); // 4111111111111111任意精度のBigInteger
値がlongの範囲を超える場合は、BigIntegerを使用します。オーバーフローは発生しませんが、プリミティブ型より低速です。暗号鍵、階乗、天文学的な大きさの数値などに使用します。
import java.math.BigInteger;
BigInteger factorial100 = BigInteger.ONE;
for (int i = 2; i <= 100; i++) {
factorial100 = factorial100.multiply(BigInteger.valueOf(i));
}
System.out.println(factorial100.toString().length() + " digits"); // 158 digits
BigInteger a = new BigInteger("999999999999999999999999999999");
BigInteger b = new BigInteger("1");
System.out.println(a.add(b)); // 1000000000000000000000000000000実践:オーバーフローに対応したカウンター
Math.addExactを使用し、オーバーフローが発生した場合はLong.MAX_VALUEにフォールバックする、安全にオーバーフローを処理するカウンターの実装パターンです。
class SafeCounter {
private long count = 0;
public void increment() {
try {
count = Math.addExact(count, 1L);
} catch (ArithmeticException e) {
count = Long.MAX_VALUE; // cap at max
}
}
public long get() { return count; }
}
SafeCounter sc = new SafeCounter();
sc.increment();
sc.increment();
System.out.println(sc.get()); // 2クイックチェック
次の式の値はいくつになりますか。
long result = 1_000_000 * 1_000_000; System.out.println(result);
まとめ:整数演算とオーバーフロー
重要なポイント:
- 整数オーバーフローは暗黙にラップアラウンドし、デフォルトでは例外が発生しません
Math.addExact/multiplyExact/subtractExactを使用してオーバーフローを検出します- 整数除算はゼロ方向に切り捨てられ、
%の符号は被除数に従います - 中間結果が
intの範囲を超える可能性がある場合は、longリテラル(Lサフィックス)を使用します BigIntegerを使用すると、オーバーフローなしで任意の大きさの値を扱えます- ビットシフト演算子は、2のべき乗による乗算や除算の高速な代替手段です
よくある質問
「整数演算とオーバーフロー」レッスンは無料ですか?
はい。「整数演算とオーバーフロー」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「整数演算とオーバーフロー」で何を学びますか?
整数の除算、剰余、オーバーフローの動作と、その検出方法を理解します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「整数演算とオーバーフロー」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。