閉じる

【C言語】 sqrtの使い方(math.h) 平方根の計算と注意点

平方根の計算は、距離や幾何、統計など幅広い分野で欠かせません。

C言語ではsqrt(math.h)が標準で用意されており、正しくインクルードし、必要に応じてリンク設定を行えばすぐに使えます。

この記事ではsqrtの基礎から注意点、実用的な例まで、初心者の方にもわかりやすく解説します。

sqrtとは

平方根を求める標準関数

sqrtは、与えた数の主値の平方根を返すC標準ライブラリの関数です。

非負の数<x>に対してsqrt(x)は「y≥0 かつ y*y = x」を満たす値になります。

Cでは#include <math.h>で宣言が提供されます。

以下は代表的なプロトタイプです。

C言語
// 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書式
floatsqrtffloat sqrtf(float x);%f
doublesqrtdouble sqrt(double x);%f
long doublesqrtllong double sqrtl(long double x);%Lf

簡単な比較コードです。

C言語
#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>も一緒に使います。

C言語
#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を付ける点が重要です。

Shell
# 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は不要です。
Shell
cl /std:c11 /W4 main.c
  • MinGW系(GCC): Unix系と同様に-lmが必要です。
Shell
gcc -std=c11 -Wall -Wextra main.c -lm -o run.exe

ビルドが通らない時は、オプションの有無や順序を見直すと解決することが多いです。

呼び出しの基本

sqrtは引数に数値を渡すだけのシンプルな関数です。

書式指定子で桁数を調整すると、誤差や見やすさをコントロールできます。

C言語
#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

等値比較(==)ではなく、許容誤差内で比較するのが実践的です(誤差については後述)。

整数との併用

整数を渡すのは問題ありませんが、結果を整数に代入する時の丸めに注意が必要です。

C言語
#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でチェックできます。

環境によってはerrnoEDOMが設定されたり、浮動小数点例外FE_INVALIDが発生する場合があります。

C言語
#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.0sqrt(4.0) == 2.0のように期待通りの結果が得られます。

IEEE 754準拠の環境ではsqrt(INFINITY) == INFINITYとなります。

C言語
#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にならないことがあります。

C言語
#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)で求められます。

C言語
#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

距離計算はゲーム開発や幾何アルゴリズムの基本で、平方根の代表的な応用です。

入力値の平方根を表示する

ユーザーから数値を受け取り、負の数はエラーメッセージ、非負なら平方根を表示する例です。

C言語
#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

入力の検証を入れておくと、予期せぬ動作を防げます。

配列の各要素の平方根を計算する

配列内の値に対してまとめて平方根を適用する例です。

負の値は個別に扱います。

C言語
#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であること、型に合わせてsqrtfsqrtlを使い分けることが重要です。

負の数に対してはNaNが返るためisnanでの確認や入力検証を行い、浮動小数点の誤差と表示桁にも配慮しましょう。

実例(距離計算、入力処理、配列処理)のとおり、sqrtは現実の問題をシンプルに解く強力な道具です。

まずは小さなプログラムで動作を確かめ、必要な精度と安全性に合わせて使い方を磨いていってください。

この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!