C語言 math.h 徹底指南|主要函式、用法與實作範例

目次

1. 前言

math.h 是什麼?

C 語言有支援數學計算的標準函式庫 math.h。使用此函式庫即可執行三角函數、指數與對數計算、平方根、絕對值等各種數學運算。

math.h 的使用好處

  • 可用簡單的函式實作數學計算
  • 可輕鬆實作高精度計算
  • 作為標準函式庫,無需額外安裝

math.h 的引用方式

math.h 若要使用,請在程式開頭以如下方式寫入 #include 指令。
#include <stdio.h>
#include <math.h>
此外,若使用 math.h 的函式,需在編譯時加入 -lm 選項。例如,使用 GCC 時可如下編譯。
gcc program.c -o program -lm

math.h 的主要用途

math.h 可用於以下用途。
  1. 利用三角函數進行角度計算
  2. 利用指數與對數進行數值運算
  3. 平方根計算
  4. 數值的四捨五入處理
  5. 絕對值計算

2. 用途別 math.h 的主要函式

2.1 三角函式(角度的計算)

三角函式用於圓形與三角形的計算,並在物理模擬、圖形處理等廣泛領域中活用。

sin()cos()tan() 的概述

這些函式分別用於求取 正弦(sine)、餘弦(cosine)、正切(tangent)
#include <stdio.h>
#include <math.h>

