Javaで絶対値を求める方法|Math.absの使い方とMIN_VALUEの落とし穴まで解説

目次

1. この記事で分かること

Javaで「絶対値(ぜったいち)」を求めたい場合、結論はシンプルです。

  • 基本は Math.abs() を使えばOK
  • ただし Integer.MIN_VALUE / Long.MIN_VALUE だけは例外(絶対値にしても負のままになる可能性がある)
  • お金・小数の厳密計算を扱うなら BigDecimal#abs() が安全

このセクションでは、まず「最短で正解にたどり着く」ために、すぐ使えるコードと注意点だけ先に押さえます。

1.1 迷ったらこれ:Math.abs() が基本

整数でも小数でも、一般的な絶対値は Math.abs() が最も分かりやすく、読み手にも意図が伝わります。

int x = -10;
int a = Math.abs(x);
System.out.println(a); // 10

Math.abs() は「符号を外した値(0からの距離)」を返します。
つまり、-10 でも 10 でも、結果は 10 になります。

1.2 ただし重要:MIN_VALUEは“落とし穴”がある

ここが「java 絶対値」でつまずく代表例です。

Javaの intlong には取り扱える範囲があり、最小値(MIN_VALUE)は特別です。

  • Integer.MIN_VALUE(intの最小値)
  • Long.MIN_VALUE(longの最小値)

これらに対して Math.abs() を使うと、絶対値にしたはずなのに負のままになることがあります。

int min = Integer.MIN_VALUE;
int absMin = Math.abs(min);
System.out.println(absMin); // 期待は正の値…だが負のままになる可能性

なぜこんなことが起きるのか、どう回避するのかは **後のセクション(落とし穴対策)**で丁寧に解説します。
ここでは「absすれば必ず正になる、と思い込むのは危険」という点だけ先に覚えておけばOKです。

1.3 金額や正確な小数なら:BigDecimal#abs() を使う

doublefloat は便利ですが、小数の誤差が避けられません。
金額計算(請求、手数料、残高など)や、厳密さが求められる場面では BigDecimal が定番です。

BigDecimal の絶対値は Math.abs() ではなく、オブジェクトのメソッド abs() を使います。

import java.math.BigDecimal;

BigDecimal price = new BigDecimal("-1234.56");
BigDecimal absPrice = price.abs();
System.out.println(absPrice); // 1234.56

「金額のマイナスを正の値にそろえたい」「差額を必ず正で表示したい」など、実務でも頻出です。

1.4 このあと何を順番に解説するか

この記事は、初心者でも迷わないように **“使える順”**で進めます。

  • まず:絶対値の意味(なぜそうなるか)
  • 次に:Math.abs() の基本(型ごと)
  • そして:MIN_VALUEの落とし穴(原因と安全な回避策)
  • 最後に:BigDecimal や実務パターン、FAQで「よくある疑問」を回収

2. 絶対値とは(0からの距離を返す)

このセクションでは、「そもそも絶対値とは何か」を整理します。
ここを押さえておくと、Math.abs() の挙動や、後半で解説する MIN_VALUEの問題 が自然に理解できます。

2.1 絶対値の基本的な意味

絶対値とは、数直線上で「0からどれだけ離れているか」を表す値です。

  • 正の数:そのままの値
  • 負の数:符号を外した値

数式で書くと次のようなイメージです。

元の値絶対値
1010
-1010
00

重要なのは、符号(プラス・マイナス)には意味がなくなるという点です。
残るのは「大きさ」だけです。

2.2 なぜプログラムで絶対値が必要になるのか

Javaに限らず、プログラミングでは絶対値を使う場面が非常に多くあります。

代表的な例を挙げると:

  • 差の大きさを知りたい
    • 例:A - BB - A の結果を同じ扱いにしたい
  • 距離や誤差を評価したい
    • 例:許容誤差以内かどうか
  • 負の入力を正規化したい
    • 例:設定値や金額を必ず正の値で扱う
  • スコアや重み付け
    • マイナス方向の評価も大きさだけを見る

このような場面では、「どちらが大きいか」よりも
どれだけ離れているか が重要になります。

2.3 Javaにおける絶対値の考え方

