平方根の計算は、距離や幾何、統計など幅広い分野で欠かせません。
C言語ではsqrt
(math.h
)が標準で用意されており、正しくインクルードし、必要に応じてリンク設定を行えばすぐに使えます。
この記事ではsqrtの基礎から注意点、実用的な例まで、初心者の方にもわかりやすく解説します。
sqrtとは
平方根を求める標準関数
sqrt
は、与えた数の主値の平方根を返すC標準ライブラリの関数です。
非負の数<x>に対してsqrt(x)
は「y≥0 かつ y*y = x」を満たす値になります。
Cでは#include <math.h>
で宣言が提供されます。
以下は代表的なプロトタイプです。
// math.h より(概念的な説明)
// 非負の x の平方根を返す。負の x に対しては NaN を返す(詳細は注意点を参照)。
double sqrt(double x);
float sqrtf(float x);
long double sqrtl(long double x);
多くの計算で使われる重要な関数ですので、まずはインクルードと戻り値の型を押さえておくと安心です。
引数と戻り値はdouble
sqrt
の基本形はdouble sqrt(double x)
で、引数と戻り値の両方がdouble
です。
整数リテラルやint
変数を渡すと自動的にdoubleに拡張されます。
- 例:
sqrt(9)
は内部的にsqrt(9.0)
として扱われます。
floatはsqrtf, long doubleはsqrtl
浮動小数点の精度を揃えたい場合は、型に対応するバージョンを使います。
特にfloat
変数に対してsqrt
を使うと毎回double
に変換され、戻り値もdouble
になるため、sqrtf
を使うと無駄な変換が避けられます。
次の表は型ごとの関数対応です。
浮動小数点型 | 関数 | プロトタイプ | 推奨printf書式 |
---|---|---|---|
float | sqrtf | float sqrtf(float x); | %f |
double | sqrt | double sqrt(double x); | %f |
long double | sqrtl | long double sqrtl(long double x); | %Lf |
簡単な比較コードです。
#include <stdio.h>
#include <math.h>
int main(void) {
float xf = 2.0f;
double xd = 2.0;
long double xld = 2.0L;
// それぞれの型に対応する関数で平方根を計算
float rf = sqrtf(xf);
double rd = sqrt(xd);
long double rld = sqrtl(xld);
printf("sqrtf(2.0f) = %.8f (float)\n", rf);
printf("sqrt(2.0) = %.15f (double)\n", rd);
printf("sqrtl(2.0L) = %.18Lf (long double)\n", rld);
return 0;
}
sqrtf(2.0f) = 1.41421354 (float)
sqrt(2.0) = 1.414213562373095 (double)
sqrtl(2.0L) = 1.414213562373095049 (long double)
必要な精度に応じて関数を選ぶことが、計算の質と性能の両方に効いてきます。
sqrtの使い方
math.hをインクルード
sqrt
を使うには#include <math.h>
が必須です。
標準入出力のために#include <stdio.h>
も一緒に使います。
#include <stdio.h>
#include <math.h>
int main(void) {
double x = 9.0;
double r = sqrt(x); // 9 の平方根は 3
printf("sqrt(%.1f) = %.1f\n", x, r);
return 0;
}
sqrt(9.0) = 3.0
インクルードを忘れると警告や未定義動作の原因になります。
コンパイル方法
Unix系環境(GCC/Clang)では、数学ライブラリのリンクオプションが必要です。
必ず-lm
を付ける点が重要です。
# GCC の例
gcc -std=c11 -Wall -Wextra main.c -lm -o run
# Clang の例
clang -std=c11 -Wall -Wextra main.c -lm -o run
Windows環境ではツールチェーンにより挙動が異なります。
- MSVC(Visual Studio): 追加の
-lm
は不要です。
cl /std:c11 /W4 main.c
- MinGW系(GCC): Unix系と同様に
-lm
が必要です。
gcc -std=c11 -Wall -Wextra main.c -lm -o run.exe
ビルドが通らない時は、オプションの有無や順序を見直すと解決することが多いです。
呼び出しの基本
sqrt
は引数に数値を渡すだけのシンプルな関数です。
書式指定子で桁数を調整すると、誤差や見やすさをコントロールできます。
#include <stdio.h>
#include <math.h>
int main(void) {
double a = 2.0;
double b = 9.0;
double ra = sqrt(a);
double rb = sqrt(b);
// 表示桁を変えて出力
printf("sqrt(%.1f) = %.6f\n", a, ra); // 6桁表示
printf("sqrt(%.1f) = %.15f\n", a, ra); // 15桁表示(誤差の観察に便利)
printf("sqrt(%.1f) = %.1f\n", b, rb);
return 0;
}
sqrt(2.0) = 1.414214
sqrt(2.0) = 1.414213562373095
sqrt(9.0) = 3.0
等値比較(==)ではなく、許容誤差内で比較するのが実践的です(誤差については後述)。
整数との併用
整数を渡すのは問題ありませんが、結果を整数に代入する時の丸めに注意が必要です。
#include <stdio.h>
#include <math.h> // lround を使うため
int main(void) {
int n1 = 10;
int n2 = 144;
// 整数を渡しても内部で double に拡張される
double r1 = sqrt(n1); // ≈ 3.162277...
double r2 = sqrt(n2); // 12.0 (ぴったり)
// 単純なキャストは小数点以下を切り捨てる
int t1 = (int)r1; // 3
int t2 = (int)r2; // 12
// 四捨五入して整数にしたいなら lround/llround などを使う
long rr1 = lround(r1); // 3
long rr2 = lround(r2); // 12
// 完全な平方数かどうか判定する簡易例(小さめの整数向け)
int m = 225;
int s = (int)(sqrt(m) + 0.5); // 近い整数に丸め
int is_square = (s * s == m); // 真なら完全平方
printf("sqrt(%d) ≈ %.6f, (int)で切り捨て -> %d, 四捨五入 -> %ld\n", n1, r1, t1, rr1);
printf("sqrt(%d) = %.1f, (int)で切り捨て -> %d, 四捨五入 -> %ld\n", n2, r2, t2, rr2);
printf("%d は完全平方数ですか? -> %s\n", m, is_square ? "YES" : "NO");
return 0;
}
sqrt(10) ≈ 3.162278, (int)で切り捨て -> 3, 四捨五入 -> 3
sqrt(144) = 12.0, (int)で切り捨て -> 12, 四捨五入 -> 12
225 は完全平方数ですか? -> YES
大きな整数で完全平方の判定を行う場合は、浮動小数点誤差の影響に注意してください。
厳密な判定が必要なら整数演算ベースのアルゴリズムを検討します。
sqrtの注意点
負の数はNaNになる
sqrt
は負の引数に対してNaN(非数)を返します。
標準関数isnan
でチェックできます。
環境によってはerrno
にEDOM
が設定されたり、浮動小数点例外FE_INVALID
が発生する場合があります。
#include <stdio.h>
#include <math.h> // sqrt, isnan
int main(void) {
double x = -1.0;
double r = sqrt(x);
printf("sqrt(%g) = %f\n", x, r); // 多くの処理系で "nan" と表示
if (isnan(r)) {
printf("結果は NaN でした(負の数の平方根は実数では定義されません)。\n");
}
return 0;
}
sqrt(-1) = nan
結果は NaN でした(負の数の平方根は実数では定義されません)。
複素数の平方根を扱いたい場合は、複素数ライブラリ<complex.h>
のcsqrt
系を使います(本記事の範囲外)。
0や正の数の扱い
0や正の数では、sqrt(0.0) == 0.0
、sqrt(4.0) == 2.0
のように期待通りの結果が得られます。
IEEE 754準拠の環境ではsqrt(INFINITY) == INFINITY
となります。
#include <stdio.h>
#include <math.h>
int main(void) {
double z = 0.0;
double p = 4.0;
double r1 = sqrt(z);
double r2 = sqrt(p);
double r3 = sqrt(INFINITY); // 無限大の平方根
printf("sqrt(%.1f) = %.1f\n", z, r1);
printf("sqrt(%.1f) = %.1f\n", p, r2);
printf("sqrt(INFINITY) = %f\n", r3); // 多くの環境で "inf"
return 0;
}
sqrt(0.0) = 0.0
sqrt(4.0) = 2.0
sqrt(INFINITY) = inf
計算誤差と表示桁に注意
浮動小数点は有限桁の近似なので、sqrt(2.0)
のように無理数の結果は厳密には表現できません。
表示桁を増やすと誤差が見えてきますし、計算の再合成(sqrt(2)*sqrt(2)
)がちょうど2にならないことがあります。
#include <stdio.h>
#include <math.h>
#include <float.h>
int main(void) {
double s = sqrt(2.0);
double back = s * s;
double diff = back - 2.0;
printf("sqrt(2.0) ≈ %.17f\n", s);
printf("再合成 s*s = %.17f\n", back);
printf("差分(back - 2.0) = %.17e\n", diff);
// 等値比較ではなく、許容誤差(イプシロン)による比較が安全
double eps = 1e-12; // 例: 適切な閾値を用途に応じて選ぶ
printf("|back - 2.0| < %.1e ? -> %s\n", eps, (fabs(diff) < eps) ? "YES" : "NO");
return 0;
}
sqrt(2.0) ≈ 1.4142135623730951
再合成 s*s = 2.0000000000000004
差分(back - 2.0) = 4.440892098501e-16
|back - 2.0| < 1.0e-12 ? -> YES
表示や比較は「必要な精度」に合わせるのが実務的です。
sqrtの実用例
2点間の距離を求める
2次元平面の2点(x1, y1)
と(x2, y2)
の距離はsqrt((x2-x1)^2 + (y2-y1)^2)
で求められます。
#include <stdio.h>
#include <math.h>
int main(void) {
// 例: (1, 2) と (4, 6) の距離
double x1 = 1.0, y1 = 2.0;
double x2 = 4.0, y2 = 6.0;
double dx = x2 - x1;
double dy = y2 - y1;
double dist = sqrt(dx*dx + dy*dy);
printf("点A(%.1f, %.1f) と 点B(%.1f, %.1f) の距離 = %.6f\n", x1, y1, x2, y2, dist);
return 0;
}
点A(1.0, 2.0) と 点B(4.0, 6.0) の距離 = 5.000000
距離計算はゲーム開発や幾何アルゴリズムの基本で、平方根の代表的な応用です。
入力値の平方根を表示する
ユーザーから数値を受け取り、負の数はエラーメッセージ、非負なら平方根を表示する例です。
#include <stdio.h>
#include <math.h>
int main(void) {
double x;
printf("数値を入力してください: ");
if (scanf("%lf", &x) != 1) {
// 入力の検証(失敗したら終了)
fprintf(stderr, "入力エラーです。\n");
return 1;
}
if (x < 0.0) {
// 実数の平方根は定義されないため NaN になる
printf("負の数の平方根は実数では定義されません(NaN)。\n");
} else {
double r = sqrt(x);
printf("sqrt(%.6f) = %.12f\n", x, r);
}
return 0;
}
実行結果例(入力に25を与えた場合):
数値を入力してください: sqrt(25.000000) = 5.000000000000
入力の検証を入れておくと、予期せぬ動作を防げます。
配列の各要素の平方根を計算する
配列内の値に対してまとめて平方根を適用する例です。
負の値は個別に扱います。
#include <stdio.h>
#include <math.h>
int main(void) {
// 混在するデータ(負の値も含む)
double data[] = {0.0, 1.0, 2.0, 4.0, 9.0, -3.0};
size_t n = sizeof(data) / sizeof(data[0]);
printf("元の値 -> 平方根\n");
for (size_t i = 0; i < n; ++i) {
double x = data[i];
if (x < 0.0) {
// 負の数は NaN(ここでは説明文字列を表示)
printf("%8.3f -> NaN(負)\n", x);
} else {
double r = sqrt(x);
printf("%8.3f -> % .12f\n", x, r);
}
}
return 0;
}
元の値 -> 平方根
0.000 -> 0.000000000000
1.000 -> 1.000000000000
2.000 -> 1.414213562373
4.000 -> 2.000000000000
9.000 -> 3.000000000000
-3.000 -> NaN(負)
データ前処理の段階で負値を除外するか、NaNを許容するかを設計しておくと、後段の処理が安定します。
まとめ
sqrtはC言語で平方根を求める基本中の基本ですが、正しく使うにはいくつかのポイントがあります。
math.hをインクルードし、Unix系では-lmを忘れないこと、引数と戻り値がdouble
であること、型に合わせてsqrtf
やsqrtl
を使い分けることが重要です。
負の数に対してはNaNが返るためisnan
での確認や入力検証を行い、浮動小数点の誤差と表示桁にも配慮しましょう。
実例(距離計算、入力処理、配列処理)のとおり、sqrtは現実の問題をシンプルに解く強力な道具です。
まずは小さなプログラムで動作を確かめ、必要な精度と安全性に合わせて使い方を磨いていってください。