数学工具
1、标量数值计算工具类
包含 IntMath、LongMath、BigIntegerMath 和 DoubleMath,重点解决数值溢出、精确舍入和数论计算。
1.1、核心API
| 类名 | 特有/核心 API | 说明 |
|---|---|---|
| IntMath / LongMath | checkedAdd / checkedMultiply … | 溢出检查:发生溢出时直接抛出 ArithmeticException |
saturatingAdd / saturatingMultiply | 饱和算术:溢出时返回 MAX_VALUE 或 MIN_VALUE,不抛异常 | |
divide(a, b, RoundingMode) | 指定舍入模式的整数除法,避免转换为 double 导致的精度丢失 | |
log2 / log10 / sqrt | 结合 RoundingMode 计算对数和开平方根 | |
factorial(n) / binomial(n, k) | 阶乘与组合数 C n k C_n^k Cnk 计算(自动内部优化) | |
gcd(a, b) / mod(x, m) | 计算最大公约数;mod 保证返回非负结果(区别于 % 运算符) | |
| BigIntegerMath | divide, log2, log10, sqrt, factorial | 针对大整数的对数、平方根与阶乘,支持 RoundingMode |
| DoubleMath | isMathematicalInteger(x) | 判断 double 值是否为无小数部分的数学整数(如 3.0) |
| roundToInt / roundToLong | 安全地将 double 按指定舍入模式转为整数 |
1.2、使用示例
import com.google.common.math.BigIntegerMath;
import com.google.common.math.IntMath;
import com.google.common.math.DoubleMath;
import java.math.BigInteger;
import java.math.RoundingMode;
public class ScalarMathExample {
public static void main(String[] args) {
// 饱和加法:Integer.MAX_VALUE + 100 -> Integer.MAX_VALUE
int saturated = IntMath.saturatingAdd(Integer.MAX_VALUE, 100);
// 整数除法向上取整:10 / 4 -> 3
int divCeil = IntMath.divide(10, 4, RoundingMode.CEILING);
// 大整数开平方根向下取整
BigInteger bigNum = new BigInteger("1000000000000000000000000");
BigInteger sqrtVal = BigIntegerMath.sqrt(bigNum, RoundingMode.FLOOR);
// 双精度转整数(四舍五入)
int roundedInt = DoubleMath.roundToInt(3.5, RoundingMode.HALF_UP); // 4
}
}
2、单变量统计分析(Stats & StatsAccumulator)
用于计算数据的均值、方差、标准差和极值。提供不可变的 Stats 和可变的流式累加器 StatsAccumulator。
2.1、核心API
| 方法名 | 返回值 / 说明 |
|---|---|
count() / sum() | 数据总量 / 总和 |
mean() | 算术平均值 |
min() / max() | 最小值 / 最大值 |
populationVariance() / sampleVariance() | 总体方差 / 样本方差 |
populationStandardDeviation() | 总体标准差 σ \sigma σ |
sampleStandardDeviation() | 样本标准差 s s s |
2.2、使用示例
import com.google.common.math.Stats;
import com.google.common.math.StatsAccumulator;
public class StatsExample {
public static void main(String[] args) {
// 1. 静态一次性计算
Stats stats = Stats.of(1.0, 2.0, 3.0, 4.0, 5.0);
System.out.println("均值: " + stats.mean() + ", 标准差: " + stats.populationStandardDeviation());
// 2. 流式动态累加 (适合处理数据流)
StatsAccumulator accumulator = new StatsAccumulator();
accumulator.add(10.5);
accumulator.addAll(20.1, 30.4);
// 导出不可变的 Stats 统计快照
Stats snapshot = accumulator.snapshot();
System.out.println("数据量: " + snapshot.count() + ", 最小值: " + snapshot.min());
}
}
均值: 3.0, 标准差: 1.4142135623730951
数据量: 3, 最小值: 10.5
3、双变量统计与回归(PairedStats & PairedStatsAccumulator)
用于分析两组成对数据 ( x , y ) (x, y) (x,y) 之间的相关性、协方差及最小二乘法拟合直线。
3.1、核心API
| 方法名 | 说明 |
|---|---|
populationCovariance() / sampleCovariance() | 计算总体/样本协方差 |
pearsonsCorrelationCoefficient() | 计算皮尔逊相关系数 r ∈ [ − 1 , 1 ] r \in [-1, 1] r∈[−1,1] |
leastSquaresFit() | 计算拟合直线,返回 LinearTransformation 对象 |
xStats() / yStats() | 提取
x
x
x 轴或
y
y
y 轴独立的 Stats 对象 |
3.2、使用示例
import com.google.common.math.LinearTransformation;
import com.google.common.math.PairedStats;
import com.google.common.math.PairedStatsAccumulator;
public class PairedStatsDemo {
public static void main(String[] args) {
// 1. 创建累加器并添加数据点 (x, y)
PairedStatsAccumulator accumulator = new PairedStatsAccumulator();
accumulator.add(1.0, 2.1);
accumulator.add(2.0, 3.9);
accumulator.add(3.0, 6.1);
accumulator.add(4.0, 8.0);
accumulator.add(5.0, 9.8);
// 2. 计算统计指标
System.out.println("数据点数量: " + accumulator.count()); // 5
System.out.println("X 的均值: " + accumulator.xStats().mean()); // 3.0
System.out.println("样本协方差: " + accumulator.sampleCovariance());
System.out.println("皮尔逊相关系数: " + accumulator.pearsonsCorrelationCoefficient());
// 3. 线性回归拟合 (y = slope * x + intercept)
LinearTransformation fit = accumulator.leastSquaresFit();
System.out.println("斜率 (Slope): " + fit.slope());
System.out.println("Y轴截距 (Intercept): " + fit.transform(0.0)); // x=0 时求 y
// 4. 使用拟合直线进行预测
double predictedY = fit.transform(6.0); // 预测 x = 6 时 y 的值
System.out.println("预测 x=6 时的 y 值: " + predictedY);
// 5. 生成不可变快照
PairedStats snapshot = accumulator.snapshot();
// snapshot 可以在多线程间安全共享或返回给调用方
}
}
4、线性变换(LinearTransformation)
Guava(com.google.common.math)中的 LinearTransformation 表示一个一元线性变换(或二维平面上的直线),形式通常为 y = m ⋅ x + b y = m \cdot x + b y=m⋅x+b 或垂直线 x = c x = c x=c。
它主要配合 PairedStats / PairedStatsAccumulator 的 leastSquaresFit()(最小二乘法回归)使用,也可以独立用来构建和执行线性映射(如单位转换、温度转换等)。
4.1、核心API
LinearTransformation 是一个抽象类,提供了多个静态工厂方法来创建不同类型的线性变换,并提供了用于变换和查询属性的实例方法。
1. 创建变换(工厂方法)
| 方法形式/含义 | 说明 |
|---|---|
forPointAndSlope(double x1, double y1, double slope) | 点斜式 y − y 1 = m ( x − x 1 ) y - y_1 = m(x - x_1) y−y1=m(x−x1):给定直线上一点及斜率 |
mapping(double x1, double y1, double x2, double y2) | 两点式:给定直线上不同的两个点 |
vertical(double x) | 垂直线 x = c x = c x=c:斜率为无穷大,适用于所有点 x x x 坐标相同的情况 |
horizontal(double y) | 水平线 y = c y = c y=c:斜率为 0 |
identity() | 恒等变换 y = x y = x y=x:斜率为 1,截距为 0 |
2. 变换计算(实例方法)
| 方法 | 返回值 | 说明 |
|---|---|---|
transform(double x) | double | 根据 x x x 计算对应的 y y y 值(垂直线调用会抛出异常) |
inverse() | LinearTransformation | 返回反函数/逆变换(如原函数为 y = 2 x y=2x y=2x,逆函数为 x = 0.5 y x=0.5y x=0.5y;水平线求逆会变为垂直线) |
3. 属性查询(实例方法)
| 方法 | 返回值 | 说明 |
|---|---|---|
isVertical() | boolean | 是否为垂直线 |
isHorizontal() | boolean | 是否为水平线 |
slope() | double | 获取斜率
m
m
m(若为垂直线会抛出 IllegalStateException) |
4.2、使用示例
示例 1:温度单位转换(摄氏度 ↔ 华氏度)
线性变换非常适合处理公式转换,例如: F = 1.8 ⋅ C + 32 F = 1.8 \cdot C + 32 F=1.8⋅C+32。
import com.google.common.math.LinearTransformation;
public class TemperatureConverter {
public static void main(String[] args) {
// 1. 通过已知两点构建转换关系:
// 冰点 (0°C, 32°F),沸点 (100°C, 212°F)
LinearTransformation celsiusToFahrenheit = LinearTransformation.mapping(0, 32).and(100, 212);
// 2. 摄氏度转华氏度 (y = 1.8 * x + 32)
double c = 25.0;
double f = celsiusToFahrenheit.transform(c);
System.out.println(c + " °C = " + f + " °F"); // 25.0 °C = 77.0 °F
System.out.println("斜率 (Slope): " + celsiusToFahrenheit.slope()); // 1.8
// 3. 获取逆变换(华氏度转摄氏度)
LinearTransformation fahrenheitToCelsius = celsiusToFahrenheit.inverse();
double backToC = fahrenheitToCelsius.transform(77.0);
System.out.println("77.0 °F = " + backToC + " °C"); // 77.0 °F = 25.0 °C
}
}
25.0 °C = 77.0 °F
斜率 (Slope): 1.8
77.0 °F = 25.0 °C
示例 2:结合回归分析预测数据
结合 PairedStatsAccumulator 拟合线性模型并进行数据预测:
import com.google.common.math.LinearTransformation;
import com.google.common.math.PairedStatsAccumulator;
public class RegressionPredictionDemo {
public static void main(String[] args) {
PairedStatsAccumulator stats = new PairedStatsAccumulator();
// 添加样本数据 (工作年限 x, 年薪/万元 y)
stats.add(1.0, 5.0);
stats.add(2.0, 6.2);
stats.add(3.0, 7.8);
stats.add(4.0, 9.1);
// 最小二乘法拟合直线
LinearTransformation fit = stats.leastSquaresFit();
if (fit.isVertical()) {
System.out.println("数据点分布在同一垂直线上,无法进行常规线性回归!");
} else {
System.out.printf("拟合回归方程: y = %.2fx + %.2f%n", fit.slope(), fit.transform(0));
// 预测工作 6 年时的薪资
double years = 6.0;
double predictedSalary = fit.transform(years);
System.out.printf("预测工作 %.1f 年后的薪资为: %.2f 万元%n", years, predictedSalary);
}
}
}
5、分位数计算(Quantiles)
Guava(com.google.common.math 包)中的 Quantiles 是一个专门用于高效计算数据流或数组中分位数(如中位数 Median、四分位数 Quartiles、百分位数 Percentiles 等)的工具类。
它采用了选择算法(基于 Quickselect 的算法变体),可以在 O ( N ) O(N) O(N) 平均时间复杂度内直接在输入数组上完成计算,无需对整个数据集进行完整的 O ( N log N ) O(N \log N) O(NlogN) 排序。
5.1、核心API
Quantiles 采用了 Fluent API(流式接口) 结构,按照以下三步来完成计算:
- 指定分位数切分粒度:例如 median()(中位数/二分)、quartiles()(四分位/4分)、percentiles()(百分位/100分)、indexes(k)(自定义 k k k 等分)。
- 选择要计算的具体位置:如四分位数中的第 1 和第 3 个切点(即 Q1 和 Q3)。
- 传入数据源计算:支持 double[]、long[]、int[] 数组或 Collection<? extends Number> 集合。
5.2、使用示例
1. 计算单个分位数(中位数、百分位数等)
使用 index() 指定计算某一个具体的分位数,返回单个 double 值。
import com.google.common.math.Quantiles;
import java.util.Arrays;
import java.util.List;
public class QuantilesSingleDemo {
public static void main(String[] args) {
List<Double> data = Arrays.asList(6.0, 1.0, 2.0, 3.0, 4.0, 5.0, 7.0, 8.0, 9.0);
// 1. 计算中位数 (Median)
double median = Quantiles.median().compute(data);
System.out.println("中位数: " + median); // 5.0
// 2. 计算第 90 百分位数 (P90)
double p90 = Quantiles.percentiles().index(90).compute(data);
System.out.println("P90: " + p90); // 8.2
// 3. 自定义切分:将数据切分为 5 等份 (Quintiles),计算第 3 个切点 (60%)
double quintile3 = Quantiles.scale(5).index(3).compute(data);
System.out.println("第3个五分位数: " + quintile3); // 5.8
}
}
中位数: 5.0
P90: 8.2
第3个五分位数: 5.8
2. 批量计算多个分位数
如果需要同时求多个分位数(例如箱线图所需的 Q1, Q2, Q3),使用 indexes() 一次性计算效率更高(算法会复用已划好的分区)。返回结果为 Map<Integer, Double>,Key 为对应切点的索引号。
import com.google.common.math.Quantiles;
import java.util.Map;
public class QuantilesBatchDemo {
public static void main(String[] args) {
double[] data = {12.0, 3.0, 5.0, 7.0, 11.0, 13.0, 17.0, 19.0, 23.0, 29.0};
// 1. 批量计算四分位数 (Q1=第1切点, Q2=第2切点/中位数, Q3=第3切点)
Map<Integer, Double> quartiles = Quantiles.quartiles()
.indexes(1, 2, 3)
.compute(data);
System.out.println("Q1 (25%): " + quartiles.get(1));
System.out.println("Q2 (50%): " + quartiles.get(2));
System.out.println("Q3 (75%): " + quartiles.get(3));
// 2. 批量获取 P50, P90, P99(常用于系统延迟指标耗时分析)
Map<Integer, Double> latencies = Quantiles.percentiles()
.indexes(50, 90, 99)
.compute(data);
System.out.println("P50: " + latencies.get(50));
System.out.println("P90: " + latencies.get(90));
System.out.println("P99: " + latencies.get(99));
}
}
Q1 (25%): 8.0
Q2 (50%): 12.5
Q3 (75%): 18.5
P50: 12.5
P90: 23.6
P99: 28.46
5.3、主要切分粒度(Scale)方法对比
| 方法 | 切份数 (k 等分) | 索引范围 | 常见用途 |
|---|---|---|---|
median() | 2 | 固定的切点 1 | 中位数 |
quartiles() | 4 | 1, 2, 3 | 箱线图分析 (Q1, Q2, Q3) |
percentiles() | 100 | 1 到 99 | 系统 P90 / P95 / P99 延迟响应指标 |
scale(k) | k k k | 1 到 k − 1 k-1 k−1 | 任意 k k k 等分计算 |

783

被折叠的 条评论
为什么被折叠?



