C#において数値計算を行う際、頻繁に利用されるのが平方根 (ルート) の計算です。
グラフィックス処理、物理シミュレーション、データ分析、あるいは単純な距離計算など、プログラミングのあらゆる場面で「ある数値の2乗根を求める」という操作が必要になります。
C#では標準ライブラリとしてMath.Sqrtメソッドが用意されており、これを利用することで簡潔かつ正確に計算を行うことが可能です。
本記事では、基本的な使い方から、パフォーマンスが求められる場面での高速化テクニックまで、詳しく紐解いていきます。
Math.Sqrtの基本的な使い方
C#で平方根を計算する最も一般的で標準的な方法は、System.Math.Sqrtメソッドを使用することです。
このメソッドは、引数として渡された数値の平方根をdouble型で返します。
基本的な構文とサンプルコード
Math.Sqrtのシグネチャは以下の通りです。
public static double Sqrt(double d);
引数に負の値を指定した場合は、NaN (Not a Number: 非数)が返される点に注意が必要です。
まずは、基本的な計算例を見てみましょう。
using System;
class Program
{
static void Main()
{
double value = 25.0;
// 平方根を計算
double result = Math.Sqrt(value);
Console.WriteLine($"元の値: {value}");
Console.WriteLine($"平方根: {result}");
// 小数を含む値の計算
double value2 = 2.0;
double result2 = Math.Sqrt(value2);
Console.WriteLine($"2の平方根: {result2}");
}
}
元の値: 25
平方根: 5
2の平方根: 1.4142135623730951
返り値の型と精度の注意点
Math.Sqrtは常に倍精度浮動小数点数 (double)を返します。
C#ではfloat型やdecimal型を扱うことも多いですが、Math.Sqrtにこれらの型を渡す場合は、暗黙的または明示的なキャストが発生します。
特にdecimal型を扱う場合、doubleへのキャストによって精度が失われる可能性があるため、金融計算などの厳密な精度が求められるケースでは、計算後に元の型へ戻す際の誤差に配慮する必要があります。
Math.SqrtとMathF.Sqrtの使い分け
.NET Core 2.1以降および.NET 5以降では、float型に特化したMathF.Sqrtメソッドが導入されました。
これは単精度浮動小数点数を扱う場合に非常に有用です。
MathF.Sqrtの利点
従来のMath.Sqrtでfloat型の計算を行おうとすると、以下のような処理が内部で行われます。
floatからdoubleへ変換doubleで平方根を計算- 結果を
doubleからfloatへキャストして戻す
この変換プロセスは、大量の計算を繰り返すゲームエンジン (Unityなど) やリアルタイム信号処理においては、わずかなオーバーヘッドとなります。
一方、MathF.Sqrtを使用すれば、最初から最後まで単精度で処理されるため、パフォーマンスの向上が期待できます。
float fValue = 10.0f;
// float型のまま計算可能
float fResult = MathF.Sqrt(fValue);
「精度が必要なら Math.Sqrt、速度とメモリ効率を優先するなら MathF.Sqrt」という使い分けが、現代的なC#開発におけるスタンダードです。
負の値と例外処理
数学的には、実数の範囲内で負の数の平方根を求めることはできません。
C#のMath.Sqrtもこのルールに従い、引数に負の値を渡すとdouble.NaNを返します。
NaNの判定方法
プログラム内で計算結果が正当な数値であるかどうかを確認するには、double.IsNaNメソッドを使用します。
double negativeValue = -1.0;
double result = Math.Sqrt(negativeValue);
if (double.IsNaN(result))
{
Console.WriteLine("計算結果は実数ではありません (NaN)。");
}
計算結果は実数ではありません (NaN)。
例外 (Exception) がスローされるわけではないため、チェックを忘れると後続の計算がすべてNaNになり、原因の特定が困難になることがあります。
入力値が負にならないことが保証されていない場合は、事前にif (value >= 0)などの条件分岐を入れることが推奨されます。
実践的な応用例:2点間の距離を求める
平方根の最も代表的な応用例は、ピタゴラスの定理を用いた2点間の距離計算です。
2次元座標 $(x1, y1)$ と $(x2, y2)$ の距離 $d$ は、以下の式で求められます。
$d = \sqrt{(x2 – x1)^2 + (y2 – y1)^2}$
これをC#のコードで実装すると次のようになります。
public static double GetDistance(double x1, double y1, double x2, double y2)
{
double dx = x2 - x1;
double dy = y2 - y1;
// Math.Pow(dx, 2) を使うよりも dx * dx の方が高速です
return Math.Sqrt(dx * dx + dy * dy);
}
ここで、Math.Pow(dx, 2) ではなく dx * dx を使用している点に注目してください。
2乗程度の計算であれば、メソッドを呼び出すよりも乗算演算子を直接使う方が計算コストが低く、高速に動作します。
計算の高速化テクニック
通常のアプリケーション開発では Math.Sqrt で十分な速度が得られますが、数万〜数百万回のループ内で計算を行う場合には、さらなる最適化が必要になることがあります。
1. 平方根の計算を避ける (距離比較)
もし、2つの距離を比較するだけであれば、平方根を計算する必要はありません。 距離 $A$ と距離 $B$ を比較する場合、$A < B$ ならば $A^2 < B^2$ も成立します。
// 重い処理
if (Math.Sqrt(dx*dx + dy*dy) < 10.0) { ... }
// 軽い処理 (2乗のまま比較)
if ((dx*dx + dy*dy) < 100.0) { ... }
平方根の計算は、四則演算に比べてCPUサイクルを多く消費するため、比較目的であれば「2乗した値」同士で比べるのが定石です。
2. SIMD (System.Runtime.Intrinsics) の活用
.NET 7や.NET 8以降、ハードウェア固有の最適化命令 (SIMD: Single Instruction, Multiple Data) へのアクセスが容易になりました。
複数の数値の平方根を一度に計算する場合、Vector128.Sqrt や Vector256.Sqrt を使用することで、劇的な高速化が可能です。
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
// 例: 4つのfloat値を同時に計算 (SSE命令を使用)
var vector = Vector128.Create(1.0f, 4.0f, 9.0f, 16.0f);
var resultVector = Vector128.Sqrt(vector);
これは主に、大量の頂点データを持つグラフィックスライブラリや、数値計算エンジンを自作する場合に有効な手段です。
3. 高速逆平方根 (Fast Inverse Square Root) の歴史と現在
かつて「Q_rsqrt」として知られた、魔法の定数を利用する高速な逆平方根計算手法がありました。
しかし、現代のCPUにおいては、ハードウェアレベルで平方根計算が最適化されており、また専用の命令 (RSQRTPS等) が存在するため、自作の近似アルゴリズムを用いるメリットはほとんどなくなりました。 むしろ、標準の Math.Sqrt を使用する方が、JITコンパイラによる最適化の恩恵を受けやすく、安全かつ高速です。
数値型ごとの平方根計算まとめ
C#における各型に対する平方根の求め方を表にまとめました。
| 型 | 推奨されるメソッド | 備考 |
|---|---|---|
double | Math.Sqrt(n) | 標準的、最も高精度 |
float | MathF.Sqrt(n) | 単精度、メモリ効率・速度重視 |
int / long | Math.Sqrt(n) | doubleへ暗黙キャストされる |
decimal | (decimal)Math.Sqrt((double)n) | 明示的なキャストが必要 |
Vector<T> | Vector.SquareRoot(v) | SIMDによる並列計算 |
ニュートン法による平方根の自作実装
アルゴリズムの理解を深めるために、Math.Sqrt を使わずに平方根を求める方法も紹介します。
最も有名な手法は「ニュートン法」です。
ニュートン法は、近似値を繰り返し更新することで真の値に近づける手法です。
$x^2 = a$ となる $x$ を求めるため、$f(x) = x^2 – a$ という関数が $0$ になる点を探索します。
public static double CustomSqrt(double a)
{
if (a < 0) return double.NaN;
if (a == 0) return 0;
double x = a; // 初期推定値
for (int i = 0; i < 10; i++) // 10回程度の反復で十分な精度が出る
{
x = (x + a / x) / 2.0;
}
return x;
}
実際にこのコードを動かすと、驚くほど速く精度が高い結果が得られることがわかります。
標準ライブラリの中身を想像する一助となるでしょう。
まとめ
C#での平方根計算は、単純に見えて奥が深いテーマです。
- 基本的には
Math.Sqrtを使用すれば間違いありません。 - パフォーマンスが重要な
float演算ではMathF.Sqrtを選択しましょう。 - 負の値に対する NaN チェック を忘れないようにしてください。
- 大量のデータ処理やゲーム開発では、「平方根を計算せずに済む方法 (距離の2乗比較)」やSIMDの活用を検討してください。
適切なメソッドを選択することで、プログラムの可読性とパフォーマンスを両立させることができます。
数値計算の基本となる平方根を正しくマスターし、より効率的なC#プログラミングを実践していきましょう。
