For AI agents: the complete documentation index is available at /tc39-atlas/llms.txt, the full documentation bundle is available at /tc39-atlas/llms-full.txt, and this page is available as Markdown at /tc39-atlas/proposals/year/pending/proposal-integer-and-modulus-math.md.
  • 简体中文
  • Modulus and Additional Integer Math S1

    中文标题:模运算与额外整数数学

    提案概览
    提案速览

    本提案扩展了Math对象,增加了真正的模运算和针对有符号32位整数的整数数学函数,解决了ECMAScript缺少原生模运算和整数运算效率低的问题。它引入了Math.mod、Math.idiv、Math.imod、Math.imuldiv、Math.irem和Math.irandom,并处理了除法溢出的特殊情况。

    Note

    以下 README 来自上游仓库,其中的阶段或状态标注可能滞后;当前信息以提案概览为准。

    模运算与额外整数数学

    更新于2023年7月9日

    状态

    提案人:Peter Hoddie(由Dan Ehrenberg协助)

    阶段:1

    动机

    本提案包含对Math对象的两个相关扩展:额外的整数数学函数以及整数和浮点数的真正模运算。

    本提案增加了ECMAScript中缺失的功能。它以一种对开发者友好的方式实现,并允许引擎在各种硬件上进行高效实现。虽然与WebAssembly和asm.js在某些功能上有所重叠,但本提案是独立于它们的。

    整数数学

    整数数学运算通常比浮点数学更高效。即使在带有FPU的CPU上也是如此。

    本提案在Math上引入了额外的静态方法,用于有符号32位整数值。

    虽然ECMA-262以浮点数定义数学运算,但引擎和ECMAScript编译器可能实施优化,在结果无可观察差异的情况下使用整数。

    引擎可以推断出一些可能进行整数优化的情况,但这并非总是可行的。因此,ES6添加了Math.imul,允许源代码直接表达32位有符号整数乘法运算。

    除了更高效之外,整数数学运算符可能比执行浮点运算然后将结果转换为整数更加方便。整数除法、整数模、整数余数和整数随机数就是例子。

    模运算

    %运算符通常被错误地称为“模运算符”,但实际运算是余数

    对于正输入,余数和模运算等价,但对于负数则不同。这篇文章描述了差异。

    Brendan Eich 指出

    ...我们仍然需要向JS添加mod(与类似C的%区分开来)。

    本提案在Math上引入了额外的静态方法,用于对Number和有符号32位整数值进行模运算。

    MDN关于Math Remainder的页面有一段长文解释了余数和模运算之间的差异,一个模运算公式,以及一个令人困惑的注释,开头是“在JavaScript中,模运算(没有专用的运算符)...”。

    使用场景

    • 引擎优化
    • 编译器优化
    • 简化支持整数运算的脚本代码
    • 脚本优化 - J5e(嵌入式机器人技术)

    描述

    以下操作来自原始提案:

    • Math.mod(x, y) – IEEE 754 模
    • Math.idiv(x, y) – Int32 除法
    • Math.imod(x, y) – Int32 模
    • Math.imuldiv(x, y, z) – Int32 乘法和除法,具有64位中间结果 - (x * y) / z
    • Math.irem(x, y) – Int32 余数(%运算符的整数等价物)

    对于整数操作,输入参数使用ToInt32转换为整数值。

    特殊情况

    32位有符号整数除法有一个特殊情况:将值-2147483648(0x80000000,最小的负32位整数值)除以-1。结果无法表示为32位有符号整数(最大的正32位有符号整数是+2147483647)。这影响了Math.idivMath.imodMath.iremMath.imuldiv的实现。

    此操作的行为因CPU架构而异。一些架构会生成异常,而其他架构具有定义的行为。建议的返回值(与某些CPU架构生成的结果一致)如下:

    • Math.idiv - 结果是x的值(-2147483648)
    • Math.imod - 结果是0
    • Math.imuldiv - 结果是-2147483648
    • Math.irem - 结果是0

    对于已经产生建议结果的架构,这个特殊情况下不需要额外开销;对于不产生此结果的架构,则需要进行额外的运行时检查。

    添加Math.irandom()

    在JavaScript中生成随机整数很棘手。MDN在Math.random()页面上提供了两个生成随机整数的示例,包括对常见错误的警告。生成随机浮点值然后将其转换为整数有额外开销。

    • Math.irandom() – 从0到2147483647(含)的Int32值
    • Math.irandom(x) – 介于0x - 1(含)之间的Int32值
    • Math.irandom(x, y) – 介于xy - 1(含)之间的Int32值。这与MDN上getRandomInt示例的行为相匹配。

    Math.random()一样,这里尝试提供加密安全的随机数。

    Math.irandom方便访问Array中的随机元素。这里y通常是undefined,因为非整数数组索引会转换为字符串。另一方面,z始终是数组元素之一。

    let x = ["one", "two", "three"];
    let y = x[Math.random() * x.length];
    let z = x[Math.irandom(x.length)];

    移除

    此提案的原始版本包含一个返回对象中多个值的操作。这难以优化且很少见。因此,它不再属于此提案。

    • Math.idivmod(x, y) – Int32 带模除法,返回[除法结果,模结果]

    比较

    大多数语言提供这些整数和模操作的一些子集。本节包含来自Python和Ruby的示例。

    Python

    • math.remaindermath.fmod

    ...fmod() 通常更适用于处理浮点数,而 Python 的 x % y 更适合处理整数。

    但是... %被定义为“余数”

    • //

    地板商... 也称为整数除法

    • divmod(x, y)

    [返回] 对 (x // y, x % y)

    Ruby

    • x.divmod(y) – 返回 [商, 模]
    • x.modulo(y)x - y * (x / y).floor
    • x.remainder(y)x - y * (x / y).truncate

    实现

    Polyfill/transpiler实现

    • (无)

    原生实现

    • XS - 当前实现

    问答

    :为什么使用静态方法而不是运算符?

    :此提案遵循Math.imul建立的方法。如果未来ECMAScript支持运算符重载,开发者可能在此应用运算符。

    :为什么这需要内建,而不是在ECMAScript中实现?

    :这些静态方法允许引擎以使用等效ECMAScript函数无法实现的方式进行优化。

    :这些静态方法接受BigInt参数吗?

    :不接受,以便与Math上的其他静态方法保持一致,包括Math.imul。如果委员会偏好,支持BigInt在合理的情况下没有根本性反对。