C#のdouble型とは?float・decimalとの違い、誤差の原因、正しい使い分けを初心者向けに解説
はじめに
C#で小数を扱うときによく使う型がdouble型です。「C# double」と検索している人の多くは、doubleが何なのか、floatやdecimalと何が違うのか、なぜ0.1 + 0.2の結果が思った通りにならないのかを知りたいのではないでしょうか。
double型は便利で使用頻度の高い数値型ですが、何でもdoubleで計算すればよいわけではありません。特に、金額計算や税金計算のように誤差が許されにくい処理では、doubleではなくdecimalを使うのが一般的です。
この記事では、C#のdouble型について、初心者にもわかりやすく基本から解説します。宣言方法、計算方法、float・decimalとの違い、誤差が発生する理由、正しい比較方法、実践的なコード例まで順番に見ていきましょう。
1. C#のdouble型とは?初心者向けに基本を解説
1-1. double型は小数を扱うための数値型
C#のdouble型は、小数を扱うための数値型です。たとえば、身長、体重、平均点、距離、座標、角度、温度など、整数だけでは表せない値を扱うときに使います。
C#double height = 170.5;
double weight = 62.3;
double temperature = 36.6;
int型は整数を扱う型なので、1、100、-5のような値に向いています。一方、double型は3.14や0.5のような小数を扱えます。
C#int count = 10;
double rate = 0.08;
C#では、小数リテラルをそのまま書くと基本的にdouble型として扱われます。たとえば3.14はdouble型の値です。MicrosoftのC#リファレンスでも、サフィックスなし、またはd/D付きの実数リテラルはdoubleになると説明されています。
1-2. double型で扱える値の範囲と精度
double型は、64ビットの浮動小数点数です。floatより広い範囲と高い精度を持ち、C#で小数を扱うときの標準的な型としてよく使われます。
double型の主な特徴は次の通りです。
| 型 | サイズ | 精度の目安 | 主な用途 |
|---|---|---|---|
float | 4バイト | 約6〜9桁 | メモリ節約、ゲーム、画像処理など |
double | 8バイト | 約15〜17桁 | 一般的な小数計算、科学技術計算、座標計算など |
decimal | 16バイト | 約28〜29桁 | 金額、税金、会計処理など |
doubleはかなり大きな値やかなり小さな値を扱えますが、「すべての小数を正確に表せる」という意味ではありません。doubleは2進数で小数を表現するため、0.1や0.2のような一見単純な10進小数でも、内部では正確に表せない場合があります。
1-3. double型の宣言・代入・計算の基本例
double型の変数は、次のように宣言します。
C#double price = 120.5;
double taxRate = 0.10;
double total = price + price * taxRate;
Console.WriteLine(total);
double型同士は、足し算、引き算、掛け算、割り算などの四則演算ができます。
C#double a = 10.5;
double b = 2.0;
Console.WriteLine(a + b); // 12.5
Console.WriteLine(a - b); // 8.5
Console.WriteLine(a * b); // 21
Console.WriteLine(a / b); // 5.25
int型とdouble型を一緒に計算すると、結果はdouble型になります。
C#int count = 3;
double price = 100.5;
double total = count * price;
Console.WriteLine(total); // 301.5
ただし、int / intの計算は整数同士の割り算になるため注意が必要です。
C#double result1 = 5 / 2;
double result2 = 5.0 / 2;
Console.WriteLine(result1); // 2
Console.WriteLine(result2); // 2.5
result1はdouble型に代入していますが、右辺の5 / 2が先に整数同士で計算されるため、結果は2になります。小数として計算したい場合は、どちらか一方をdoubleにします。
1-4. double型の既定値とnullを扱いたい場合
double型の既定値は0です。たとえば、クラスのフィールドとしてdoubleを宣言し、明示的に値を代入しない場合は0になります。
C#class Sample
{
public double Value;
}
Sample sample = new Sample();
Console.WriteLine(sample.Value); // 0
一方、double型は値型なので、通常はnullを代入できません。
C#double value = null; // エラー
nullを扱いたい場合は、 nullable 型であるdouble?を使います。
C#double? value = null;
if (value == null)
{
Console.WriteLine("値がありません");
}
double?は、「小数の値がある場合もあれば、値がない場合もある」という状態を表現したいときに便利です。たとえば、未入力の身長、未取得の測定値、未計算の結果などを扱う場面で使えます。
2. C#でdouble型を使う基本的な書き方
2-1. double変数の宣言方法
double型の変数は、次の形式で宣言します。
C#double 変数名 = 値;
具体例は次の通りです。
C#double score = 85.5;
double distance = 12.34;
double pi = 3.14159;
宣言だけして、あとから値を代入することもできます。
C#double result;
result = 10.5;
複数のdouble変数を使って計算することもできます。
C#double width = 5.5;
double height = 3.2;
double area = width * height;
Console.WriteLine(area);
初心者のうちは、変数名をxやaのように短くしすぎるより、height、weight、average、distanceのように意味がわかる名前にするのがおすすめです。
2-2. 小数リテラルとdouble型の関係
C#では、3.14や0.5のようにソースコードに直接書かれた小数を「小数リテラル」または「実数リテラル」と呼びます。
C#double value = 3.14;
この3.14は、サフィックスを付けなければdouble型として扱われます。
C#double d = 3.14; // double
float f = 3.14f; // float
decimal m = 3.14m; // decimal
float型に代入する場合はfまたはFを付けます。decimal型に代入する場合はmまたはMを付けます。C#では、サフィックスによって実数リテラルの型が決まります。
C#double d1 = 1.23;
double d2 = 1.23d;
double d3 = 1.23D;
float f1 = 1.23f;
decimal m1 = 1.23m;
2-3. double型の四則演算
double型では、基本的な四則演算ができます。
C#double a = 10.0;
double b = 3.0;
Console.WriteLine(a + b); // 足し算
Console.WriteLine(a - b); // 引き算
Console.WriteLine(a * b); // 掛け算
Console.WriteLine(a / b); // 割り算
出力結果は次のようになります。
13
7
30
3.3333333333333335
割り算では、結果が割り切れない場合、小数として表示されます。ただし、doubleは2進数で小数を近似する型なので、計算結果が人間の期待する10進表記と完全に一致しないことがあります。
余りを求める%演算子も使えます。
C#double remainder = 10.5 % 3.0;
Console.WriteLine(remainder); // 1.5
2-4. intなど整数型との計算
double型は、intなどの整数型と一緒に計算できます。
C#int count = 4;
double unitPrice = 99.8;
double total = count * unitPrice;
Console.WriteLine(total); // 399.2
この場合、intの値がdoubleとして扱われ、結果もdoubleになります。
ただし、整数同士の割り算には注意しましょう。
C#int a = 5;
int b = 2;
double result = a / b;
Console.WriteLine(result); // 2
a / bはint / intなので、結果は整数の2になります。小数の2.5を得たい場合は、どちらかをdoubleに変換します。
C#double result = (double)a / b;
Console.WriteLine(result); // 2.5
または、最初から小数リテラルを使います。
C#double result = 5.0 / 2;
Console.WriteLine(result); // 2.5
2-5. 文字列からdouble型に変換する方法
ユーザー入力やファイルから読み込んだ値は、文字列として扱われることがよくあります。文字列をdoubleに変換するには、double.Parseまたはdouble.TryParseを使います。
C#string text = "123.45";
double value = double.Parse(text);
Console.WriteLine(value);
ただし、double.Parseは変換できない文字列を渡すと例外が発生します。
C#string text = "abc";
double value = double.Parse(text); // 例外
安全に変換したい場合は、double.TryParseを使います。
C#string text = "123.45";
if (double.TryParse(text, out double value))
{
Console.WriteLine($"変換成功: {value}");
}
else
{
Console.WriteLine("変換できませんでした");
}
TryParseは、変換に成功するとtrueを返し、変換後の値をout引数に入れます。変換に失敗しても例外が発生しないため、ユーザー入力を扱う場面ではTryParseの方が実用的です。
3. double・float・decimalの違い
3-1. double・float・decimalの比較表
C#で小数を扱う代表的な型には、float、double、decimalがあります。それぞれの違いを表にまとめると、次のようになります。
| 型 | サイズ | 精度の目安 | リテラル例 | 特徴 | 主な用途 |
|---|---|---|---|---|---|
float | 4バイト | 約6〜9桁 | 1.23f | 軽量だが精度は低め | ゲーム、画像処理、大量データ |
double | 8バイト | 約15〜17桁 | 1.23 / 1.23d | 標準的な小数計算に使いやすい | 科学技術計算、座標、平均値 |
decimal | 16バイト | 約28〜29桁 | 1.23m | 10進小数に強い | 金額、税金、会計 |
doubleは、精度と速度のバランスがよく、C#で小数計算をするときによく使われる型です。一方、金額計算ではdecimalが向いています。MicrosoftのC#リファレンスでも、decimalはdoubleより精度が高く範囲は狭い型として説明されています。
3-2. doubleとfloatの違い
doubleとfloatは、どちらも2進浮動小数点数です。違いは、主にサイズと精度です。
floatは4バイトで、doubleは8バイトです。floatの方がメモリ使用量は少ないですが、表現できる精度はdoubleより低くなります。
C#float f = 1.23456789f;
double d = 1.23456789;
Console.WriteLine(f);
Console.WriteLine(d);
floatは、ゲーム開発やグラフィック処理など、大量の小数データを扱い、多少の誤差よりもメモリ効率や処理速度を重視する場面で使われることがあります。
一方、通常のアプリケーションで小数を扱う場合は、まずdoubleを検討することが多いです。C#の小数リテラルも、サフィックスなしではdoubleになるため、自然にdoubleを使う場面が多くなります。
3-3. doubleとdecimalの違い
doubleとdecimalの大きな違いは、小数の表現方法と用途です。
doubleは2進数ベースの浮動小数点数です。非常に広い範囲の値を扱え、計算も高速ですが、0.1のような10進小数を正確に表せない場合があります。
一方、decimalは10進小数の計算に向いています。金額や税金のように、10進数としての正確さが重要な処理ではdecimalを使うのが一般的です。
C#double d = 0.1 + 0.2;
decimal m = 0.1m + 0.2m;
Console.WriteLine(d); // 0.30000000000000004 になることがある
Console.WriteLine(m); // 0.3
decimalはdoubleよりメモリを多く使い、計算速度も遅くなる傾向があります。しかし、金額計算では速度よりも正確さが重要になるため、decimalを選ぶべきです。
3-4. 精度・メモリサイズ・計算速度の違い
float、double、decimalの違いを考えるときは、次の3つの観点が重要です。
1つ目は精度です。floatよりdoubleの方が精度が高く、doubleよりdecimalの方が10進計算に向いています。
2つ目はメモリサイズです。floatは4バイト、doubleは8バイト、decimalは16バイトです。大量のデータを配列で扱う場合、サイズの違いはメモリ使用量に影響します。
3つ目は計算速度です。一般的に、科学技術計算や座標計算ではdoubleがよく使われます。decimalは金額計算に強い一方、doubleより重い処理になりやすいです。
C#float f = 1.23f; // 軽量
double d = 1.23; // 標準的
decimal m = 1.23m; // 金額向き
迷った場合は、金額ならdecimal、一般的な小数計算ならdouble、メモリ効率が重要な大量データならfloatと考えるとわかりやすいです。
3-5. 用途別に見る使い分けの判断基準
用途別の判断基準は次の通りです。
| 用途 | おすすめの型 | 理由 |
|---|---|---|
| 平均値の計算 | double | 一般的な小数計算に向いている |
| 身長・体重・BMI | double | 小数を自然に扱える |
| 座標・距離・角度 | double | 精度と速度のバランスがよい |
| ゲームの大量データ | float | メモリ使用量を抑えやすい |
| 金額・税金・会計 | decimal | 10進小数の正確さが重要 |
| 請求金額 | decimal | 誤差が問題になりやすい |
| 科学技術計算 | double | 広い範囲と十分な精度が必要 |
初心者がまず覚えるべきなのは、doubleとdecimalの使い分けです。通常の小数計算ではdouble、お金の計算ではdecimalと覚えておくと、多くの場面で判断しやすくなります。
4. double型で誤差が発生する原因
4-1. double型は2進数で小数を表現している
double型で誤差が発生する最大の理由は、内部で2進数を使って小数を表現しているからです。
私たちが普段使っている数値は10進数です。たとえば0.1は、10進数ではとても自然な小数です。しかし、コンピューター内部では2進数で値を扱います。
10進数の0.1は、2進数では有限の桁数で正確に表せません。そのため、double型では0.1にとても近い値として保存されます。
つまり、C#のdoubleで0.1と書いても、内部的には完全な0.1ではなく、0.1に非常に近い近似値として扱われるのです。
4-2. 0.1や0.2が正確に表せない理由
10進数では、1 / 10は0.1として正確に表せます。しかし、2進数では0.1を有限桁で表すことができません。
これは、10進数で1 / 3が0.333333...と無限に続くのと似ています。10進数では1 / 3を正確に有限桁で表せません。同じように、2進数では0.1や0.2を正確に表せません。
そのため、次のようなコードでは、期待と少し違う結果になることがあります。
C#double result = 0.1 + 0.2;
Console.WriteLine(result);
出力例は次のようになる場合があります。
0.30000000000000004
人間の感覚では0.1 + 0.2は0.3ですが、doubleでは近似値同士の計算になるため、わずかな誤差が表面化することがあります。
4-3. double型の計算結果が想定とずれる例
double型の誤差は、次のようなコードで確認できます。
C#double a = 0.1;
double b = 0.2;
double c = 0.3;
Console.WriteLine(a + b);
Console.WriteLine(c);
Console.WriteLine(a + b == c);
出力例は次のようになります。
0.30000000000000004
0.3
False
a + bとcは、どちらも数学的には0.3に見えます。しかし、内部的な値が完全には一致しないため、==で比較するとfalseになることがあります。
このような誤差は、double型を使ううえで非常に重要な注意点です。
4-4. 誤差はバグではなく浮動小数点数の仕様
double型の誤差は、C#のバグではありません。浮動小数点数という仕組みの仕様です。
doubleは、広い範囲の数値を限られたメモリで効率よく扱うために、近似値を使います。そのおかげで、非常に大きな値や非常に小さな値を扱えます。
一方で、すべての小数を正確に表現できるわけではありません。これはC#だけでなく、Java、JavaScript、Python、C++など、多くのプログラミング言語でも共通する問題です。
大切なのは、「doubleには誤差があるから使えない」と考えることではありません。「doubleは近似計算のための型であり、用途に応じて正しく使う」と理解することです。
4-5. 誤差が問題になりやすいケース
doubleの誤差が問題になりやすいのは、次のようなケースです。
| ケース | 問題点 |
|---|---|
| 金額計算 | 1円単位のズレが問題になる |
| 税金計算 | 端数処理のルールが重要 |
| 請求金額 | 誤差がそのまま金銭トラブルにつながる |
==による比較 | わずかな誤差でfalseになる |
| 大きな値と小さな値の混在 | 小さい値が計算結果に反映されにくい |
| 何度も加算する処理 | 誤差が蓄積することがある |
たとえば、0.1を10回足すコードを考えてみます。
C#double sum = 0;
for (int i = 0; i < 10; i++)
{
sum += 0.1;
}
Console.WriteLine(sum);
期待する結果は1.0ですが、実際には0.9999999999999999のような値になることがあります。
このような誤差を避けるには、用途に応じてdecimalを使ったり、比較時に許容誤差を使ったりする必要があります。
5. double型の誤差への正しい対処法
5-1. double同士を==で比較しない
double型を扱うときに特に注意したいのが、==による比較です。
次のコードを見てください。
C#double a = 0.1 + 0.2;
double b = 0.3;
Console.WriteLine(a == b);
数学的には同じ値に見えますが、結果はfalseになることがあります。
False
これは、aとbの内部的な値が完全には一致していないためです。
double型の値は近似値であることが多いため、「完全に等しいか」を調べる==とは相性がよくありません。特に、計算結果同士を比較する場合は注意が必要です。
C#if (a == b)
{
Console.WriteLine("等しい");
}
このような書き方は、doubleでは避けた方が安全です。
5-2. 許容誤差を使って比較する
double同士を比較するときは、「完全に一致するか」ではなく、「差が十分に小さいか」で判断します。このときに使う小さな値を「許容誤差」と呼びます。
C#double a = 0.1 + 0.2;
double b = 0.3;
double epsilon = 0.0000001;
if (Math.Abs(a - b) < epsilon)
{
Console.WriteLine("ほぼ等しい");
}
else
{
Console.WriteLine("等しくない");
}
Math.Abs(a - b)は、aとbの差の絶対値を求めます。その差がepsilonより小さければ、「ほぼ等しい」と判断します。
ほぼ等しい
許容誤差の値は、扱うデータの性質によって変える必要があります。たとえば、座標計算では0.000001で十分な場合もありますが、科学技術計算ではもっと厳密な基準が必要になることもあります。
5-3. 表示時は丸め・桁数指定を行う
doubleの誤差は、画面表示のときに目立つことがあります。
C#double result = 0.1 + 0.2;
Console.WriteLine(result);
出力例は次の通りです。
0.30000000000000004
ユーザーに表示する値としては、このままだと不自然です。そのため、表示時には桁数を指定するのが一般的です。
C#double result = 0.1 + 0.2;
Console.WriteLine(result.ToString("F2"));
出力は次のようになります。
0.30
文字列補間でも桁数指定ができます。
C#double value = 123.4567;
Console.WriteLine($"{value:F2}");
出力は次の通りです。
123.46
F2は、小数点以下2桁で表示する指定です。表示用に見た目を整える場合は、ToStringや文字列補間の書式指定を使うと便利です。
5-4. Math.Roundで丸める方法
数値そのものを指定した桁数に丸めたい場合は、Math.Roundを使います。
C#double value = 123.4567;
double rounded = Math.Round(value, 2);
Console.WriteLine(rounded); // 123.46
第2引数には、小数点以下の桁数を指定します。
C#Console.WriteLine(Math.Round(1.2345, 2)); // 1.23
Console.WriteLine(Math.Round(1.2355, 2)); // 1.24
ただし、Math.Roundの丸め方法には注意が必要です。既定では、中間値の丸めに「最近接偶数への丸め」が使われる場合があります。一般的な四捨五入に近い動作を明示したい場合は、MidpointRounding.AwayFromZeroを指定します。MicrosoftのMath.Roundのドキュメントでも、丸め方法を指定できるオーバーロードが用意されています。
C#double value = 2.5;
Console.WriteLine(Math.Round(value));
Console.WriteLine(Math.Round(value, MidpointRounding.AwayFromZero));
業務ルールで端数処理が決まっている場合は、「どの丸め方法を使うか」を必ず確認しましょう。
5-5. 金額計算ではdecimal型を使う
金額計算では、doubleではなくdecimalを使うのが基本です。
C#decimal price = 1000m;
decimal taxRate = 0.10m;
decimal total = price + price * taxRate;
Console.WriteLine(total); // 1100.00
decimal型のリテラルにはmまたはMを付けます。
C#decimal amount = 123.45m;
doubleで金額を扱うと、2進数による小数表現の誤差が問題になることがあります。たとえば、請求金額や税額の端数処理で誤差が混ざると、表示金額や合計金額が合わない原因になります。
金額、税金、割引額、請求金額、会計データなどは、decimalを使うと覚えておきましょう。
6. double型を使うべき場面・使わない方がよい場面
6-1. double型が向いている処理
double型が向いているのは、多少の丸め誤差を許容でき、広い範囲の数値や小数を扱いたい処理です。
具体的には、次のような処理に向いています。
| 処理 | 例 |
|---|---|
| 平均値の計算 | テスト平均、測定値の平均 |
| 科学技術計算 | 物理計算、統計処理 |
| 座標計算 | 2D座標、3D座標 |
| 距離計算 | 2点間の距離 |
| 角度計算 | 三角関数、回転処理 |
| センサー値 | 温度、湿度、速度など |
| グラフ描画 | 座標、倍率、スケール |
たとえば、BMIの計算や距離の計算ではdoubleが自然です。
C#double height = 1.70;
double weight = 65.0;
double bmi = weight / (height * height);
Console.WriteLine(bmi);
このような計算では、金額のように1円単位で厳密に一致する必要はないため、doubleが使いやすいです。
6-2. float型が向いている処理
float型は、doubleより精度は低いものの、メモリ使用量が少ない型です。
floatが向いているのは、次のような場面です。
| 処理 | 理由 |
|---|---|
| ゲーム開発 | 大量の座標やベクトルを扱うことが多い |
| 画像処理 | ピクセルや色のデータを大量に扱う |
| 3Dグラフィックス | GPUとの相性を考える場面がある |
| メモリ制約が厳しい処理 | 4バイトで小数を扱える |
C#でfloatリテラルを書く場合は、fを付けます。
C#float x = 1.5f;
float y = 2.5f;
float result = x + y;
ただし、通常のアプリケーション開発で小数を扱うだけなら、まずdoubleを使う方がわかりやすいです。floatは、メモリ効率やライブラリの都合で必要になったときに選ぶとよいでしょう。
6-3. decimal型が向いている処理
decimal型が向いているのは、10進数としての正確さが重要な処理です。
代表的なのは金額計算です。
C#decimal price = 1980m;
decimal discountRate = 0.15m;
decimal discountedPrice = price * (1 - discountRate);
Console.WriteLine(discountedPrice);
decimalが向いている処理には、次のようなものがあります。
| 処理 | 理由 |
|---|---|
| 商品価格 | 1円単位の正確さが重要 |
| 税金計算 | 端数処理のルールがある |
| 請求金額 | 誤差がトラブルになる |
| 会計処理 | 正確な10進計算が必要 |
| 割引計算 | 表示金額との一致が重要 |
| 給与計算 | 金額の誤差が許されにくい |
decimalはdoubleより重い処理になりやすいですが、金額計算では速度より正確さが重要です。
6-4. 金額・税金・請求金額の計算でdoubleを避ける理由
金額計算でdoubleを避けるべき理由は、2進数による小数表現の誤差が発生するためです。
たとえば、次のようなコードを考えます。
C#double price = 0.1;
double total = price * 3;
Console.WriteLine(total);
人間の感覚では0.3ですが、内部的にはわずかな誤差を含む可能性があります。
金額計算では、このようなわずかな誤差が、端数処理や合計金額に影響することがあります。特に、消費税、割引、請求金額、複数商品の合計などでは、誤差の蓄積が問題になりやすいです。
そのため、金額を扱うコードでは次のようにdecimalを使います。
C#decimal price = 0.1m;
decimal total = price * 3;
Console.WriteLine(total); // 0.3
金額の計算では、doubleではなくdecimalを使う。このルールは、C#初心者が早い段階で覚えておきたい重要ポイントです。
6-5. 科学技術計算や座標計算でdoubleが使われる理由
科学技術計算や座標計算では、doubleがよく使われます。理由は、広い範囲の値を扱え、計算速度と精度のバランスがよいからです。
たとえば、2点間の距離を求めるコードではdoubleが自然です。
C#double x1 = 1.0;
double y1 = 2.0;
double x2 = 4.0;
double y2 = 6.0;
double dx = x2 - x1;
double dy = y2 - y1;
double distance = Math.Sqrt(dx * dx + dy * dy);
Console.WriteLine(distance);
座標や距離の計算では、金額のように10進数の小数を厳密に扱う必要はありません。それよりも、三角関数、平方根、指数計算などを効率よく扱えることが重要です。
C#のMath.Sin、Math.Cos、Math.Sqrtなどのメソッドも、主にdoubleを扱います。そのため、数学的な計算ではdoubleを使う場面が多くなります。
7. double型でよく使うメソッド・プロパティ
7-1. double.Parseで文字列を数値に変換する
double.Parseは、文字列をdouble型に変換するメソッドです。
C#string text = "123.45";
double value = double.Parse(text);
Console.WriteLine(value);
入力文字列が正しい数値であれば、doubleに変換できます。
ただし、変換できない文字列を渡すと例外が発生します。
C#string text = "hello";
double value = double.Parse(text); // 例外
そのため、ユーザー入力を直接double.Parseに渡すと、入力ミスによってプログラムが止まる可能性があります。
固定されたデータや、数値であることが確実な文字列を変換する場合はParseで問題ありません。しかし、ユーザーが入力する値を扱う場合は、次に紹介するTryParseの方が安全です。
7-2. double.TryParseで安全に変換する
double.TryParseは、文字列をdoubleに変換できるかどうかを安全に判定できるメソッドです。変換に失敗しても例外が発生しません。
C#string text = "123.45";
bool success = double.TryParse(text, out double value);
if (success)
{
Console.WriteLine($"変換成功: {value}");
}
else
{
Console.WriteLine("変換失敗");
}
ユーザー入力を扱う場合は、次のように書くと安全です。
C#Console.Write("数値を入力してください: ");
string? input = Console.ReadLine();
if (double.TryParse(input, out double number))
{
Console.WriteLine($"入力された数値: {number}");
}
else
{
Console.WriteLine("数値として認識できませんでした");
}
TryParseは、入力フォーム、CSVファイルの読み込み、設定ファイルの読み込みなどでよく使います。実務ではParseよりTryParseを使う場面の方が多いと考えてよいでしょう。
7-3. double.IsNaNとは
double.IsNaNは、値がNaNかどうかを判定するメソッドです。NaNは「Not a Number」の略で、数値ではない結果を表します。
たとえば、0.0 / 0.0のような計算ではNaNが発生します。
C#double value = 0.0 / 0.0;
Console.WriteLine(value); // NaN
Console.WriteLine(double.IsNaN(value)); // True
NaNの判定では、==を使ってはいけません。
C#double value = double.NaN;
Console.WriteLine(value == double.NaN); // False
Console.WriteLine(double.IsNaN(value)); // True
NaNは自分自身とも等しくないという特殊な性質を持ちます。そのため、NaNかどうかを調べるときは、必ずdouble.IsNaNを使います。System.Doubleには、IsNaNやIsInfinityなど、特殊な浮動小数点値を判定するためのメソッドが用意されています。
7-4. double.IsInfinityとは
double.IsInfinityは、値が正または負の無限大かどうかを判定するメソッドです。
doubleでは、0で割ったときに例外ではなくInfinityになる場合があります。
C#double value = 1.0 / 0.0;
Console.WriteLine(value); // Infinity
Console.WriteLine(double.IsInfinity(value)); // True
負の値を0で割ると、負の無限大になります。
C#double value = -1.0 / 0.0;
Console.WriteLine(value); // -Infinity
Console.WriteLine(double.IsInfinity(value)); // True
正の無限大かどうかを判定したい場合は、double.IsPositiveInfinityを使います。
C#double value = 1.0 / 0.0;
Console.WriteLine(double.IsPositiveInfinity(value)); // True
負の無限大かどうかを判定したい場合は、double.IsNegativeInfinityを使います。
C#double value = -1.0 / 0.0;
Console.WriteLine(double.IsNegativeInfinity(value)); // True
計算結果が異常に大きくなる可能性がある処理では、IsInfinityを使ってチェックすると安全です。
7-5. double.MaxValue・double.MinValueの使い方
double.MaxValueは、double型で表現できる最大の値を表します。
C#Console.WriteLine(double.MaxValue);
非常に大きな値が出力されます。
double.MinValueは、double型で表現できる最小の値というより、「最も小さい負の値」、つまり最も大きなマイナス方向の値を表します。
C#Console.WriteLine(double.MinValue);
ここで注意したいのは、double.MinValueは「0より大きい最小の正の値」ではないという点です。最も小さい正の値に近い概念としてはdouble.Epsilonがありますが、一般的な許容誤差としてそのまま使うには小さすぎることが多いです。
たとえば、比較用の許容誤差は自分で決めるのが一般的です。
C#double epsilon = 0.000001;
MaxValueやMinValueは、初期値として非常に大きな値や小さな値を設定したいときに使うことがあります。
C#double min = double.MaxValue;
double[] values = { 3.5, 1.2, 9.8 };
foreach (double value in values)
{
if (value < min)
{
min = value;
}
}
Console.WriteLine(min); // 1.2
8. double型でよくあるエラーと注意点
8-1. decimal型へ代入するときにエラーになる理由
次のコードはエラーになります。
C#decimal price = 123.45; // エラー
理由は、123.45がdouble型のリテラルとして扱われるためです。double型の値をdecimal型に暗黙的に変換することはできません。
decimal型に代入する場合は、mまたはMを付けます。
C#decimal price = 123.45m;
または、明示的にキャストします。
C#decimal price = (decimal)123.45;
ただし、金額計算では最初からdecimalリテラルとして書く方が安全です。
C#decimal taxRate = 0.10m;
doubleからdecimalに変換すると、すでにdouble側で近似された値を変換することになるため、意図しない値になる可能性があります。
8-2. float型へ代入するときにキャストが必要な理由
次のコードもエラーになります。
C#float value = 1.23; // エラー
理由は、1.23がdouble型として扱われるためです。doubleはfloatより精度が高い型なので、暗黙的にfloatへ変換すると情報が失われる可能性があります。そのため、C#では自動変換されません。
float型に代入するには、fまたはFを付けます。
C#float value = 1.23f;
または、明示的にキャストします。
C#float value = (float)1.23;
ただし、通常は1.23fのようにサフィックスを付ける方が自然です。
8-3. 0除算時の挙動
C#では、整数の0除算とdoubleの0除算で挙動が異なります。
整数を0で割ると例外が発生します。
C#int a = 1;
int b = 0;
// int result = a / b; // DivideByZeroException
一方、double型では、0で割っても例外ではなくInfinityやNaNになる場合があります。
C#double a = 1.0 / 0.0;
double b = -1.0 / 0.0;
double c = 0.0 / 0.0;
Console.WriteLine(a); // Infinity
Console.WriteLine(b); // -Infinity
Console.WriteLine(c); // NaN
この違いは初心者が混乱しやすいポイントです。
doubleの計算結果がそのまま後続処理に使われると、InfinityやNaNが広がって予期しない結果になることがあります。必要に応じて、double.IsInfinityやdouble.IsNaNでチェックしましょう。
8-4. NaNやInfinityが発生するケース
NaNやInfinityは、次のようなケースで発生します。
| 値 | 発生例 |
|---|---|
NaN | 0.0 / 0.0 |
Infinity | 1.0 / 0.0 |
-Infinity | -1.0 / 0.0 |
NaN | 無効な数学演算 |
Infinity | 非常に大きな値の計算結果 |
例を見てみましょう。
C#double nan = 0.0 / 0.0;
double positiveInfinity = 1.0 / 0.0;
double negativeInfinity = -1.0 / 0.0;
Console.WriteLine(double.IsNaN(nan));
Console.WriteLine(double.IsPositiveInfinity(positiveInfinity));
Console.WriteLine(double.IsNegativeInfinity(negativeInfinity));
計算結果を安全に扱うには、必要に応じてチェックを入れます。
C#double result = Calculate();
if (double.IsNaN(result) || double.IsInfinity(result))
{
Console.WriteLine("計算結果が不正です");
}
else
{
Console.WriteLine(result);
}
特に、ユーザー入力を使った計算、外部データを使った計算、0に近い値で割る可能性がある計算では注意が必要です。
8-5. 桁落ちや丸め誤差に注意する
double型では、丸め誤差だけでなく、桁落ちにも注意が必要です。
桁落ちとは、非常に近い値同士を引き算したときに、有効な桁が失われてしまう現象です。
C#double a = 1.0000001;
double b = 1.0000000;
double result = a - b;
Console.WriteLine(result);
期待する値は0.0000001ですが、浮動小数点数の表現の都合で、完全に期待通りの値にならない場合があります。
また、大きな値と小さな値を足す場合、小さな値が結果に反映されにくくなることもあります。
C#double big = 10000000000000000.0;
double small = 1.0;
Console.WriteLine(big + small);
このような問題は、数値計算では重要です。通常のアプリケーションでは深く意識しなくてもよい場面も多いですが、精密な計算を行う場合は、計算順序や型の選択に注意しましょう。
9. double型の実践コード例
9-1. 平均値を計算する例
double型は、平均値の計算に向いています。整数の合計を小数として割り算したい場合は、doubleを使います。
C#int[] scores = { 80, 90, 75, 85, 95 };
int sum = 0;
foreach (int score in scores)
{
sum += score;
}
double average = (double)sum / scores.Length;
Console.WriteLine($"平均点: {average:F1}");
出力例は次の通りです。
平均点: 85.0
ポイントは、(double)sumとしてから割り算していることです。これにより、整数同士の割り算ではなく、小数の割り算になります。
9-2. BMIを計算する例
BMIは、体重を身長の2乗で割って求めます。身長や体重は小数になることが多いため、doubleが向いています。
C#double height = 1.70; // メートル
double weight = 65.0; // キログラム
double bmi = weight / (height * height);
Console.WriteLine($"BMI: {bmi:F1}");
出力例は次の通りです。
BMI: 22.5
表示時にF1を指定しているため、小数点以下1桁で表示されます。
関数にすると、次のように書けます。
C#static double CalculateBmi(double height, double weight)
{
return weight / (height * height);
}
double bmi = CalculateBmi(1.70, 65.0);
Console.WriteLine($"{bmi:F1}");
9-3. 距離や座標を計算する例
2点間の距離を求める場合にもdoubleがよく使われます。
C#double x1 = 1.0;
double y1 = 2.0;
double x2 = 4.0;
double y2 = 6.0;
double dx = x2 - x1;
double dy = y2 - y1;
double distance = Math.Sqrt(dx * dx + dy * dy);
Console.WriteLine($"距離: {distance}");
出力は次のようになります。
距離: 5
2Dや3Dの座標計算、ゲーム、シミュレーション、地図アプリなどでは、このような計算がよく登場します。
3次元の距離なら、次のように書けます。
C#double x1 = 1.0;
double y1 = 2.0;
double z1 = 3.0;
double x2 = 4.0;
double y2 = 6.0;
double z2 = 8.0;
double dx = x2 - x1;
double dy = y2 - y1;
double dz = z2 - z1;
double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz);
Console.WriteLine(distance);
9-4. 小数点以下の桁数を指定して表示する例
doubleの値を表示するときは、桁数を指定すると見やすくなります。
C#double value = 123.456789;
Console.WriteLine(value.ToString("F2"));
Console.WriteLine($"{value:F2}");
Console.WriteLine($"{value:F3}");
出力例は次の通りです。
123.46
123.46
123.457
F2は小数点以下2桁、F3は小数点以下3桁です。
パーセント表示をしたい場合は、次のようにできます。
C#double rate = 0.1234;
Console.WriteLine($"{rate:P1}");
出力例は次の通りです。
12.3%
ただし、表示を丸めることと、内部の数値そのものを丸めることは別です。表示だけ整えたい場合は書式指定、値そのものを丸めたい場合はMath.Roundを使います。
9-5. 許容誤差を使って比較する例
double同士を安全に比較するには、許容誤差を使います。
C#static bool AreAlmostEqual(double a, double b, double epsilon)
{
return Math.Abs(a - b) < epsilon;
}
double x = 0.1 + 0.2;
double y = 0.3;
if (AreAlmostEqual(x, y, 0.0000001))
{
Console.WriteLine("ほぼ等しい");
}
else
{
Console.WriteLine("等しくない");
}
出力は次のようになります。
ほぼ等しい
毎回同じ許容誤差を使うなら、定数として定義しておくと便利です。
C#const double Epsilon = 0.0000001;
double a = 0.1 + 0.2;
double b = 0.3;
if (Math.Abs(a - b) < Epsilon)
{
Console.WriteLine("ほぼ等しい");
}
ただし、すべての場面で同じEpsilonを使えばよいわけではありません。扱う値の大きさや必要な精度に応じて、許容誤差を調整しましょう。
10. C#のdouble型に関するよくある質問
10-1. doubleとDoubleに違いはある?
C#では、doubleとDoubleは基本的に同じものを指します。
doubleはC#のキーワードで、System.Doubleの別名です。
C#double a = 1.23;
System.Double b = 1.23;
Double c = 1.23;
通常のC#コードでは、doubleと書くのが一般的です。
C#double value = 3.14;
一方、.NETの型名として説明するときや、リフレクションなどで型を扱うときにはSystem.DoubleやDoubleという名前を見ることがあります。
初心者は、まずdoubleと書けば問題ありません。
10-2. double型の小数点以下は何桁まで正確?
double型の精度は、小数点以下何桁というより、「有効桁数が約15〜17桁」と考える方が正確です。
たとえば、次のような値では、全体として何桁の精度があるかが重要です。
C#double a = 12345.6789012345;
double b = 0.000000123456789;
doubleは、小数点以下の桁数が固定されている型ではありません。非常に大きな値や非常に小さな値を扱うために、小数点の位置を動かして表現します。そのため、「小数点以下15桁まで必ず正確」とは言えません。
また、0.1のような短い小数でも、2進数では正確に表せない場合があります。
C#double value = 0.1;
このため、doubleは「約15〜17桁の精度を持つ近似値」と理解するのがよいでしょう。
10-3. double型とdecimal型はどちらを使うべき?
用途によって使い分けます。
一般的な小数計算、科学技術計算、座標計算、距離計算、平均値の計算などではdoubleが向いています。
C#double distance = 12.34;
double average = 85.6;
金額、税金、会計、請求金額、給与計算などではdecimalが向いています。
C#decimal price = 1980m;
decimal tax = 0.10m;
判断に迷ったら、次のように考えるとわかりやすいです。
| 判断基準 | 使う型 |
|---|---|
| 金額を扱う | decimal |
| 税金を扱う | decimal |
| 請求金額を扱う | decimal |
| 座標や距離を扱う | double |
| 平均値を扱う | double |
| 科学技術計算をする | double |
初心者向けに一言でまとめるなら、「お金はdecimal、それ以外の一般的な小数はdouble」です。
10-4. double型で0.1 + 0.2が0.3にならないのはなぜ?
double型は、内部で2進数を使って小数を表現しているためです。
10進数では0.1や0.2は簡単に表せますが、2進数では正確に表せません。そのため、doubleでは0.1や0.2が近似値として保存されます。
C#double result = 0.1 + 0.2;
Console.WriteLine(result);
出力例は次の通りです。
0.30000000000000004
これはC#のバグではなく、浮動小数点数の仕様です。
比較するときは、==ではなく許容誤差を使います。
C#double result = 0.1 + 0.2;
double expected = 0.3;
if (Math.Abs(result - expected) < 0.0000001)
{
Console.WriteLine("ほぼ等しい");
}
金額のように10進数として正確に扱いたい場合は、decimalを使いましょう。
C#decimal result = 0.1m + 0.2m;
Console.WriteLine(result); // 0.3
10-5. 初心者はまずどの数値型を覚えるべき?
C#初心者は、まず次の数値型を覚えるとよいでしょう。
| 型 | 役割 |
|---|---|
int | 整数を扱う |
double | 一般的な小数を扱う |
decimal | 金額を扱う |
最初は、この3つを覚えれば多くの基本的なプログラムを書けます。
C#int count = 10;
double average = 85.5;
decimal price = 1200m;
floatは、ゲーム開発や画像処理などで使う場面がありますが、初心者が最初に必ず覚える必要はありません。まずは、整数ならint、小数ならdouble、金額ならdecimalという使い分けを理解しましょう。
まとめ
C#のdouble型は、小数を扱うための代表的な数値型です。floatより精度が高く、decimalより広い範囲の値を効率よく扱えるため、平均値、距離、座標、科学技術計算など、さまざまな場面で使われます。
一方で、doubleは2進数で小数を表現するため、0.1や0.2のような10進小数を正確に表せないことがあります。その結果、0.1 + 0.2が0.30000000000000004になるような誤差が発生することがあります。
double型を使うときの重要ポイントは次の通りです。
| ポイント | 内容 |
|---|---|
doubleは小数を扱う型 | 一般的な小数計算に向いている |
小数リテラルは基本的にdouble | 3.14はdoubleとして扱われる |
floatは軽量 | 1.23fのようにfを付ける |
decimalは金額向き | 1.23mのようにmを付ける |
doubleには誤差がある | 2進数で小数を近似するため |
==比較は避ける | 許容誤差を使って比較する |
| 表示時は桁数指定する | F2やMath.Roundを使う |
金額計算ではdecimal | 税金・請求金額ではdoubleを避ける |
C#で小数を扱うときは、まずdoubleを理解することが大切です。ただし、すべての小数計算にdoubleを使うのではなく、用途に応じてfloatやdecimalと使い分ける必要があります。
初心者はまず、「一般的な小数はdouble、お金はdecimal、大量データやゲームではfloat」という基本ルールを覚えておきましょう。これだけでも、C#の数値型でつまずく場面を大きく減らせます。

