golang实现一元二次方程

一元二次方程: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#
相关推荐
java熊猫31 分钟前
CSS语言的网络编程
开发语言·后端·golang
生活很暖很治愈34 分钟前
C语言之旅5--分支与循环【2】
c语言·开发语言
Xudde.1 小时前
HTML中meta的用法
java·前端·javascript·笔记·html
nece0011 小时前
PHP的扩展Imagick的安装
开发语言·php
Panda-gallery1 小时前
【Rust】常见集合
开发语言·后端·rust
陈序缘1 小时前
Rust实现智能助手 - 项目初始化
开发语言·后端·语言模型·rust
KeyPan1 小时前
【Ubuntu与Linux操作系统:十二、LAMP平台与PHP开发环境】
android·java·linux·运维·服务器·ubuntu
timer_0171 小时前
Rust 1.84.0 发布
开发语言·后端·rust
落霞的思绪2 小时前
苍穹外卖08——(涉及接收日期格式数据、ApachePOI导出报表、sql获取top10菜品数据)
java·spring boot·后端·mybatis·苍穹外卖
morning_judger2 小时前
【Python学习系列】数据类型(二)
开发语言·python·学习