2.

Java 算術演算子完全ガイド

編集
この記事の要点
  • Java の算術演算子は + - * / % の 5 種 (累乗 ** は無い → Math.pow)
  • 整数除算と浮動小数除算の違い: 5 / 2 = 2 (int)、5.0 / 2 = 2.5 (double)
  • int オーバーフロー: Integer.MAX_VALUE + 1 = Integer.MIN_VALUE (環らない → 静かに壊れる)
  • オーバーフロー検知は Math.addExact / multiplyExact
  • 金額計算は BigDecimal 必須 (0.1 + 0.2 != 0.3 問題)

基本の算術演算子

int a = 10, b = 3;

System.out.println(a + b);   // 13
System.out.println(a - b);   // 7
System.out.println(a * b);   // 30
System.out.println(a / b);   // 3  ← 整数除算
System.out.println(a % b);   // 1  ← 剰余

// 浮動小数除算
double c = 10.0, d = 3.0;
System.out.println(c / d);   // 3.3333333333333335

// 累乗は Math.pow
System.out.println(Math.pow(2, 10));   // 1024.0 (double)

整数除算 vs 浮動小数除算

System.out.println(5 / 2);         // 2     (int / int)
System.out.println(5.0 / 2);       // 2.5   (double / int → double)
System.out.println(5 / 2.0);       // 2.5
System.out.println((double) 5 / 2); // 2.5

// 平均値計算でハマる例
int total = 100, count = 3;
double avg = total / count;        // 33.0 (整数除算してから double 化)
double avgOK = (double) total / count;   // 33.333...

オーバーフロー

int max = Integer.MAX_VALUE;   //  2147483647
System.out.println(max + 1);   // -2147483648 (静かにラップ)

// long でも限界がある
long lmax = Long.MAX_VALUE;
System.out.println(lmax + 1);  // Long.MIN_VALUE

// 検知したいなら Math.addExact (Java 8+)
try {
    int r = Math.addExact(Integer.MAX_VALUE, 1);
} catch (ArithmeticException e) {
    System.out.println("overflow!");
}

Math.multiplyExact(100000, 100000);   // ArithmeticException
Math.subtractExact(Integer.MIN_VALUE, 1);
Math.negateExact(Integer.MIN_VALUE);
Math.incrementExact(Integer.MAX_VALUE);
Math.toIntExact(3_000_000_000L);   // long → int 範囲外で例外

float と double と BigDecimal

// 二進浮動小数の罠
double x = 0.1 + 0.2;
System.out.println(x);             // 0.30000000000000004
System.out.println(x == 0.3);      // false ! ★

// 金額計算は必ず BigDecimal
import java.math.BigDecimal;

BigDecimal price = new BigDecimal("1000.50");
BigDecimal tax   = new BigDecimal("0.10");
BigDecimal total = price.multiply(BigDecimal.ONE.add(tax));
System.out.println(total);   // 1100.5500

// ★ コンストラクタは String を使う
new BigDecimal(0.1);        // 0.1000000000000000055511...
new BigDecimal("0.1");      // 0.1 (期待通り)

// 除算は scale 指定必須
BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
a.divide(b, 2, RoundingMode.HALF_UP);   // 3.33
// a.divide(b)  ← 割り切れない → ArithmeticException

modulo (%) の符号

// 被除数の符号に従う (Java / C / PHP)
System.out.println( 7 %  3);   //  1
System.out.println(-7 %  3);   // -1
System.out.println( 7 % -3);   //  1
System.out.println(-7 % -3);   // -1

// Python は除数の符号 (-7 % 3 = 2)
// → 正の剰余が欲しいなら Math.floorMod (Java 8+)
System.out.println(Math.floorMod(-7,  3));   //  2
System.out.println(Math.floorMod( 7, -3));   // -2

// 用途: 巡回バッファのインデックス
int next = Math.floorMod(idx - 1, size);   // 負でも正の範囲に

インクリメント / デクリメント

int i = 5;

// 後置 (式の値を返してから増減)
int a = i++;   // a = 5, i = 6

// 前置 (増減してから式の値を返す)
int b = ++i;   // b = 7, i = 7

// 同一式内で同じ変数を ++ するのは Undefined Behavior に近い
int x = 1;
int y = x++ + ++x;   // 1 + 3 = 4 (実装依存に見えるが Java では定義済)

型変換 (Widening / Narrowing)

// 暗黙の拡大変換 (Widening): OK
int    i = 100;
long   l = i;          // OK
double d = l;          // OK

// 暗黙の縮小変換 (Narrowing): NG
double pi = 3.14;
int p = pi;            // ★ コンパイルエラー
int p = (int) pi;      // 3 (キャストで OK, 小数切り捨て)

// 整数リテラルの暗黙変換
long bigL = 3_000_000_000L;       // L サフィックス必須
long oops = 3_000_000_000;        // ★ int リテラル → コンパイルエラー

// long 演算でも int リテラルに注意
long ms = 60 * 60 * 24 * 1000;    // int オーバーフロー (86400000 はギリ OK)
long ms2 = 60L * 60 * 24 * 1000 * 365;  // 一発目を long にする

PHP / Python との比較

項目JavaPHPPython
累乗Math.pow(a, b)a ** ba ** b
整数除算int / int = int常に float (intdiv で整数)// 整数 / / 浮動
オーバーフロー静かにラップ (int)自動で float 化無制限 (int は任意精度)
剰余の符号被除数被除数除数 (floor 動作)
0 除算 (int)ArithmeticExceptionDivisionByZeroErrorZeroDivisionError
0 除算 (float)NaN / InfinityINF / NANZeroDivisionError

0 除算とNaN / Infinity

// 整数の 0 除算 → 例外
try {
    int x = 10 / 0;
} catch (ArithmeticException e) {
    /* / by zero */
}

// 浮動小数の 0 除算 → 例外にならず Infinity / NaN
double a =  1.0 / 0;   //  Infinity
double b = -1.0 / 0;   // -Infinity
double c =  0.0 / 0;   //  NaN

// NaN は何と比べても false (自分自身とすら ==)
System.out.println(c == c);             // false !
System.out.println(Double.isNaN(c));    // true (正しい判定)
System.out.println(Double.isInfinite(a)); // true

FAQ

Q: int と long どっち使う?
A: ループカウンタや小さい数は int で十分。タイムスタンプ ms、サイズ、ID は long を推奨 (オーバーフロー対策)。

Q: 金額に double を使ってもいい?
A: ダメ。0.1 + 0.2 != 0.3 問題があり、税計算で 1 円ずれます。BigDecimal 必須。

Q: BigDecimal の比較は == で OK?
A: NG。compareTo() を使う。equals は scale も見るので 1.01.00 が別物扱い。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 単項演算子
  2. 算術演算子
  3. 代入演算子
  4. 比較演算子
  5. 論理演算子

最近更新/作成されたページ