CodeGym /コース /C# SELF /浮動小数点型の丸め

浮動小数点型の丸め

C# SELF
レベル 6 , レッスン 4
使用可能

1. はじめに

現実世界でお金を100兆分の1ユーロ単位で払うことなんてまずないし、部屋の長さを0.01ミリ単位で測ることもほぼないよね。プログラミングでも同じで、doublefloatを使うと、結果が「細かすぎる」ことがよくあるんだ。

こんなクラシックな問題があるよ:

double result = 10.0 / 3.0;
Console.WriteLine(result); // 3.3333333333333335
浮動小数点の割り算 — 「しっぽ」がついた結果

でも、もしこの数字を小数点以下2桁だけで表示したい(ユーザーを「ビビらせない」ために)なら?そのために丸めが必要なんだ。

2. C#の主な丸めメソッド

C#では浮動小数点数を丸める方法がいくつかあるよ。ここからが面白いところで、丸め方にもいろいろあるんだ!主なパターンを見て、違いを理解しよう。

1) Math.Round関数 — クラシックな丸め

一番よく使うのはMath.Roundメソッド。これは数字を一番近い整数(または指定した小数点以下の桁数)に丸めてくれるよ。


Math.Round(数値[, 桁数[, MidpointRounding]])
Math.Roundのシンタックス
  • 数値 — 丸めたい値。
  • 桁数 — 小数点以下何桁残すか(デフォルトは0、つまり整数まで)。
  • MidpointRounding — 0.5の時の丸め方(これは後で説明するね)。

例:

double x = 2.71828;

Console.WriteLine(Math.Round(x));         // 3
Console.WriteLine(Math.Round(x, 2));      // 2.72
Console.WriteLine(Math.Round(x, 3));      // 2.718

ビジュアライズ:

入力値 Math.Round(x) Math.Round(x, 2)
2.3 2 2.3
2.5 2 2.5
2.7 3 2.7
2.71828 3 2.72

戻り値の型:
この講義で出てくる関数は全部double型を返すよ。だから丸めた結果を代入するとき、エラーになることもあるんだ:

double result = 10.0 / 5.0;     // 結果は2.0
int x = Math.Round(x);          // エラー! double型をint型にそのまま代入できない

もしdouble型をint型の変数に入れたいなら、キャストを明示的に書こう:

double result = 10.0 / 5.0;     // 結果は2.0
int x = (int) Math.Round(x);    // これでOK!

2) 切り上げ・切り捨ての丸め

C#では「クラシック」な丸めだけじゃなくて、強制的に上か下に丸めることもできるよ。

