2025-11-17 11:49:31 +08:00
|
|
|
|
package com.gunshi.project.hsz.model;
|
|
|
|
|
|
|
|
|
|
|
|
import lombok.Data;
|
|
|
|
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
2025-11-18 16:26:32 +08:00
|
|
|
|
import java.math.RoundingMode;
|
2025-11-17 11:49:31 +08:00
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 线性回归方程实体类
|
|
|
|
|
|
*/
|
|
|
|
|
|
@Data
|
|
|
|
|
|
public class RegressionEquation {
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 方程阶数
|
|
|
|
|
|
*/
|
|
|
|
|
|
private int order;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 方程系数(从常数项到最高次项)
|
|
|
|
|
|
* 例如:对于二次方程 y = ax² + bx + c,coefficients = [c, b, a]
|
|
|
|
|
|
*/
|
|
|
|
|
|
private List<BigDecimal> coefficients;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 相关系数 R²
|
|
|
|
|
|
*/
|
|
|
|
|
|
private BigDecimal rSquared;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 数据点数
|
|
|
|
|
|
*/
|
|
|
|
|
|
private int dataCount;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* 方程字符串表示
|
|
|
|
|
|
*/
|
|
|
|
|
|
private String equationString;
|
|
|
|
|
|
|
|
|
|
|
|
public RegressionEquation(int order, List<BigDecimal> coefficients, BigDecimal rSquared, int dataCount) {
|
|
|
|
|
|
this.order = order;
|
|
|
|
|
|
this.coefficients = coefficients;
|
|
|
|
|
|
this.rSquared = rSquared;
|
|
|
|
|
|
this.dataCount = dataCount;
|
|
|
|
|
|
this.equationString = generateEquationString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2025-11-18 16:26:32 +08:00
|
|
|
|
* 生成方程字符串(使用数学符号)
|
2025-11-17 11:49:31 +08:00
|
|
|
|
*/
|
|
|
|
|
|
private String generateEquationString() {
|
|
|
|
|
|
StringBuilder sb = new StringBuilder("y = ");
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = coefficients.size() - 1; i >= 0; i--) {
|
|
|
|
|
|
BigDecimal coeff = coefficients.get(i);
|
|
|
|
|
|
if (coeff.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 符号处理
|
|
|
|
|
|
if (sb.length() > 4 && coeff.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
|
sb.append(" + ");
|
|
|
|
|
|
} else if (sb.length() > 4 && coeff.compareTo(BigDecimal.ZERO) < 0) {
|
|
|
|
|
|
sb.append(" - ");
|
|
|
|
|
|
coeff = coeff.abs();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 16:26:32 +08:00
|
|
|
|
// 系数和变量 - 保留至少20位小数
|
2025-11-17 11:49:31 +08:00
|
|
|
|
if (i == 0) {
|
2025-11-18 16:26:32 +08:00
|
|
|
|
// 常数项 - 保留至少20位小数
|
|
|
|
|
|
sb.append(coeff.setScale(20, RoundingMode.HALF_UP).toPlainString());
|
2025-11-17 11:49:31 +08:00
|
|
|
|
} else {
|
2025-11-18 16:26:32 +08:00
|
|
|
|
// 非常数项 - 保留至少20位小数
|
2025-11-17 11:49:31 +08:00
|
|
|
|
if (coeff.compareTo(BigDecimal.ONE) != 0 && coeff.compareTo(BigDecimal.ONE.negate()) != 0) {
|
2025-11-18 16:26:32 +08:00
|
|
|
|
sb.append(coeff.setScale(20, RoundingMode.HALF_UP).toPlainString());
|
2025-11-17 11:49:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
sb.append("x");
|
|
|
|
|
|
if (i > 1) {
|
2025-11-18 16:26:32 +08:00
|
|
|
|
// 使用Unicode上标数字
|
|
|
|
|
|
sb.append(getSuperscript(i));
|
2025-11-17 11:49:31 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-18 16:26:32 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 获取数字的Unicode上标表示
|
|
|
|
|
|
*/
|
|
|
|
|
|
private String getSuperscript(int number) {
|
|
|
|
|
|
String numStr = String.valueOf(number);
|
|
|
|
|
|
StringBuilder superscript = new StringBuilder();
|
|
|
|
|
|
for (char c : numStr.toCharArray()) {
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
|
case '0': superscript.append('⁰'); break;
|
|
|
|
|
|
case '1': superscript.append('¹'); break;
|
|
|
|
|
|
case '2': superscript.append('²'); break;
|
|
|
|
|
|
case '3': superscript.append('³'); break;
|
|
|
|
|
|
case '4': superscript.append('⁴'); break;
|
|
|
|
|
|
case '5': superscript.append('⁵'); break;
|
|
|
|
|
|
case '6': superscript.append('⁶'); break;
|
|
|
|
|
|
case '7': superscript.append('⁷'); break;
|
|
|
|
|
|
case '8': superscript.append('⁸'); break;
|
|
|
|
|
|
case '9': superscript.append('⁹'); break;
|
|
|
|
|
|
default: superscript.append(c);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return superscript.toString();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-17 11:49:31 +08:00
|
|
|
|
/**
|
|
|
|
|
|
* 根据x值预测y值
|
|
|
|
|
|
*/
|
|
|
|
|
|
public BigDecimal predict(BigDecimal x) {
|
|
|
|
|
|
BigDecimal result = BigDecimal.ZERO;
|
|
|
|
|
|
BigDecimal xPower = BigDecimal.ONE;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < coefficients.size(); i++) {
|
|
|
|
|
|
result = result.add(coefficients.get(i).multiply(xPower));
|
|
|
|
|
|
xPower = xPower.multiply(x);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
|
public String toString() {
|
|
|
|
|
|
return String.format("%s", equationString);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|