Math.sumPrecise S4
中文标题:Math.sumPrecise:精确求和
- 阶段: Stage 4
- 状态: 已完成
- ECMAScript 版本: ES2026
- 同步时间: 2026年11月3日
- English original · 官方仓库
该提案向 JavaScript 添加 Math.sumPrecise 方法,用于对多个值求和,其动机是对列表求和的常见需求以及使用 Array.prototype.reduce 的局限。它不采用朴素累加,而是接受一个可迭代对象,并使用更精确的算法返回和。它会拒绝非数字值,且空列表的和为 -0。
以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。
Math.sumPrecise
一个向 JavaScript 添加用于对多个值求和的方法的提案。
状态
作者:Kevin Gibbons
提案负责人:Kevin Gibbons
本提案处于 TC39 流程的第 4 阶段:它已完成并包含在标准中。任何进一步的更改都需要通过常规流程在单独的提案中进行。此仓库已归档。
动机
对列表求和是一种非常常见的操作,也是 Array.prototype.reduce 少数剩余用例之一。更好的做法是让用户直接表达该操作。
此外,使用更巧妙的算法,对一组浮点数求和可以比朴素的 .reduce((a, b) => a + b, 0) 方法更精确;很少有 JavaScript 程序员意识到这一点(即使在他们当中,大多数人也不会费心去做)。我们可以让人们更容易采用更好的选择。
提案
添加一个接受可迭代对象的 Math.sumPrecise 方法,该方法使用比朴素求和更精确的算法返回可迭代对象中各个值的和。
问题
采用哪种算法?
本提案没有规定任何特定算法,而是要求得到最大程度正确的答案——也就是说,如果你进行任意精度算术,然后把结果转换回浮点数,就会得到的答案。这可以在实际上不需要任意精度算术的情况下完成。实现这一点的一种方式见 Shewchuk '96,我已将其用 JS 实现(另有一些处理中间溢出的细节)。其他策略也是可能的。
Python 的 math.fsum 目前使用相同算法实现(不过不处理中间溢出)。
Radford M. Neal 在 Fast exact summation using small and large superaccumulators 中给出了一种更近期的算法,其采用 MIT 许可的代码可在此处获取。
接受可迭代对象还是可变参数?
Math.max 的先例暗示应采用可变参数形式,但这实际上并不是你想要的方式——一旦你的列表超过几万个元素,你很可能会使栈溢出并得到 RangeError。
因此本提案只包含接受可迭代对象的形式。
命名
Math.sum 是显而易见的名称,但人们并不清楚它将采用与朴素求和不同的(更慢的)算法。将其称为 Math.sumPrecise 是为了提请人们注意这一差异。
这个方法是应该把值强制转换为数字,还是在给定非数字值时抛出错误?
它将拒绝非数字值,这与 Math.max 的先例不同。
空列表的和是 0 还是 -0?
是 -0。这是浮点加法的单位元。这一选择确保 Math.sumPrecise([]) + Math.sumPrecise(foo) 总是与 Math.sumPrecise(foo) 给出相同的答案。
它应该支持 BigInt 吗?
不 —— Math.sumPrecise([]) 返回 Number -0(或 0)很重要,这意味着当 bigints 为空时,5n + Math.sumPrecise(bigints) 会抛出错误,这很糟糕。
我们可以为 BigInt 求和设置单独的方法。根据上面命名讨论的结果,我会倾向于 BigInt.sum 或 BigInt.sumFrom。但这样的方法不会成为本提案的一部分。
乘积呢?
这种情况出现得少得多,因此我目前不提议它。