int main() {
    double angle = 3.14159 / 4; // 45度(弧度)

    printf("sin(45°) = %f
", sin(angle));
    printf("cos(45°) = %f
", cos(angle));
    printf("tan(45°) = %f
", tan(angle));

    return 0;
}
執行結果
sin(45°) = 0.707107
cos(45°) = 0.707107
tan(45°) = 1.000000
注意事項
  • math.h 的三角函式以 弧度 為輸入。度單位的值使用時,需要 (角度 × π / 180) 的轉換。
double degrees = 45.0;
double radians = degrees * M_PI / 180.0;

2.2 反三角函式(求取角度)

反三角函式用於從給定的比例求取角度。

asin()acos()atan()atan2() 的概述

  • asin(x):返回 x 的反正弦(arc sine),範圍為(-π/2 ~ π/2)
  • acos(x):返回 x 的反餘弦(arc cosine),範圍為(0 ~ π)
  • atan(x):返回 x 的反正切(arc tangent),範圍為(-π/2 ~ π/2)
  • atan2(y, x):返回 y/x 的反正切(支援全部象限)
#include <stdio.h>
#include <math.h>

int main() {
    double value = 0.5;

    printf("asin(0.5) = %f 弧度
", asin(value));
    printf("acos(0.5) = %f 弧度
", acos(value));
    printf("atan(1.0) = %f 弧度
", atan(1.0));
    printf("atan2(1.0, 1.0) = %f 弧度
", atan2(1.0, 1.0));

    return 0;
}
注意事項
  • asin()acos() 的參數必須在 -1.01.0 之間。超出此範圍會返回 NaN(非數)。

2.3 指數與對數函式(指數計算與對數計算)

指數與對數的計算廣泛用於資料分析、統計、機器學習等。

exp()log()log10() 的概述

  • exp(x):計算 e^x
  • log(x):計算自然對數(ln x),底為 e
  • log10(x):計算常用對數(底 10)
#include <stdio.h>
#include <math.h>

int main() {
    double x = 2.0;

    printf("exp(2.0) = %f
", exp(x));
    printf("log(10.0) = %f
", log(10.0));
    printf("log10(100.0) = %f
", log10(100.0));

    return 0;
}
執行結果
exp(2.0) = 7.389056
log(10.0) = 2.302585
log10(100.0) = 2.000000
注意事項
  • log() 若傳入 ≤0 的值會返回 NaN(例如:log(0.0))。
  • exp(x) 若傳入過大值可能會 溢位

2.4 次方與平方根(數值運算)

次方與平方根的計算是許多數學演算法的基本處理。

pow()sqrt() 的概述

  • pow(x, y):計算 x^y(x 的 y 次方)
  • sqrt(x):計算 x 的平方根
#include <stdio.h>
#include <math.h>

int main() {
    double x = 9.0;

    printf("pow(2, 3) = %f
", pow(2.0, 3.0));
    printf("sqrt(9.0) = %f
", sqrt(x));

    return 0;
}
注意事項
  • pow(x, y) 若將 y 指定為 0.5 也可計算平方根(pow(9.0, 0.5) = 3.0)。
  • sqrt(x) 若傳入負值會返回 NaN

2.5 數值處理(四捨五入與絕對值)

數值四捨五入為整數或求取絕對值的函式,在金額計算與整數處理上很重要。

fabs()ceil()floor()round() 的概述

  • fabs(x):求取 x 的絕對值
  • ceil(x):將 x 向上取整(小數點以下進位)
  • floor(x):將 x 向下取整(小數點以下捨去)
  • round(x):將 x 四捨五入
#include <stdio.h>
#include <math.h>

int main() {
    double num = -5.7;

    printf("fabs(-5.7) = %f
", fabs(num));
    printf("ceil(-5.7) = %f
", ceil(num));
    printf("floor(-5.7) = %f
", floor(num));
    printf("round(-5.7) = %f
", round(num));

    return 0;
}
執行結果
fabs(-5.7) = 5.700000
ceil(-5.7) = -5.000000
floor(-5.7) = -6.000000
round(-5.7) = -6.000000

3. math.h 的使用方法與注意事項

3.1 使用 math.h 時的編譯選項

使用 math.h 時,許多 C 編譯器需要 明確鏈接數學函式庫(libm

GCC 的編譯方式

使用 GCC 時,如果未指定 -lm 選項,包含數學函式的程式將無法正確鏈接,可能會出現以下錯誤。
undefined reference to `sin'
為避免此問題,請如以下方式加入 -lm 選項進行編譯。
gcc program.c -o program -lm

Clang 與 MSVC 的情況

  • 在某些環境下,Clang 仍可能需要 -lm 選項。
  • 在 Microsoft Visual Studio(MSVC)中,即使未指定 -lm,也能使用 math.h 的函式。

3.2 浮點數精度與誤差的注意事項

math.h 中的數學函式使用 浮點運算(IEEE 754 標準),因此可能會產生精度誤差。

什麼是浮點誤差?

浮點數在內部以 近似值 表示,無法保持精確值。因此,計算結果可能會產生微小誤差。

誤差的具體例子

#include <stdio.h>
#include <math.h>

int main() {
    double x = 0.1;
    double y = 0.2;
    double z = 0.3;

    if ((x + y) == z) {
        printf("Equaln");
    } else {
        printf("Not Equaln");
    }

    return 0;
}
輸出
Not Equal
如此,會出現 0.1 + 0.2 無法嚴格等於 0.3 的情況。

考慮浮點誤差的比較

在考慮誤差時,會設定 閾值(epsilon) 來進行比較。
#include <stdio.h>
#include <math.h>

#define EPSILON 1e-9

int main() {
    double x = 0.1, y = 0.2, z = 0.3;

    if (fabs((x + y) - z) < EPSILON) {
        printf("Approximately Equaln");
    } else {
        printf("Not Equaln");
    }

    return 0;
}
輸出
Approximately Equal

3.3 math.h 的錯誤處理

math.h 的函式中,有些在傳入 無效參數 時會產生錯誤。此時需要適當處理錯誤。

錯誤發生的例子

  • sqrt(-1.0)NaN(非數)
  • log(0.0)-inf(負無限大)
  • 1.0 / 0.0inf(正無限大)

使用 errno 的錯誤處理

#include <stdio.h>
#include <math.h>
#include <errno.h>

int main() {
    errno = 0; // 重設 errno
    double result = sqrt(-1.0); 

    if (errno != 0) {
        perror("計算錯誤發生");
    } else {
        printf("結果: %fn", result);
    }

    return 0;
}
errno 的主要錯誤代碼
錯誤代碼意義
EDOM數學函式傳入無效值(例如: sqrt(-1.0))
ERANGE結果超出可表示的範圍(例如: exp(1000.0))

3.4 math.h 使用的最佳實踐

  • 編譯時加入 -lm 選項
  • 考慮浮點誤差,比較時使用閾值
  • 對於傳入的無效輸入值進行錯誤處理
  • 檢查避免發生溢位/下溢
  • 確認計算結果不是 NaNinf

4. FAQ(常見問題)

4.1 math.h 的函式發生錯誤時的處理方法?

問題範例

#include <stdio.h>
#include <math.h>

int main() {
    double result = sqrt(-1.0);
    printf("sqrt(-1.0) = %fn", result);
    return 0;
}
輸出
sqrt(-1.0) = nan
這樣,當求負數的平方根時,會返回 NaN(Not a Number)。

對策

  • 事先檢查輸入值,避免無效的值進入。
  • 利用 errno 來偵測錯誤
#include <stdio.h>
#include <math.h>
#include <errno.h>

int main() {
    errno = 0;
    double result = sqrt(-1.0);

    if (errno == EDOM) {
        printf("錯誤: 無效的輸入值n");
    } else {
        printf("sqrt(-1.0) = %fn", result);
    }

    return 0;
}

4.2 使用 math.h 時需要的編譯選項是什麼?

C 語言的 math.h 依賴於 數學函式庫(libm)。 因此,在使用 GCC 編譯時,需要加入 -lm 選項

編譯方法

gcc program.c -o program -lm

如果不指定選項會怎樣?

GCC 若未加 -lm 而使用 math.h 的函式,會出現以下 「undefined reference」錯誤
/tmp/ccxlj3hs.o: In function `main':
program.c:(.text+0x15): undefined reference to `sin'
collect2: error: ld returned 1 exit status

4.3 使用 math.h 的函式時的精度如何?

math.h 使用基於 IEEE 754 標準 的浮點數,運算精度有限。

問題範例

#include <stdio.h>
#include <math.h>

int main() {
    double x = 0.1, y = 0.2;
    double z = x + y;

    if (z == 0.3) {
        printf("等於n");
    } else {
        printf("不同n");
    }

    return 0;
}
輸出
不同

對策

浮點數比較時需要 考慮誤差容忍範圍(EPSILON)
#include <stdio.h>
#include <math.h>

#define EPSILON 1e-9

int main() {
    double x = 0.1, y = 0.2, z = 0.3;

    if (fabs((x + y) - z) < EPSILON) {
        printf("幾乎相等n");
    } else {
        printf("不同n");
    }

    return 0;
}
輸出
幾乎相等

4.4 math.h 的函式可以用於整數型嗎?

math.h 的函式假設以浮點型(double)作為參數。 因此,傳入整數時會 隱式轉換為 double

問題範例

#include <stdio.h>
#include <math.h>

int main() {
    int x = 4;
    printf("sqrt(4) = %fn", sqrt(x));
    return 0;
}

對策

透過明確的型別轉換,可防止意外的行為。
#include <stdio.h>
#include <math.h>

int main() {
    int x = 4;
    double result = sqrt((double)x); // 明確的型別轉換
    printf("sqrt(4) = %fn", result);
    return 0;
}

4.5 math.h 中有定義圓周率常數嗎?

C99 之後的標準在 math.h 中定義了圓周率(π)的常數 M_PI

使用範例

#include <stdio.h>
#include <math.h>

int main() {
    printf("π = %.15fn", M_PI);
    return 0;
}
輸出
π = 3.141592653589793

如果無法使用 M_PI

在某些編譯器或舊環境中,M_PI 可能未被定義。此時需要 自行定義
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif

5. math.h 的應用:實用範例

5.1 物理模擬中的應用

1. 物體的落下運動(自由落下的計算)

#include <stdio.h>
#include <math.h>

#define G 9.81  // 重力加速度

int main() {
    double time = 3.0;  // 3秒的落下
    double distance = 0.5 * G * pow(time, 2);

    printf("物體在 %.2f 秒後會落下 %.2f 公尺。n", time, distance);
    return 0;
}
輸出
物體在 3.00 秒後會落下 44.15 公尺。

5.2 統計分析中的應用

標準差的計算

#include <stdio.h>
#include <math.h>

double mean(double data[], int size) {
    double sum = 0.0;
    for (int i = 0; i < size; i++) {
        sum += data[i];
    }
    return sum / size;
}

double standardDeviation(double data[], int size) {
    double avg = mean(data, size);
    double sum = 0.0;
    for (int i = 0; i < size; i++) {
        sum += pow(data[i] - avg, 2);
    }
    return sqrt(sum / size);
}

int main() {
    double dataset[] = {10.0, 20.0, 30.0, 40.0, 50.0};
    int size = sizeof(dataset) / sizeof(dataset[0]);

    printf("標準差: %.2fn", standardDeviation(dataset, size));
    return 0;
}
輸出
標準差: 14.14

5.3 遊戲開發中的應用

2D 遊戲中的角色角度計算

#include <stdio.h>
#include <math.h>

int main() {
    double playerX = 1.0, playerY = 1.0;
    double enemyX = 4.0, enemyY = 5.0;

    double angle = atan2(enemyY - playerY, enemyX - playerX) * 180.0 / M_PI;

    printf("敵人的方向: %.2f 度n", angle);
    return 0;
}
輸出
敵人的方向: 45.00 度

3D 遊戲中的碰撞判定

#include <stdio.h>
#include <math.h>

int main() {
    double obj1[3] = {1.0, 2.0, 3.0};  // 物件1的座標
    double obj2[3] = {4.0, 6.0, 3.0};  // 物件2的座標
    double distance;

    distance = sqrt(pow(obj2[0] - obj1[0], 2) +
                    pow(obj2[1] - obj1[1], 2) +
                    pow(obj2[2] - obj1[2], 2));

    printf("物件間的距離: %.2fn", distance);
    return 0;
}
輸出
物件間的距離: 5.00

6. 總結

6.1 math.h 的主要要點

  1. math.h 的基礎
  • C 語言的標準函式庫,用於數學計算。
  • #include <math.h> 需要在程式的開頭宣告。
  1. 編譯時的注意事項
  • math.h 的函式若要使用,GCC 需要 -lm 選項。
   gcc program.c -o program -lm
  1. 依用途的主要函式
  • 三角函式(sin, cos, tan) → 角度計算
  • 反三角函式(asin, acos, atan, atan2) → 取得角度
  • 指數與對數(exp, log, log10) → 指數與對數運算
  • 冪次與平方根(pow, sqrt) → 冪次與平方根
  • 數值處理(fabs, ceil, floor, round) → 絕對值與四捨五入處理
  1. 精度與誤差的考量
  • math.h 的函式使用 浮點運算(IEEE 754 標準),因此會產生精度誤差。
   #define EPSILON 1e-9
   if (fabs(a - b) < EPSILON) { /* 判斷為幾乎相等 */ }
  1. 錯誤處理
  • 傳入無效的輸入(例如 sqrt(-1.0), log(0.0))可能會產生 NaNinf
   errno = 0;
   double result = sqrt(-1.0);
   if (errno != 0) {
       perror("錯誤發生");
   }
  1. 實用範例
  • 物理模擬 → 計算落體運動與拋射運動
  • 統計分析 → 計算標準差
  • 遊戲開發 → 敵人方向計算(atan2())與碰撞判定(sqrt()

6.2 math.h 學習參考連結

如果想更深入了解 math.h,建議利用以下資源。

6.3 最終學習步驟

  1. 嘗試基本函式
  • sqrt(), pow(), sin(), cos() 等函式,製作簡單的程式。
  1. 撰寫考慮錯誤處理的程式碼
  • 利用 errno 了解無效輸入時的行為。
  1. 製作實用程式
  • 在遊戲開發、資料分析等具體專案中活用 math.h。

最終總結

math.h 作為 C 語言的標準函式庫,提供許多數學函式。了解正確的使用方式,並考慮精度誤差與錯誤處理,即可 更安全且精確地執行數學運算。請在實際程式中活用 math.h,挑戰更高階的 C 程式設計。
年収訴求