求解任意大小的線性方程組 Ax = b,其中 A 為 n × n 方陣,n > 10。需在 C/C++ 中實作數值穩定、效能良好的演算法。
針對中小型稠密矩陣 (n < 500),部分樞軸高斯消去法 是最標準、易實作且數值穩定的選擇。核心步驟:
[A|b] 轉為上三角形式,每列選擇當前欄絕對值最大的行作為樞軸列交換。#include
#include
#include
#include
using Matrix = std::vector>;
using Vector = std::vector;
/**
* 部分樞軸高斯消去法求解 Ax = b
* @param A 係數矩陣 (n x n),函數內部會被修改
* @param b 常數向量 (n),函數內部會被修改
* @return 解向量 x
* @throws std::runtime_error 矩陣奇異或接近奇異
*/
Vector gaussianElimination(Matrix& A, Vector& b) {
const size_t n = A.size();
if (n == 0 || A[0].size() != n || b.size() != n)
throw std::invalid_argument("矩陣維度不匹配");
const double EPS = 1e-12;
// 前向消去
for (size_t col = 0; col < n; ++col) {
// 1. 部分樞軸:尋找當前欄絕對值最大的行
size_t pivotRow = col;
double maxVal = std::abs(A[col][col]);
for (size_t row = col + 1; row < n; ++row) {
if (std::abs(A[row][col]) > maxVal) {
maxVal = std::abs(A[row][col]);
pivotRow = row;
}
}
// 2. 檢查奇異性
if (maxVal < EPS)
throw std::runtime_error("矩陣奇異或接近奇異,無法求解");
// 3. 交換行 (係數矩陣與常數向量同步交換)
if (pivotRow != col) {
std::swap(A[pivotRow], A[col]);
std::swap(b[pivotRow], b[col]);
}
// 4. 消去下方行
for (size_t row = col + 1; row < n; ++row) {
double factor = A[row][col] / A[col][col];
for (size_t c = col; c < n; ++c)
A[row][c] -= factor * A[col][c];
b[row] -= factor * b[col];
}
}
// 回代
Vector x(n);
for (int i = n - 1; i >= 0; --i) {
double sum = b[i];
for (size_t j = i + 1; j < n; ++j)
sum -= A[i][j] * x[j];
x[i] = sum / A[i][i];
}
return x;
}
// 測試主程式
int main() {
// 範例:3x3 系統,實際使用時替換為 n>10 的資料
Matrix A = {{2, 1, -1}, {-3, -1, 2}, {-2, 1, 2}};
Vector b = {8, -11, -3};
try {
Vector x = gaussianElimination(A, b);
std::cout << "解向量 x:\n";
for (size_t i = 0; i < x.size(); ++i)
std::cout << "x[" << i << "] = " << x[i] << '\n';
} catch (const std::exception& e) {
std::cerr << "錯誤: " << e.what() << '\n';
}
return 0;
}
將 A = LU (L 下三角、U 上三角),一次分解、多次前向/回代求解,複雜度從 O(n³) 降為 O(n²) per 右手邊。
std::vector A(n*n) 取代 vector> ,提升快取命中率。dgesv 例程,效能可提升 10-100 倍。若矩陣非零元素佔比 < 10%,請改用 疏矩陣直接法 (如 SuiteSparse/UMFPACK) 或 反覆法 (CG, GMRES)。
double 再計算,避免整數除法截斷。