
core-js 中 ECMAScript Math 模块全解析19 个数学方法、入口点与精确浮点求和实现【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js本文以 core-js 官方文档 docs/web/docs/features/ecmascript/math.md 为主体系统梳理 core-js 对 ECMAScriptMath内置对象全部扩展模块的组成、类型签名、加载入口并结合仓库源码剖析Math.sumPrecise、Math.hypot、Math.f16round等方法的底层实现原理。读者读完可掌握如何按需引入Math扩展、正确理解各方法的边界语义以及核心算法在 core-js 中是如何落地的。一、模块总览core-js 覆盖的 19 个 Math 方法core-js 将 ECMAScript 规范tc39.es/ecma262 下。文档中列出的完整模块清单如下es.math.acosh反双曲余弦es.math.asinh反双曲正弦es.math.atanh反双曲正切es.math.cbrt立方根es.math.clz3232 位整数前导零个数es.math.cosh双曲余弦es.math.expm1e^x - 1es.math.fround四舍五入到 32 位浮点数es.math.f16round四舍五入到 16 位半精度浮点数es.math.hypot平方和的平方根支持多参数es.math.imul32 位整数乘法es.math.log10以 10 为底的对数es.math.log1pln(1 x)es.math.log2以 2 为底的对数es.math.sign符号函数es.math.sinh双曲正弦es.math.sum-precise精确求和Math.sumPrecisees.math.tanh双曲正切es.math.trunc截断取整其中绝大多数属于 ES2015 起逐步纳入规范的标准方法而esnext.math.sum-preciseMath.sumPrecise是正在推进中的新提案TC39 proposal-math-sumcore-js 以 esnext 前缀模块先行提供。从入口目录 packages/core-js/es/math/ 可以看到每个方法均有对应的独立入口文件acosh.js、hypot.js、sum-precise.js……以及汇总入口index.js方便按需加载。二、内置方法签名TypeScript 视角文档给出了上述方法在Math命名空间下的类型签名。这些签名直接决定了调用约定与返回值的语义边界namespace Math { acosh(number: number): number; asinh(number: number): number; atanh(number: number): number; cbrt(number: number): number; clz32(number: number): number; cosh(number: number): number; expm1(number: number): number; fround(number: number): number; f16round(number: any): number; hypot(...args: Arraynumber): number; imul(number1: number, number2: number): number; log1p(number: number): number; log10(number: number): number; log2(number: number): number; sign(number: number): 1 | -1 | 0 | -0 | NaN; sinh(number: number): number; sumPrecise(items: Iterablenumber): Number; tanh(number: number): number; trunc(number: number): number; }几个值得注意的语义要点sign的返回值类型是五值联合1 | -1 | 0 | -0 | NaN这是唯一一个在签名中明确暴露符号位细节的方法。从 internals/math-sign.js 的实现看core-js 优先复用原生Math.sign源码注释标记为 safe否则使用 polyfilln 0 || n ! n ? n : n 0 ? -1 : 1——即保留-0、0与NaN的原始语义负数为-1正数为1。sumPrecise接收Iterablenumber而非可变参数且返回Number。这是与普通Math方法最大的调用差异Math.sumPrecise([1, 2, 3])而不是Math.sumPrecise(1, 2, 3)。f16round的入参标注为any因为半精度舍入同样遵循 Number 到 Number 的转换规则可接受任意可转数值的输入。hypot是唯一接受任意数量参数...args的方法与Math.max、Math.min的调用方式一致。三、入口点按需加载的四种命名空间与三种取值文档给出了Math系列功能的完整入口点模式。核心形态为core-js(-pure)/es|stable|actual|full/math core-js(-pure)/es|stable|actual|full/math/acosh core-js(-pure)/es|stable|actual|full/math/asinh core-js(-pure)/es|stable|actual|full/math/atanh core-js(-pure)/es|stable|actual|full/math/cbrt core-js(-pure)/es|stable|actual|full/math/clz32 core-js(-pure)/es|stable|actual|full/math/cosh core-js(-pure)/es|stable|actual|full/math/expm1 core-js(-pure)/es|stable|actual|full/math/fround core-js(-pure)/es|stable|actual|full/math/f16round core-js(-pure)/es|stable|actual|full/math/hypot core-js(-pure)/es|stable|actual|full/math/imul core-js(-pure)/es|stable|actual|full/math/log1p core-js(-pure)/es|stable|actual|full/math/log10 core-js(-pure)/es|stable|actual|full/math/log2 core-js(-pure)/es|stable|actual|full/math/sign core-js(-pure)/es|stable|actual|full/math/sinh core-js(-pure)/es|stable|actual|full/math/sum-precise core-js(-pure)/es|stable|actual|full/math/tanh core-js(-pure)/es|stable|actual|full/math/trunc3.1 命名空间的选择语义es | stable | actual | full四个目录对应 packages/core-js/es、packages/core-js/stable、packages/core-js/actual、packages/core-js/full代表 core-js 的四个入口层级按包含范围从小到大排序入口语义典型场景es仅含 ECMAScript 规范内、且环境缺失的部分只求标准兼容的最精简引入stable仅含已进入正式规范的内容生产环境推荐避开未定稿特性actual含已进入规范的 当前处于最新阶段stage的提案想要最新特性但仍在规范轨道上full全部特性含 esnext 级提案实验性质、追求完整3.2 聚合入口与单方法入口聚合入口.../math一次性加载全部 19 个方法对应 packages/core-js/es/math/index.js适合整个 Math 扩展都要用的场景。单方法入口.../math/acosh、.../math/hypot等按名加载tree-shaking 友好适合只需要个别方法、追求最小包体的场景。3.3 pure 与全局版本路径前缀中的core-js(-pure)表示同一入口同时适用于两个发布形态core-js全局版直接修补全局Math对象packages/core-js 是默认发布包core-js-pure纯净版不污染全局对象通过模块导出独立实现用于库作者避免影响宿主环境见 packages/core-js-pure。例如按需引入单个方法// 全局版仅在缺失时修补 Math.log2 import core-js/es/math/log2; // 纯净版得到独立的实现 import log2 from core-js-pure/es/math/log2;四、源码级深度解析三个典型实现4.1Math.sumPrecise基于 Shewchuk 算法的精确浮点求和Math.sumPrecise是当前文档示例中唯一展示实际运行效果的 esnext 级方法其实现位于 packages/core-js/modules/es.math.sum-precise.js。文件头部注释明确说明基于 Shewchuk 的精确浮点加法算法改编自 TC39 proposal-math-sum 的 polyfill。从源码结构看其核心设计包含三层异常状态机先遍历可迭代对象用MINUS_ZERO / PLUS_INFINITY / MINUS_INFINITY / NOT_A_NUMBER / FINITE五个状态跟踪-0、Infinity、-Infinity、NaN与普通有限数的传播规则。例如遇到NaN立即置为NOT_A_NUMBER最终返回NaNInfinity与-Infinity同时出现则置为NOT_A_NUMBER符合 IEEE 754 语义。参数校验if (count MAX_SAFE_INTEGER) throw new $RangeError(...)防止超过2^53 - 1个元素if (typeof n ! number) throw new $TypeError(...)强制要求元素均为 Number 类型。两两求和的 partials 补偿算法twosum(x, y)把x y拆成高位hi与误差项lolo y - (hi - x)配合 overflow 计数处理超过2^1023的极端上溢场景最终把丢掉的精度全部补偿回来。单元测试 tests/unit-global/es.math.sum-precise.js 对该方法的验证覆盖了自定义迭代器createIterable([1, 2, 3])、非可迭代入参抛TypeError、非 Number 元素抛TypeError、[NaN]、[Infinity, -Infinity]返回NaN、空数组返回-0以及[1e308, 1e308, 0.1, 0.1, 1e30, 0.1, -1e30, -1e308, -1e308]这类灾难性抵消场景仍能精确得到0.30000000000000004。4.2Math.hypot防上溢/下溢的缩放算法packages/core-js/modules/es.math.hypot.js 的实现值得单独讲解因为它并不是简单地对各参数平方求和再开方。源码中维护了当前最大绝对值larg对每个新参数若larg argdiv larg / arg; sum sum * div * div 1; larg arg;——先把旧比例折算进去再更新基准否则div arg / larg; sum div * div;——按比例累加平方和。最后返回larg Infinity ? Infinity : larg * sqrt(sum)。这种先归一化、再缩放的写法将中间结果始终控制在[0, 1]范围内从而避免直接计算1e200 * 1e200时发生上溢为Infinity也不会因极小值平方而下溢为0。该模块还通过FORCED $hypot(Infinity, NaN) ! Infinity检测 Chrome 77 的已知 bugV8 issue 9546规范要求Math.hypot(Infinity, NaN)返回Infinity仅在宿主实现有缺陷时才强制覆盖避免不必要的打补丁。4.3Math.f16round半精度浮点舍入Math.f16round依赖通用浮点舍入工具 packages/core-js/internals/math-float-round.js。该工具接收三个浮点格式参数FLOAT_EPSILON、FLOAT_MAX_VALUE、FLOAT_MIN_VALUE。模块 packages/core-js/modules/es.math.f16round.js 传入半精度常数var FLOAT16_EPSILON 0.0009765625; // 2^-10 var FLOAT16_MAX_VALUE 65504; // 半精度最大值 var FLOAT16_MIN_VALUE 6.103515625e-05; // 半精度最小正规格化数 2^-14其舍入策略清晰可读绝对值小于FLOAT_MIN_VALUE的次正规数区间用roundTiesToEven银行家舍入见 internals/math-round-ties-to-even.js实现为n 2^53 - 2^53的经典 trick做最近偶数舍入正常区间用a (1 EPSILON/Number.EPSILON) * abs然后a - (a - abs)构造舍入边界结果超过FLOAT16_MAX_VALUE或为NaN时返回带符号的Infinity。Math.fround同理只是参数换为 32 位浮点常数说明 core-js 用同一套内部工具统一实现了fround与f16round。4.4 其他方法的防御性实现Math.imules.math.imul.js将两个数按 16 位高低拆分相乘后重组规避 JS 数字无法直接表达 32 位无符号乘积的精度问题同时通过FORCED检测 WebKit 对大数计算错误或arity错误imul.length ! 2的情况仅在必要时 polyfill。Math.clz32es.math.clz32.jsn x 0先转为无符号 32 位整数再用floor(log(n 0.5) * LOG2E)求出位数差n 0时返回 32。Math.signes.math.sign.js直接复用内部工具 internals/math-sign.js并优先取原生实现保证性能。所有模块都通过统一的$({ target: Math, stat: true }, ...)导出机制注册到Math上其中stat: true表示静态方法、forced字段用于声明是否强制覆盖宿主原生实现这是 core-js 整个模块体系packages/core-js/modules 内 566 个文件一致遵循的约定。五、运行示例精确求和 vs 朴素求和文档给出的示例恰好点明了Math.sumPrecise的存在价值——普通加法在大数 小数场景下的精度损失1e20 0.1 -1e20; // 01e20 的浮点表示精度不足以容纳 0.1误差被吞掉 Math.sumPrecise([1e20, 0.1, -1e20]); // 0.1补偿算法把 0.1 的精度保留下来这说明当聚合计算涉及数量级差异悬殊的浮点数如财务累加、数值分析、统计求和时Math.sumPrecise能以 O(n) 的代价获得接近精确的求和结果而普通运算符在灾难性抵消面前会静默丢精度。其余方法的使用方式与原生一致例如Math.hypot(3, 4); // 5 Math.imul(0xFFFFFFFF, 5); // -5 Math.sign(-0); // -0 Math.f16round(1.1); // 1.099609375半精度舍入结果 Math.clz32(1); // 31六、如何验证与测试core-js 为每个 Math 模块都配备了独立的 QUnit 单元测试位于 tests/unit-global/全局版与 tests/unit-pure/纯净版。以sumPrecise为例tests/unit-global/es.math.sum-precise.js 不仅断言了基础求和结果还逐条验证了arity参数个数为 1、looksNative尽量保持原生外观、nonEnumerable方法不可枚举等元属性并覆盖了TypeError抛出条件与 IEEE 754 特殊值行为——这些测试同时可以作为各方法语义的权威参考文档。七、总结core-js 对 ECMAScriptMath的覆盖可以概括为三层能力标准方法兜底acosh、cbrt、hypot、imul、log2等 ES2015 方法仅在宿主缺失或实现有 bug如 Chrome 77 的hypot时通过forced标志修补精度增强f16round、fround提供 16/32 位浮点舍入sumPrecise提供精确求和解决工程中真实的数值精度痛点灵活的加载粒度es/stable/actual/full四档 聚合/单方法入口 全局/pure 双形态让开发者可以精确控制引入范围与包体大小。建议在生产环境中从stable入口按需引入Math扩展若需要实验性质的Math.sumPrecise精确求和能力则使用full或esnext命名空间当前实现为esnext.math.sum-precise模块并留意该提案在 TC39 的推进进度。【免费下载链接】core-jsStandard Library项目地址: https://gitcode.com/GitHub_Trending/co/core-js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考