Javaでは、絶対値を 数値演算の一部として扱います。
そのため、専用の構文ではなく、標準ライブラリのメソッドとして提供されています。

  • プリミティブ型(int, long, double など)
    • Math.abs()
  • 高精度数値(BigDecimal
    • BigDecimal#abs()

ここで注意したいのは、型によって振る舞いが異なるという点です。

  • intlong表現できる範囲が固定
  • doublefloat誤差や特殊値(NaN, Infinity)が存在
  • BigDecimalオブジェクトとして計算される

この違いが、後ほど説明する 「絶対値なのに負になる」「思った値にならない」 といった疑問につながります。

2.4 「符号を消すだけ」と考えると危険な理由

初心者がよく持つイメージに、

絶対値 = マイナスをプラスにするだけ

というものがあります。
考え方としては近いのですが、プログラム上では完全には正しくありません。

理由は次の通りです。

  • 数値には 最大値・最小値の制限がある
  • 内部では 2進数表現で管理されている
  • その結果、「正の値にできない数」が存在する

この話が、次のセクションで扱う Math.abs() の詳細
さらにその次の MIN_VALUEの落とし穴につながっていきます。

3. Javaで絶対値を求める基本:Math.abs()

このセクションでは、Javaで絶対値を求める際に最もよく使われる
Math.abs() メソッドについて、基本から順に解説します。

3.1 Math.abs() の基本的な使い方

Math.abs() は、引数に渡した数値の絶対値を返すシンプルなメソッドです。
java.lang.Math クラスに定義されているため、importは不要です。

int value = -15;
int result = Math.abs(value);
System.out.println(result); // 15

コードを読む側から見ても、

  • Math.abs(x) → 「xの絶対値」

と直感的に理解できます。
そのため、条件演算子などで自作するよりも、可読性の面で優れています

3.2 対応している数値型

Math.abs() は、複数の数値型に対してオーバーロードされています。
代表的な対応型は次の通りです。

引数の型戻り値の型
intint
longlong
floatfloat
doubledouble

重要なのは、戻り値の型は引数と同じという点です。

long x = -100L;
long y = Math.abs(x); // 戻り値も long

int を渡したら long で返ってくる」といった自動拡張は行われません。
この仕様が、後ほど解説する オーバーフロー問題に関係してきます。

3.3 正の数・負の数・0の挙動

Math.abs() の挙動は、基本的に次のルールで決まります。

  • 正の数 → そのまま返す
  • 負の数 → 符号を反転して返す
  • 0 → 0を返す
System.out.println(Math.abs(10));   // 10
System.out.println(Math.abs(-10));  // 10
System.out.println(Math.abs(0));    // 0

この範囲であれば、直感通りの結果になります。
多くのサンプルコードや解説記事は、ここまでで終わっています。

3.4 doublefloat を使う場合の基本的な注意点

小数型でも Math.abs() は同じように使えます。

double d = -3.14;
double absD = Math.abs(d);
System.out.println(absD); // 3.14

ただし、doublefloat には次の特徴があります。

  • 誤差が存在する
  • 特殊な値(NaN、Infinity)が存在する

例えば:

double nan = Double.NaN;
System.out.println(Math.abs(nan)); // NaN

絶対値を取っても、NaNはNaNのままです。
この挙動自体は仕様通りですが、比較処理や条件分岐では注意が必要です。

3.5 なぜ Math.abs() を使うべきなのか

同じ処理は、次のようにも書けます。

int x = -10;
int y = x < 0 ? -x : x;

しかし、実務では Math.abs() を使う方が安全で読みやすいです。

理由は次の通りです。

  • 意図が一目で分かる
  • 型ごとの実装を意識しなくてよい
  • Java標準APIとして信頼できる

ただし、完全に安全というわけではありません
次は、Math.abs() を使っても期待通りにならない「例外的なケース」を詳しく解説します。

4. 【重要】Math.absが負のままになるケース(MIN_VALUE)

このセクションは、「java 絶対値」で検索する人が最もつまずきやすいポイントです。
結論から言うと、Math.abs() はすべての数を正にできるわけではありません。

4.1 問題が起きる数値:Integer.MIN_VALUELong.MIN_VALUE

Javaの整数型には、それぞれ表現できる範囲があります。

  • int-2,147,483,6482,147,483,647
  • long-9,223,372,036,854,775,8089,223,372,036,854,775,807

ここで注目すべきなのが、最小値(MIN_VALUE)だけが非対称になっている点です。

System.out.println(Integer.MAX_VALUE); //  2147483647
System.out.println(Integer.MIN_VALUE); // -2147483648

最小値の絶対値は、本来なら
2147483648 になってほしいところですが、int型では表現できません

4.2 実際に起きる現象(再現コード)

実際に Math.abs() を使うと、次のような結果になります。

int min = Integer.MIN_VALUE;
int absMin = Math.abs(min);

System.out.println(absMin); // -2147483648

絶対値を取ったはずなのに、負のままです。
これはバグではなく、Javaの仕様通りの動作です。

同じことは long でも起きます。

long min = Long.MIN_VALUE;
long absMin = Math.abs(min);

System.out.println(absMin); // 負のまま

4.3 なぜこんなことが起きるのか(仕組み)

原因は、Javaが整数を **2進数(補数表現)**で管理していることにあります。

ポイントだけ整理すると:

  • int / long は固定ビット数で表現される
  • 正の最大値より、負の最小値の方が 1つだけ絶対値が大きい
  • そのため、MIN_VALUEを正に変換する領域が存在しない

結果として、

  • -MIN_VALUE を計算しようとすると
  • オーバーフローが発生し
  • 元の値に戻ってしまう

という現象が起きます。

4.4 よくある誤解:型を大きくすれば解決する?

次のように考える人は多いです。

intでダメなら、longに代入すればいいのでは?

しかし、次のコードを見てください。

int min = Integer.MIN_VALUE;
long value = Math.abs(min);

これは 意味がありません

理由は、Math.abs(min) の時点で int の範囲で計算が終わっているからです。
オーバーフローはすでに発生しています。

4.5 安全な回避策①:事前にMIN_VALUEをチェックする

最も確実で分かりやすい方法は、条件分岐で防ぐことです。

int x = Integer.MIN_VALUE;

if (x == Integer.MIN_VALUE) {
    // 例外処理や別ロジック
} else {
    int abs = Math.abs(x);
}

「MIN_VALUEは特殊」という前提を仕様として受け入れるのが、安全な設計です。

4.6 安全な回避策②:扱う型・設計を見直す

もし次のようなケースなら、設計自体を見直す価値があります。

  • 絶対値が必ず正であることを前提にしている
  • 差分・距離・件数など、負の概念が不要

その場合:

  • 最初から longBigDecimal を使う
  • MIN_VALUEが来ない設計にする
  • 例外として処理する

といった方針の方が、後から事故が起きにくいです。

4.7 この問題を知っているだけで差がつく

実務では、

  • テストで見逃される
  • レアケースとして本番でだけ発生する
  • 原因が分からず調査に時間がかかる

といったトラブルにつながりやすいポイントです。

「Math.absは万能ではない」
この一点を知っているだけで、Javaコードの安全性は大きく上がります。

5. 小数の絶対値:float / double の注意点(NaN・Infinity・-0.0)

ここまでで intlong の絶対値と、その落とし穴を見てきました。
次は float / double といった小数型で絶対値を扱う際の注意点を整理します。

小数型は便利ですが、整数とは性質がまったく異なるため、挙動を知らないと思わぬ不具合につながります。

5.1 Math.abs() は小数でも同じように使える

基本的な使い方は、整数と変わりません。

double x = -12.5;
double abs = Math.abs(x);
System.out.println(abs); // 12.5

この範囲では、直感通りに動作します。
しかし、小数型には 「整数にはない特殊な値」 が存在します。

5.2 NaN(Not a Number)の場合

NaN は「数値として定義できない状態」を表す特別な値です。

double nan = Double.NaN;
System.out.println(Math.abs(nan)); // NaN

絶対値を取っても、NaNはNaNのままです。

ここで注意したいのは、NaNの性質です。

  • NaN == NaNfalse
  • 比較演算がすべて false になる

つまり、次のようなコードは期待通りに動きません。

if (Math.abs(value) < 1.0) {
    // この条件はNaNの場合、必ずfalse
}

誤差判定や閾値チェックを行う場合は、
NaNが混ざる可能性があるかを事前に考慮する必要があります。

5.3 Infinity(無限大)の場合

doublefloat では、無限大も表現できます。

double inf = Double.POSITIVE_INFINITY;
System.out.println(Math.abs(inf)); // Infinity
  • 正の無限大 → 正の無限大
  • 負の無限大 → 正の無限大

数値としては破綻しませんが、
計算結果が無限になるロジック自体が妥当かは要確認です。

5.4 -0.0 という存在に注意

小数型には、-0.0 という値が存在します。

double z = -0.0;
double absZ = Math.abs(z);
System.out.println(absZ); // 0.0

見た目上は問題ありませんが、

  • -0.00.0 はビット表現が異なる
  • 除算や符号判定で影響が出ることがある

という特徴があります。

System.out.println(1.0 / -0.0); // -Infinity
System.out.println(1.0 /  0.0); //  Infinity

絶対値を取ることで -0.00.0 になりますが、
その前後で何をしているかによって挙動が変わる可能性があります。

5.5 小数の絶対値で気をつけるべきポイントまとめ

float / double で絶対値を扱う際は、次を意識しましょう。

  • Math.abs() 自体は正しく動く
  • ただし NaN は NaN のまま
  • Infinity はそのまま返る
  • -0.0 が存在する
  • 誤差があるため、金額計算には不向き

これらを踏まえると、

  • 科学計算・近似計算 → double
  • 金額・精密計算 → BigDecimal

という使い分けが自然です。

6. 金額・高精度計算の絶対値:BigDecimal#abs()

ここまでで、int / long / double における絶対値の扱いと注意点を見てきました。
このセクションでは、金額計算や誤差を許容できない場面で必須となる
BigDecimal の絶対値について解説します。

6.1 なぜ BigDecimal が必要なのか

doublefloat は内部的に2進数で計算されるため、小数誤差が避けられません

double a = 0.1 + 0.2;
System.out.println(a); // 0.30000000000000004

このような誤差は、次のような場面では致命的です。

  • 金額(請求額、残高、手数料)
  • 税計算
  • 割合・利率の正確な計算
  • 会計・決済ロジック

そこで使われるのが BigDecimal です。

6.2 BigDecimal の絶対値は Math.abs() ではない

ここは初心者がよく間違えるポイントです。

BigDecimal x = new BigDecimal("-100");
// Math.abs(x); ← これはコンパイルエラー

BigDecimal はプリミティブ型ではなくオブジェクトなので、
絶対値は インスタンスメソッドとして提供されています。

6.3 基本的な使い方:BigDecimal#abs()

import java.math.BigDecimal;

BigDecimal amount = new BigDecimal("-2500.75");
BigDecimal absAmount = amount.abs();

System.out.println(absAmount); // 2500.75

このように、abs() を呼び出すだけで絶対値を取得できます。

  • 元のオブジェクトは変更されない
  • 新しい BigDecimal が返る(イミュータブル)

という点も重要です。

6.4 丸めや精度を意識する場合

BigDecimal では、計算の途中で精度や丸め方法を指定することができます。

絶対値でも、MathContext を指定したバージョンが用意されています。

import java.math.BigDecimal;
import java.math.MathContext;

BigDecimal value = new BigDecimal("-1234.56789");
BigDecimal abs = value.abs(new MathContext(6));

System.out.println(abs); // 精度6桁での絶対値
  • 金額は小数第2位まで
  • 内部計算は一定の精度で

といった業務要件がある場合に役立ちます。

6.5 実務でよくある利用例

差額を必ず正で表示したい

BigDecimal before = new BigDecimal("1000");
BigDecimal after  = new BigDecimal("750");

BigDecimal diff = after.subtract(before).abs();
System.out.println(diff); // 250

マイナス入力を正規化したい

BigDecimal input = new BigDecimal("-500");
BigDecimal normalized = input.abs();

ユーザー入力や外部データを受け取る場合、
一度絶対値にしてから処理する設計はよく使われます。

6.6 BigDecimal を使うべきかどうかの判断基準

次のような場合は、迷わず BigDecimal を選びましょう。

  • 金額を扱う
  • 誤差が許されない
  • 絶対値が必ず正であることを保証したい
  • MIN_VALUEのような境界問題を避けたい

逆に、

  • 単純な差分
  • パフォーマンス重視
  • 厳密さより速度優先

であれば、int / long / double の方が適しています。

7. 自作する場合(条件演算子での絶対値)と使い分け

Math.abs() があることを知っていても、
「自分で書いた方が分かりやすいのでは?」と感じる場面はあります。
このセクションでは、条件演算子による自作パターンと、その注意点を整理します。

7.1 条件演算子で絶対値を書く方法

最も単純な書き方は、次のようなものです。

int x = -20;
int abs = x < 0 ? -x : x;
System.out.println(abs); // 20

ロジック自体は直感的で、

  • マイナスなら符号を反転
  • そうでなければそのまま

という処理になっています。

7.2 自作でもMIN_VALUE問題は避けられない

一見問題なさそうですが、MIN_VALUEでは同じ落とし穴があります。

int x = Integer.MIN_VALUE;
int abs = x < 0 ? -x : x;

System.out.println(abs); // 負のまま

-x の時点でオーバーフローが発生し、
結果は Math.abs() を使った場合と同じになります。

つまり、

  • 自作すれば安全になるわけではない
  • 問題は「書き方」ではなく「数値の仕様」

という点が重要です。

7.3 可読性と意図の明確さの違い

次の2つのコードを比べてみましょう。

int a = x < 0 ? -x : x;
int a = Math.abs(x);

後者の方が、

  • 「絶対値を取りたい」という意図が明確
  • バグの余地が少ない
  • チーム開発でも読みやすい

というメリットがあります。

7.4 パフォーマンス面の違いはほぼない

「条件演算子の方が速いのでは?」と考える人もいますが、
現代のJavaでは 差はほぼ無視できるレベルです。

  • JITコンパイラが最適化する
  • 可読性・安全性の方が重要

そのため、パフォーマンスを理由に自作する必要はありません

7.5 使い分けの指針まとめ

絶対値の書き方で迷ったら、次を基準にするとよいでしょう。

  • 基本は Math.abs()
  • 意図を明確にしたい → Math.abs()
  • BigDecimal → BigDecimal#abs()
  • MIN_VALUEが来る可能性がある → 事前チェック or 設計見直し

条件演算子は、

  • 教育目的
  • 簡単なサンプル

といった限定的な用途に留めるのが無難です。

8. 実務でよくあるパターン集(コピペOKの小レシピ)

ここでは、実務で頻繁に登場する「絶対値の使いどころ」をまとめます。
そのまま使える形のコードを中心に紹介するので、用途に合わせて活用してください。

8.1 2つの値の差を正の値で取得する

「どちらが大きいか」ではなく、差の大きさだけが必要なケースです。

int a = 120;
int b = 95;

int diff = Math.abs(a - b);
System.out.println(diff); // 25
  • スコア差
  • 件数差
  • カウントの比較

などでよく使われます。

8.2 誤差が許容範囲内かを判定する

数値計算では、「完全一致」ではなく
誤差が一定以内かを判定することが多くあります。

double expected = 100.0;
double actual   = 99.9998;

double tolerance = 0.01;

if (Math.abs(expected - actual) <= tolerance) {
    // 許容範囲内
}

テストコードや計測処理で特に有効です。

8.3 絶対値を使ったソート(大きさ順)

数値を 絶対値の小さい順・大きい順で並べたい場合もあります。

List<Integer> list = Arrays.asList(-3, 10, -1, 5);

list.sort(Comparator.comparingInt(Math::abs));
System.out.println(list); // [-1, -3, 5, 10]
  • 距離が近い順
  • 影響度が小さい順

といった評価基準に使えます。

8.4 入力値を正規化する(負数を許可しない)

ユーザー入力や外部データでは、
意図せずマイナス値が混ざることがあります。

int input = -50;
int normalized = Math.abs(input);
  • 数量
  • ページ数
  • サイズ指定

など、「負の概念が不要」な値では有効です。
ただし、MIN_VALUEが来ない前提で使うことが重要です。

8.5 BigDecimalでの差額計算(実務頻出)

金額計算では BigDecimalabs() の組み合わせが定番です。

BigDecimal before = new BigDecimal("1500");
BigDecimal after  = new BigDecimal("1800");

BigDecimal diff = after.subtract(before).abs();
System.out.println(diff); // 300

請求額の増減、残高差分などでよく使われます。

8.6 境界チェックでの利用例

絶対値は、中心からの距離を測る際にも使えます。

int center = 100;
int value  = 92;

if (Math.abs(value - center) <= 10) {
    // 許容範囲内
}
  • レンジ判定
  • しきい値チェック
  • センサー値の許容判定

など、幅広い用途があります。

8.7 実務で使う際の注意点まとめ

実務で絶対値を使うときは、次を意識しましょう。

  • MIN_VALUEの可能性はあるか
  • 小数か、整数か、金額か
  • 誤差を許容できるか

「とりあえず Math.abs()」ではなく、
前提条件を考えたうえで使うことが、安定したコードにつながります。

9. まとめ

この記事では、「java 絶対値」というテーマについて、基礎から実務まで順を追って解説してきました。
最後に、重要なポイントを整理します。

9.1 基本は Math.abs() を使う

Javaで絶対値を求める場合、第一選択は Math.abs() です。

  • int / long / float / double に対応
  • 記述が簡潔で、意図が分かりやすい
  • 標準APIなので信頼性が高い

迷ったら、まず Math.abs() を使えば問題ありません。

9.2 MIN_VALUEだけは例外として扱う

Integer.MIN_VALUELong.MIN_VALUE は、絶対値にしても正になりません

  • これはバグではなくJavaの仕様
  • 自作ロジックでも回避できない
  • 必要なら事前チェックや設計見直しが必須

「Math.absは万能ではない」
この理解があるかどうかで、コードの安全性は大きく変わります。

9.3 小数は用途に応じて型を選ぶ

  • 近似計算・誤差を許容 → double / float
  • NaN / Infinity / -0.0 の存在に注意
  • 金額・精密計算 → BigDecimal

小数の絶対値は「取れるか」よりも、
「その型を使ってよいか」が重要です。

9.4 金額や厳密さが必要なら BigDecimal#abs()

BigDecimal は、

  • 誤差が出ない
  • MIN_VALUEのような境界問題がない
  • 実務で安心して使える

という点で、金額計算ではほぼ必須です。

9.5 絶対値は「前提条件」を考えて使う

絶対値は便利ですが、次を意識することが重要です。

  • 入力にどんな値が来るか
  • 境界値は含まれるか
  • 正であることが本当に正しいか

この一歩を踏むだけで、
バグの少ない、読みやすいJavaコードになります。

10. FAQ:Javaの絶対値でよくある質問

最後に、「java 絶対値」で検索した人が疑問に思いやすい点をFAQ形式でまとめます。

10.1 Math.abs(-10) は何を返しますか?

10 を返します。
Math.abs() は「0からの距離」を返すため、符号は無視されます。

10.2 Math.abs(Integer.MIN_VALUE) が負のままなのはバグですか?

いいえ、Javaの仕様です
int の最小値は、絶対値を正の int として表現できないため、オーバーフローが発生します。

10.3 intlong に代入すれば安全になりますか?

いいえ。
Math.abs(int) の時点で計算は int 型で行われるため、
代入先を long にしても意味はありません

10.4 BigDecimal の絶対値はどうやって取りますか?

Math.abs() ではなく、BigDecimal#abs() を使います。

BigDecimal x = new BigDecimal("-100");
BigDecimal abs = x.abs();

10.5 double の絶対値で注意すべき点はありますか?

あります。

  • NaN は絶対値を取っても NaN のまま
  • Infinity はそのまま返る
  • -0.0 が存在する
  • 誤差がある

金額計算には向きません。

10.6 絶対値を使った誤差比較の正しい書き方は?

次のように、差の絶対値と許容誤差を比較します。

if (Math.abs(a - b) <= tolerance) {
    // 許容範囲内
}