小さい方に丸める(Math.Floor

Math.Floorメソッドは小数点以下を「切り捨て」(マイナス無限大方向)する。つまり、必ず下に丸める!

Console.WriteLine(Math.Floor(2.99));   // 2
Console.WriteLine(Math.Floor(-2.99));  // -3

大きい方に丸める(Math.Ceiling

Math.CeilingメソッドはFloorの逆で、必ず上に丸める(プラス無限大方向)。

Console.WriteLine(Math.Ceiling(2.01));   // 3
Console.WriteLine(Math.Ceiling(-2.01));  // -2

比較表:

関数 2.3 -2.3
Math.Round 2 -2
Math.Floor 2 -3
Math.Ceiling 3 -2

3) Truncate: 小数点以下を単純に切り捨て

Math.Truncateメソッドは「冷静な外科医」みたいなもの。小数点以下をただ消すだけで、数学的な丸めは気にしない。xがプラスならFloorと同じ、マイナスならCeilingと同じになるよ。

Console.WriteLine(Math.Truncate(2.99));   // 2
Console.WriteLine(Math.Truncate(-2.99));  // -2

3. Math.Roundの「0.5」の丸め方(MidpointRounding

例えば2.5があるとする。どっちに丸める?2と3のちょうど真ん中だよね。数学では2つの有名なやり方がある:

  • 大きい方に丸める(「切り上げ」)
  • 一番近い偶数に丸める(Banker's rounding)

C#のデフォルトは2番目の「一番近い偶数に丸める」(banker's rounding、または「偶数丸め」)。

Console.WriteLine(Math.Round(2.5)); // 2
Console.WriteLine(Math.Round(3.5)); // 4

なぜ?2つの同じ距離の整数があったら偶数が「勝つ」から。これは大量に丸めるとき、結果が偏らないようにするため。銀行で大金を扱うときに大事なんだ(だからbanker's roundingって呼ばれる)。

もし常に切り上げたいなら、モードを明示的に指定できるよ:

// 常に「ゼロから離れる」方向に丸める
Console.WriteLine(Math.Round(2.5, 0, MidpointRounding.AwayFromZero)); // 3
Console.WriteLine(Math.Round(-2.5, 0, MidpointRounding.AwayFromZero)); // -3

MidpointRoundingモードの表:

入力値 Round(デフォルト) AwayFromZero ToZero / ToEven
2.5 2 3 2
3.5 4 4 4
-2.5 -2 -3 -2

4. 必要な小数点以下の桁数に丸める:「8」や「3」に注意!

整数じゃなくて、小数点以下2桁とかに丸めたいときもあるよね(お金やパーセントの表示とか)。

double price = 149.9999;
double roundedPrice = Math.Round(price, 2);
Console.WriteLine(roundedPrice); // 150

もし単に余分な桁を「切り捨て」たいだけで、丸めたくない場合は?例えば123.4567123.45にしたいとき。

こんな小技が使えるよ:

double num = 123.4567;
double result = Math.Floor(num * 100) / 100;
Console.WriteLine(result); // 123.45

小数点を「ずらして」、小数点以下を切り捨てて、また戻すって感じ。

5. 出力フォーマットと丸めの違い

重要!

出力フォーマット({x:F2})は、「本当の」丸めじゃなくて、画面上の「見た目」だけだよ。メモリ上では長い「しっぽ」のdoubleのまま。値自体を丸めて保存したいなら、Math.Roundを使おう。

こんな感じで違いが大事になることもあるよ:

double value = 2.555;
Console.WriteLine($"{value:F2}"); // 2.56
Console.WriteLine(Math.Round(value, 2)); // 2.56

double stored = Math.Round(value, 2);
Console.WriteLine(stored); // 2.56

// でも丸めずにフォーマットだけだと...
Console.WriteLine($"{value:F2}"); // 2.56、でもメモリ上は2.555

6. よくあるミスや注意点

  • doubleで正確な金額計算に丸めを使わないで! お金には.NETのdecimal型を使おう。これは浮動小数点の「いたずら」がない(詳しくは別の講義で!)。
  • 「しつこい8」問題:バイナリで保存するから、見た目通りに丸められないこともある。例えば0.1 + 0.2は0.3にならないことも。
  • Math.FloorMath.Roundを混同しないで! 前者は常に下、後者は数学的な丸め。
  • 誤差の蓄積に注意:計算途中で何度も丸めると、最終結果がズレることがある。普通は最後だけ丸めるのがベター。

7. まとめ表:各メソッドの結果

入力値 Math.Round(x) Math.Floor(x) Math.Ceiling(x) Math.Truncate(x)
3.2 3 3 4 3
3.5 4 3 4 3
-3.2 -3 -4 -3 -3
-3.5 -4 -4 -3 -3

8. おもしろ豆知識

  • 昔、NASAは座標の丸めが甘くて、メートル法とヤード・ポンド法の違いもあって宇宙機を失ったことがあるんだ。教訓:丸めは慎重に!
  • 銀行はずっと前から「banker's rounding」を使ってる。昔は全部切り上げで、客が毎回ちょっとずつ損してた。
  • C#にはMath.Signメソッドもあって、数字の符号を返してくれる。丸め前にどっちに「切る」か決めたいとき便利だよ。
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION