一元二次方程:y = a * x^2 + b * x + c,曲线类似下面这样。
用途:仪器参数校准、轨迹预测、数据生成。
多个点,使用最小二乘法拟合二次函数方程:
go
root@iZwz99zhkxxl5h6ecbm2xwZ:~/temp# cat main.go
package main
import (
"fmt"
"math"
)
func main() {
// 输入多个离散点的坐标
x := []float64{1.8, 2, 3}
y := []float64{2, 3, 5.5}
// 计算所需的统计量
n := float64(len(x))
sumX := 0.0
sumX2 := 0.0
sumX3 := 0.0
sumX4 := 0.0
sumY := 0.0
sumXY := 0.0
sumX2Y := 0.0
for i := 0; i < len(x); i++ {
sumX += x[i]
sumX2 += math.Pow(x[i], 2)
sumX3 += math.Pow(x[i], 3)
sumX4 += math.Pow(x[i], 4)
sumY += y[i]
sumXY += x[i] * y[i]
sumX2Y += math.Pow(x[i], 2) * y[i]
}
// 构建方程组的系数矩阵 A 和向量 b
A := [][]float64{
{n, sumX, sumX2},
{sumX, sumX2, sumX3},
{sumX2, sumX3, sumX4},
}
b := []float64{sumY, sumXY, sumX2Y}
// 求解线性方程组 Ax = b
coeffs := gaussianElimination(A, b)
// 交换 coeffs[0] 和 coeffs[2] 的值
coeffs[0], coeffs[2] = coeffs[2], coeffs[0]
// 输出拟合得到的一元二次方程的系数
// 注意 coeffs[0] 是 a, coeffs[1] 是 b, coeffs[2] 是 c
fmt.Printf("一元二次方程的拟合结果: y = %.2fx^2 + %.2fx + %.2f\n", coeffs[0], coeffs[1], coeffs[2])
// 验证计算结果
for i := 0; i < len(x); i++ {
expectedY := coeffs[0]*math.Pow(x[i], 2) + coeffs[1]*x[i] + coeffs[2]
fmt.Printf("x = %.2f, expected y = %.2f, actual y = %.2f\n", x[i], expectedY, y[i])
}
}
// gaussianElimination 函数使用高斯消元法求解线性方程组 Ax = b
func gaussianElimination(A [][]float64, b []float64) []float64 {
n := len(A)
augmented := make([][]float64, n)
for i := 0; i < n; i++ {
augmented[i] = make([]float64, n+1)
copy(augmented[i], A[i])
augmented[i][n] = b[i]
}
// 前向消元
for i := 0; i < n; i++ {
// 部分主元法,找到最大元素并交换行
maxRow := i
for j := i + 1; j < n; j++ {
if math.Abs(augmented[j][i]) > math.Abs(augmented[maxRow][i]) {
maxRow = j
}
}
augmented[i], augmented[maxRow] = augmented[maxRow], augmented[i]
for j := i + 1; j < n; j++ {
factor := augmented[j][i] / augmented[i][i]
for k := i; k <= n; k++ {
augmented[j][k] -= factor * augmented[i][k]
}
}
}
// 回代求解
coeffs := make([]float64, n)
for i := n - 1; i >= 0; i-- {
coeffs[i] = augmented[i][n]
for j := i + 1; j < n; j++ {
coeffs[i] -= augmented[i][j] * coeffs[j]
}
coeffs[i] /= augmented[i][i]
}
return coeffs
}
func printMatrix(matrix [][]float64) {
for i := 0; i < len(matrix); i++ {
for j := 0; j < len(matrix[0]); j++ {
fmt.Printf("%.2f ", matrix[i][j])
}
fmt.Println()
}
}
root@iZwz99zhkxxl5h6ecbm2xwZ:~/temp# go run main.go
一元二次方程的拟合结果: y = -2.08x^2 + 12.92x + -14.50
x = 1.80, expected y = 2.00, actual y = 2.00
x = 2.00, expected y = 3.00, actual y = 3.00
x = 3.00, expected y = 5.50, actual y = 5.50
root@iZwz99zhkxxl5h6ecbm2xwZ:~/temp#
三个点,唯一确定1个一元二次方程:
go
root@iZwz99zhkxxl5h6ecbm2xwZ:~/temp/zz# cat main.go
package main
import (
"fmt"
"math"
)
func main() {
// 输入三个点的坐标
x1, y1 := 1.8, 2.0
x2, y2 := 2.0, 3.0
x3, y3 := 3.0, 5.5
// 计算方程组的系数矩阵的行列式和替换列后的行列式
detA := determinant([][]float64{
{x1 * x1, x1, 1},
{x2 * x2, x2, 1},
{x3 * x3, x3, 1},
})
detA1 := determinant([][]float64{
{y1, x1, 1},
{y2, x2, 1},
{y3, x3, 1},
})
detA2 := determinant([][]float64{
{x1 * x1, y1, 1},
{x2 * x2, y2, 1},
{x3 * x3, y3, 1},
})
detA3 := determinant([][]float64{
{x1 * x1, x1, y1},
{x2 * x2, x2, y2},
{x3 * x3, x3, y3},
})
// 求解 a, b, c
a := detA1 / detA
b := detA2 / detA
c := detA3 / detA
fmt.Printf("二次曲线的方程为: y = %.2fx^2 + %.2fx + %.2f\n", a, b, c)
}
// determinant 函数用于计算矩阵的行列式
func determinant(A [][]float64) float64 {
if len(A) == 2 {
return A[0][0]*A[1][1] - A[0][1]*A[1][0]
}
det := 0.0
for i := 0; i < len(A); i++ {
minor := minorMatrix(A, 0, i)
det += A[0][i] * math.Pow(-1, float64(i)) * determinant(minor)
}
return det
}
// minorMatrix 函数用于计算矩阵 A 去掉第 r 行第 c 列后的子矩阵
func minorMatrix(A [][]float64, r int, c int) [][]float64 {
minor := make([][]float64, len(A)-1)
for i := 0; i < len(A)-1; i++ {
minor[i] = make([]float64, len(A)-1)
}
for i := 0; i < len(A); i++ {
if i < r {
for j := 0; j < len(A); j++ {
if j < c {
minor[i][j] = A[i][j]
} else if j > c {
minor[i][j-1] = A[i][j]
}
}
} else if i > r {
for j := 0; j < len(A); j++ {
if j < c {
minor[i-1][j] = A[i][j]
} else if j > c {
minor[i-1][j-1] = A[i][j]
}
}
}
}
return minor
}
root@iZwz99zhkxxl5h6ecbm2xwZ:~/temp/zz# go run main.go
二次曲线的方程为: y = -2.08x^2 + 12.92x + -14.50
root@iZwz99zhkxxl5h6ecbm2xwZ:~/temp/zz#