
本文介绍如何在 javascript 中实现通用的算术-几何平均(agm)单步迭代函数,支持任意长度的正实数数组,通过位运算高效生成初等对称多项式并按阶归一化。
本文介绍如何在 javascript 中实现通用的算术-几何平均(agm)单步迭代函数,支持任意长度的正实数数组,通过位运算高效生成初等对称多项式并按阶归一化。
算术-几何平均(AGM)的经典定义针对两个数:反复交替计算算术平均与几何平均,序列收敛于同一极限。其高维推广基于初等对称多项式(Elementary Symmetric Polynomials, ESP):对长度为 $ n $ 的正实数数组 $ [x_0, x1, \dots, x{n-1}] $,第 $ k $ 个 AGM 分量($ k = 0, 1, \dots, n-1 $)定义为:
$$ ak = \left( \frac{e{k+1}(x)}{\binom{n}{k+1}} \right)^{1/(k+1)} $$
其中 $ e_{k+1}(x) $ 是 $ k+1 $ 阶初等对称和(即所有 $ \binom{n}{k+1} $ 个 $ k+1 $ 元乘积之和),而 $ \binom{n}{k+1} $ 是对应组合数,用于归一化均值。
直接枚举所有子集是实现任意 $ n $ 的关键。利用位掩码法(bitmasking),可将 $ 0 $ 到 $ 2^n - 1 $ 的每个整数视为一个子集:若第 $ b $ 位为 1,则包含 $ x_b $。统计每位掩码中置位数量(即子集大小 $ k $),累加对应乘积到 sums[k],最后对每个 $ k $ 计算 $ k $ 阶根下的归一化均值。
以下是完整、健壮、可直接使用的通用 agm 函数:
/**
* 计算正实数数组的单步算术-几何平均(AGM)迭代结果
* @param {Float64Array|number[]} arr - 长度 ≥ 1 的正实数数组
* @returns {Float64Array} 长度同输入的 Float64Array,第 k 项为 k 阶 AGM 分量
*/
function agm(arr) {
const n = arr.length;
if (n === 0) throw new Error('Input array must be non-empty');
if (arr.some(x => typeof x !== 'number' || x <= 0 || !isFinite(x))) {
throw new Error('All elements must be positive finite numbers');
}
// sums[k] 存储所有 (k+1)-元乘积之和(k 从 0 开始对应一阶均值)
const sums = new Array(n).fill(0);
// 枚举所有非空子集:i ∈ [1, 2^n)
const total = 1 << n; // 2^n
for (let i = 1; i < total; i++) {
let product = 1;
let len = 0; // 子集大小(即乘积中因子个数)
for (let b = 0; b < n; b++) {
if (i & (1 << b)) {
product *= arr[b];
len++;
}
}
// len ∈ [1, n] → 对应 a_{len-1},故存入 sums[len-1]
sums[len - 1] += product;
}
// 计算最终结果:a_k = (sums[k] / C(n, k+1))^(1/(k+1))
const result = new Float64Array(n);
for (let k = 0; k < n; k++) {
const order = k + 1;
const binom = binomial(n, order);
const mean = sums[k] / binom;
result[k] = Math.pow(mean, 1 / order);
}
return result;
}
// 辅助函数:计算组合数 C(n, k)
function binomial(n, k) {
if (k < 0 || k > n) return 0;
if (k === 0 || k === n) return 1;
k = Math.min(k, n - k); // 利用对称性优化
let res = 1;
for (let i = 0; i < k; i++) {
res = (res * (n - i)) / (i + 1);
}
return Math.round(res); // 避免浮点误差,返回整数
}✅ 使用示例:
console.log(agm([1, 2])); // → Float64Array [1.5, 1.4142135623730951] ≈ [(1+2)/2, √(1×2)] console.log(agm([1, 2, 3])); // → Float64Array [2, √((1×2 + 1×3 + 2×3)/3), (1×2×3)^(1/3)] // → [2, √(11/3)≈1.91485, 6^(1/3)≈1.81712] console.log(agm([2, 4, 8, 16])); // 支持任意长度,自动计算四阶对称和
⚠️ 注意事项:
- 数值稳定性:当 $ n $ 较大(如 > 20)时,$ 2^n $ 子集枚举开销显著上升;实际应用中建议限制输入长度(如 ≤ 16),或改用动态规划计算 ESP(时间复杂度 $ O(n^2) $)。
-
精度边界:JavaScript 的
Number精度有限,对极大或极小数值相乘可能溢出或失真;必要时可引入BigInt(仅限整数)或专用高精度库。 -
收敛性前提:AGM 迭代收敛要求所有输入为严格正实数;函数已内置校验,传入零、负数或
NaN将抛出错误。
该实现将数学定义无缝转化为可扩展的工程代码,兼顾清晰性、正确性与实用性,是高维 AGM 数值计算的理想起点。

















