如何在 JavaScript 中执行整数除法,并单独获取余数

How to perform an integer division, and separately get the remainder, in JavaScript

提问人:Yarin 提问时间:11/20/2010 最后编辑:Peter MortensenYarin 更新时间:10/14/2023 访问量:1184471

问:

JavaScript 中,如何获取:

  1. 一个给定整数进入另一个整数的次数?
  2. 剩下的呢?
JavaScript 数学 数除法

评论


答:

1812赞 Mark Elliot 11/20/2010 #1

对于某个数和某个除数,计算商 ()[1] 和余数 () 如下:yxquotientremainder

const quotient = Math.floor(y/x);
const remainder = y % x;

例:

const quotient = Math.floor(13/3); // => 4 => the times 3 fits into 13  
const remainder = 13 % 3;          // => 1

[1] 一个数字除以另一个数字得到的整数

评论

109赞 11/20/2010
% 适用于 JavaScript 中的浮点数(这与许多其他语言不同),这可能不是需要的:计算结果为 1.5。确保根据需要处理(parseInt、floor 等)3.5 % 2
22赞 Toughy 12/3/2014
数学中 -4.5 的整数部分是 -5,因为 -5 是“仍然低于 -4.5 的最高可能整数”。
30赞 Mark Reed 2/18/2016
但是,无论您决定对负数做什么,它都应该在商和余数上保持一致。以这种方式使用 和 一起使用是不一致的。要么使用 代替 (从而允许负余数),要么使用减法得到余数 ()。floor%truncfloorrem = y - div * x
13赞 Aaron Mansheim 2/7/2017
1. 如果你无论如何都要计算余数,你可以在不计算地板的情况下更快地获得商:.2. 顺便说一句,根据 Donald Knuth 推荐的定义(符号-匹配-除数,不是余数,即欧几里得模,也不是 JavaScript 符号-匹配-被数)的模运算是我们可以在 JavaScript 中编码为 .remdiv(y - rem) / xfunction mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }
2赞 Mark Reed 8/22/2017
-9 / 2 = -4.5。然后你取 -4.5 的下限,即 -5。请记住,-5 小于 -4.5,下限运算定义为小于给定值的最大整数。
496赞 user113716 11/20/2010 #2

我不是按位运算符方面的专家,但这是获取整数的另一种方法:

var num = ~~(a / b);

这也适用于负数,但会向错误的方向四舍五入。Math.floor()

这似乎也是正确的:

var num = (a / b) >> 0;

注意:仅当您确信输入范围在 32 位整数范围内时,才使用 ~~ 作为 Math.trunc() 的替代品。

评论

106赞 BlueRaja - Danny Pflughoeft 3/26/2011
另一个,我花了最后 20 分钟试图弄清楚其目的,显然是a/b | 0
26赞 Aleksei Zabrodskii 7/15/2012
@user113716 @BlueRaja 按位运算只对整数类型有意义,JS(当然)知道这一点。,并且不修改初始参数,但使解释器将整数部分传递给运算符。~~intint | 0int >> 0
19赞 Mark K Cowan 12/19/2013
floor鉴于它的名字,几乎不会朝着错误的方向四舍五入 - 只是不是人们通常想要的方向!
36赞 Mirek Rusin 3/26/2014
那是布欧布欧。 -> 和 -> 。a = 12447132275286670000; b = 128Math.floor(a/b)97243220900677100~~(a/b)-1231452688
10赞 timkay 5/29/2014
注意优先顺序。 和 一样,但是 ,而 。 是一个不错的选择,因为优先级更合适。~~(5/2) --> 2(5/2)>>0 --> 2~~(5/2) + 1 --> 3~~(5/2)>>0 + 1 --> 1~~
43赞 gammax 2/14/2013 #3
var remainder = x % y;
return (x - remainder) / y;

评论

2赞 Samuel 12/7/2013
不幸的是,当 x = -100 时,此版本未通过测试,因为它返回 -34 而不是 -33。
1赞 4esn0k 2/3/2015
“VAR x = 0.3;var y = 0.01;“ ?(感谢 github.com/JuliaLang/julia/issues/4156#issuecomment-23324163)
1赞 Marjan Venema 7/12/2018
实际上,@Samuel,对于负值,此方法返回正确的结果,或者至少它返回与使用 :) 的方法相同的值。我检查了 100,3;-100,3;100,-3 和 -100,-3。当然,自从您的评论和事情发生变化以来已经过去了很多时间。Math.trunc
302赞 KalEl 6/20/2013 #4

我在Firefox上做了一些速度测试。

-100/3             // -33.33..., 0.3663 millisec
Math.floor(-100/3) // -34,       0.5016 millisec
~~(-100/3)         // -33,       0.3619 millisec
(-100/3>>0)        // -33,       0.3632 millisec
(-100/3|0)         // -33,       0.3856 millisec
(-100-(-100%3))/3  // -33,       0.3591 millisec

/* a=-100, b=3 */
a/b                // -33.33..., 0.4863 millisec
Math.floor(a/b)    // -34,       0.6019 millisec
~~(a/b)            // -33,       0.5148 millisec
(a/b>>0)           // -33,       0.5048 millisec
(a/b|0)            // -33,       0.5078 millisec
(a-(a%b))/b        // -33,       0.6649 millisec

以上是基于每个试验的 1000 万次试验。

结论:使用(或或)可实现约20%的效率增益。还要记住,它们都与 、 不一致。(a/b>>0)(~~(a/b))(a/b|0)Math.floora/b<0 && a%b!=0

评论

94赞 mik01aj 1/8/2014
请注意,只有当您经常这样做时,优化整数除法的速度才有意义。在任何其他情况下,我建议选择最简单的一种(以您和您的同事认为最简单的为准)。
11赞 JonnyRaa 9/17/2014
@m01完全同意 - 网上有太多关注这样的事情
7赞 Stijn de Witt 11/28/2015
@m01 但哪个更难:学习和谁知道有多少其他 API 函数,还是学习(按位非)运算符以及 JS 中按位操作的工作方式,然后了解双波浪号的效果?Math.floor~
28赞 mik01aj 11/28/2015
好吧,如果你的同事没有在汇编程序中对芯片进行编程,他们可能会更好地理解。即使没有,这个也是可以谷歌搜索的。Math.floor
3赞 mikemaccana 3/2/2021
这是整数除法方法的性能比较,而不是问题的答案。
5赞 Cyberknight 2/28/2014 #5

JavaScript 按照负数的数学定义计算负数和非整数的余数的下限。

FLOOR 被定义为“小于参数的最大整数”,因此:

  • 正数:FLOOR(X)=X 的整数部分;
  • 负数:FLOOR(X)=X 减去 1 的整数部分(因为它必须小于参数,即更负!

REMAINDER 被定义为除法的“剩余”(欧几里得算术)。当被除数不是整数时,商通常也不是整数,即没有余数,但如果商被强制为整数(当有人试图获得浮点数的余数或模数时,就会发生这种情况),显然会有一个非整数“剩余”。

JavaScript 确实按预期计算了一切,因此程序员必须小心地提出正确的问题(人们应该小心地回答所问的问题!Yarin的第一个问题不是“X除以Y的整数除以多少”,而是“一个给定整数进入另一个整数的整数”。对于正数,两者的答案是相同的,但对于负数则不然,因为整数除法(除数除数)将比一个数(除数)“进入”另一个数(除数)的次数小 -1。换句话说,FLOOR 将返回负数整数除法的正确答案,但 Yarin 没有问这个问题!

gammax 回答正确,该代码按照 Yarin 的要求工作。另一方面,塞缪尔错了,我没有做数学,我猜,否则他会看到它确实有效(另外,他没有说他的例子的除数是多少,但我希望它是 3):

余数 = X % Y = -100 % 3 = -1

GoesInto = (x - 余数) / y = (-100 - -1) / 3 = -99 / 3 = -33

顺便说一句,我在 Firefox 27.0.1 上测试了代码,它按预期工作,具有正数和负数以及非整数值,包括除数和除数。例:

-100.34 / 3.57:GoesInto = -28,余数 = -0.3800000000000079

是的,我注意到,那里有精度问题,但我没有时间检查它(我不知道这是 Firefox、Windows 7 还是我的 CPU 的 FPU 有问题)。然而,对于Yarin的问题,它只涉及整数,gammax的代码可以完美地工作。

270赞 Oriol 3/11/2014 #6

ES6 引入了新的 Math.trunc 方法。这允许修复@MarkElliot的答案,使其也适用于负数:

var div = Math.trunc(y/x);
var rem = y % x;

请注意,与按位运算符相比,方法的优点是它们处理超过 231 的数字。Math

评论

0赞 4esn0k 2/3/2015
变量 y =18014398509481984;变量 x= 5;div = ?-错误?
6赞 Oriol 2/4/2015
@4esn0k 这不是一个错误。您的数字太多,在 64 位二进制格式的 IEEE 754 数字中不能有那么高的精度。例如。18014398509481984 == 18014398509481985
0赞 4esn0k 2/4/2015
18014398509481984 == 2**54,我特意用了这个数字,因为它完全以 binary64 格式表示。答案也恰恰代表了
1赞 Stijn de Witt 11/28/2015
我认为选择很简单:您需要支持最多 32 位的签名数字吗?用。需要支持最大 54 位的更大数字?如果您有它,请使用它,或者以其他方式使用(更正为负数)。需要支持更大的数字?使用一些大数字库。~~(x/y)Math.truncMath.floor
5赞 Alex Moore-Niemi 11/25/2016
对于来自 Google 的 Ruby 爱好者来说,您可以这样实现它:divmodfunction divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
9赞 Aetricity 11/1/2014 #7

Math.floor(operation)返回操作的向下舍入值。

第一个问题的示例:

const x = 5;
const y = 10.4;
const z = Math.floor(x + y);

console.log(z);

第二个问题的例子:

const x = 14;
const y = 5;
const z = Math.floor(x % y);

console.log(x);

29赞 Édipo Costa Rebouças 4/14/2015 #8

您可以使用该函数获取截断的结果。parseInt

parseInt(a/b)

要获取余数,请使用 mod 运算符:

a%b

parseInt 在字符串方面存在一些陷阱,以避免使用基数为 10 的基数参数

parseInt("09", 10)

在某些情况下,数字的字符串表示可以是科学记数法,在这种情况下,parseInt 会产生错误的结果。

parseInt(100000000000000000000000000000000, 10) // 1e+32

此调用将生成 1 作为结果。

评论

14赞 Powers 11/2/2015
parseInt应尽可能避免使用。这是道格拉斯·克罗克福德(Douglas Crockford)的警告:“如果字符串的第一个字符是0,则该字符串以8为基数而不是以10为基数计算。以 8 为基数,8 和 9 不是数字,因此 parseInt(“08”) 和 parseInt(“09”) 生成 0 作为结果。此错误会导致分析日期和时间的程序出现问题。幸运的是,parseInt 可以接受基数参数,因此 parseInt(“08”, 10) 生成 8。我建议您始终提供 radix 参数。archive.oreilly.com/pub/a/javascript/excerpts/......
5赞 Édipo Costa Rebouças 11/25/2015
在一个部门中,我希望收到一个数字,而不是一个字符串,但这是一个很好的观点。
4赞 None 12/22/2015
@Powers所以添加基数。他没有说应该避免;只是有一些陷阱需要注意。你必须意识到这些事情,并准备好应对。parseInt
4赞 Oriol 6/17/2016
切勿使用数字参数进行调用。 应该解析部分数字字符串,而不是截断数字。parseIntparseInt
4赞 fregante 3/25/2017
仅仅因为事物最初并不打算以某种方式使用,并不意味着你不应该这样做。这个答案有效。
0赞 Josh Weston 6/8/2015 #9

您也可以使用三元运算符来决定如何处理正整数和负整数值。

var myInt = (y > 0) ? Math.floor(y/x) : Math.floor(y/x) + 1

如果数字是正数,则一切都很好。如果数字为负数,则由于 Math.floor 处理负数的方式,它将加 1。

0赞 bzim 5/11/2017 #10

这将始终被截断为零。

function intdiv(dividend, divisor) {
    divisor = divisor - divisor % 1;
    if (divisor == 0) throw new Error("division by zero");
    dividend = dividend - dividend % 1;
    var rem = dividend % divisor;
    return {
        remainder: rem,
        quotient: (dividend - rem) / divisor
    };
}
56赞 Wolf Elkan 5/20/2017 #11

我通常使用:

const quotient =  (a - a % b) / b;
const remainder = a % b;

它可能不是最优雅的,但它有效。

评论

3赞 Dem Pilafian 3/20/2019
不错的解决方案,因为它避免了解析或截断浮点数的丑陋。
17赞 gb96 4/4/2019
如果您同时需要商和余数,请先计算余数,然后在商的表达式中重用该值,即商 = (a - 余数) / b;
5赞 Zv_oDD 10/30/2019
余数 = a % b;商 = (a - 余数) / b;
4赞 Alex 7/7/2017 #12

Alex Moore-Niemi 的评论作为回答:

对于来自 Google 的 Ruby 主义者来说,你可以这样实现它:divmod

function divmod(x, y) {
  var div = Math.trunc(x/y);
  var rem = x % y;
  return [div, rem];
}

结果:

// [2, 33]

评论

3赞 Palec 7/7/2017
通常,当涉及负数时,使用地板除法 (),这与截断除法 () 不同。NPM divmod 包、Ruby divmod、SWI-Prolog divmod 以及许多其他实现也是如此。 divmodMath.floorMath.trunc
1赞 Palec 7/7/2017
截断除法比地板除法提供更自然的结果,但兼容性胜过 IMO。也许,使用地板除法也有数学或性能方面的原因。请注意,通常存在,因为它的执行速度是单独计算两个操作的两倍。在没有这种性能优势的情况下提供这样的功能可能会令人困惑。divmod
1赞 Konstantin Möllers 9/13/2017 #13

如果只是用 2 的幂除法,则可以使用按位运算符:

export function divideBy2(num) {
  return [num >> 1, num & 1];
}

export function divideBy4(num) {
  return [num >> 2, num & 3];
}

export function divideBy8(num) {
  return [num >> 3, num & 7];
}

(第一个是商,第二个是余数)

评论

0赞 Palec 9/13/2017
一般。function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
0赞 user1920925 11/11/2017 #14

计算页数可以通过一个步骤完成:

Math.ceil(x/y)

评论

2赞 Paul Rooney 12/19/2018
我不明白这如何提供其余部分。
1赞 Peter Mortensen 8/19/2023
“页数”是什么意思?这是一个虚假的答案吗?
2赞 rewritten 9/19/2018 #15

如果你需要计算非常大的整数的余数,而 JS 运行时无法这样表示(任何大于 2^32 的整数都表示为浮点数,因此它失去了精度),你需要做一些技巧。

这对于检查我们日常生活中许多情况下存在的许多校验位(银行帐号、信用卡等)尤为重要。

首先,你需要你的数字作为一个字符串(否则你已经失去了精度,其余的没有意义)。

str = '123456789123456789123456789'

您现在需要将字符串拆分为较小的部分,足够小,以便任何余数和字符串的连接可以容纳 9 位数字。

digits = 9 - String(divisor).length

准备一个正则表达式来拆分字符串

splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g')

例如,如果为 7,则正则表达式为digits

/.{1,7}(?=(.{7})+$)/g

它匹配最大长度为 7 的非空子字符串,该子字符串后面是 7 的倍数字符(是正面展望)。“g”是使表达式遍历所有字符串,而不是在第一次匹配时停止。(?=...)

现在将每个部分转换为整数,并通过以下方式计算余数(将前面的余数 - 或 0 - 乘以 10 的正确幂相加):reduce

reducer = (rem, piece) => (rem * Math.pow(10, digits) + piece) % divisor

由于“减法”余数算法,这将起作用:

n mod d = (n - kd) mod d

它允许用其余数替换数字十进制表示的任何“初始部分”,而不会影响最终余数。

最终代码如下所示:

function remainder(num, div) {
  const digits = 9 - String(div).length;
  const splitter = new RegExp(`.{1,${digits}}(?=(.{${digits}})+$)`, 'g');
  const mult = Math.pow(10, digits);
  const reducer = (rem, piece) => (rem * mult + piece) % div;

  return str.match(splitter).map(Number).reduce(reducer, 0);
}
-6赞 Daniel 11/13/2020 #16

这是执行此操作的一种方法。(就我个人而言,我不会这样做,但我认为这是一种有趣的方式。前面的答案中提到的方法肯定更好,因为这会调用多个函数,因此速度较慢,并且在捆绑包中占用更多空间。

function intDivide(numerator, denominator) {
  return parseInt((numerator/denominator).toString().split(".")[0]);
}

let x = intDivide(4,5);
let y = intDivide(5,5);
let z = intDivide(6,5);
console.log(x);
console.log(y);
console.log(z);

评论

0赞 Paul-Sebastian Manole 11/11/2022
我真的很喜欢提到占用更多空间。
0赞 Daniel 4/12/2023
你们都是野蛮人,我从字面上说这不是一个好办法......但就像它确实有效一样
5赞 nkitku 11/25/2020 #17

用:

const idivmod = (a, b) => [a/b |0, a%b];

还有一个关于它的建议:模数和附加整数数学

1赞 Sandeep Kumar 11/30/2020 #18
function integerDivison(dividend, divisor) {

    this.Division = dividend/divisor;
    this.Quotient = Math.floor(dividend/divisor);
    this.Remainder = dividend%divisor;
    this.calculate = () => {
        return {Value:this.Division, Quotient:this.Quotient, Remainder:this.Remainder};
    }
}

var divide = new integerDivison(5, 2);
console.log(divide.Quotient)     // To get the quotient of two values
console.log(divide.division)     // To get the floating division of two values
console.log(divide.Remainder)    // To get the remainder of two values
console.log(divide.calculate())  // To get the object containing all the values
1赞 HiEv 7/30/2023 #19

如果你需要一些愚蠢的大数字的商,你可以使用:

Math.trunc((x/y) + (Number.EPSILON * (2 ** Math.ceil(Math.log2(Math.abs(x/y))))) * Math.sign(x/y))

注意:这仅适用于 和 值(即被除数和除数)被准确表示的情况,即使在任何四舍五入以使它们大于 时作为整工作的情况也是如此。xyNumber.MAX_SAFE_INTEGER

例如,如果我们有:

x = 45000000000000000000000000000 = 4.5e+28
y =   500000000000000000000000000 =   5e+26

然后,此页面上给出的答案会为您提供:

89.99999999999999: x/y
90: Math.trunc((x/y) + (Number.EPSILON * (2 ** Math.ceil(Math.log2(Math.abs(x/y))))) * Math.sign(x/y))
89: Math.floor(x/y)
89: ~~(x/y)
89: (x/y)>>0
89: x/y|0
89: (x-(x%y))/y

正确答案是 ,所以,正如你所看到的,我上面给出的方程式是唯一提供正确答案的方程式。90

该等式也适用于负面结果。如果我们定为负数,那么我们得到:x

-89.99999999999999: x/y
-90: Math.trunc((x/y) + (Number.EPSILON * (2 ** Math.ceil(Math.log2(Math.abs(x/y))))) * Math.sign(x/y))
-90: Math.floor(x/y)
-89: ~~(x/y)
-89: (x/y)>>0
-89: x/y|0
-89: (x-(x%y))/y

只有那个等式并给出正确的答案。Math.floor()

而且,只是为了确认一些不同的值,这些值会给出稍大的值:

x = -45000000000000000000000000 = -4.5e+25
y =    500000000000000000000000 =    5e+23

我们得到:

-90.00000000000001: x/y
-90: Math.trunc((x/y) + (Number.EPSILON * (2 ** Math.ceil(Math.log2(Math.abs(x/y))))) * Math.sign(x/y))
-91: Math.floor(x/y)
-90: ~~(x/y)
-90: (x/y)>>0
-90: x/y|0
-90.00000000000001: (x-(x%y))/y

在这种情况下,并且失败了,这意味着,虽然它可能不快或不漂亮,但为这个答案给出的代码是唯一在所有情况下都能给出正确结果的方法,前提是除数和被除数能够准确表示。(或者,至少,我所知道的所有案例。Math.floor()(x-(x%y))/y

如果您想知道如何获得大数的正确余数,请参阅:

补遗:如果你只使用正数,那么你可以把它缩短为这样:

Math.trunc((x/y) + (Number.EPSILON * (2 ** Math.ceil(Math.log2(x/y)))))
2赞 Géry Ogam 9/15/2023 #20

对于满足这些约束的基元函数(计算除法的)和(计算除法的余数),有几种可能的定义:divmod

  • Number.isInteger(div(x, y));
  • x === div(x, y) * y + mod(x, y);
  • Math.abs((mod(x, y)) < Math.abs(y).

计算机科学文献和编程语言中常用的定义基于

  • 截断的除法:

    function div(x, y) {
      return Math.trunc(x / y);
    }
    
    function mod(x, y) {
      return x % y;
    }
    
  • 地板部门:

    function div(x, y) {
      return Math.floor(x / y);
    }
    
    function mod(x, y) {
      return ((x % y) + y) % y;
    }
    
  • 欧几里得分部:

    function div(x, y) {
      return Math.sign(y) * Math.floor(x / Math.abs(y));
    }
    
    function mod(x, y) {
      const z = Math.abs(y);
      return ((x % z) + z) % z;
    }
    

此外

  • 截断的除法具有以下属性:mod(x, y) * x >= 0;
  • The Floored Division具有以下属性:mod(x, y) * y >= 0;
  • 欧几里得除法具有以下性质: .mod(x, y) >= 0

因此

  • 如果 和 ,则截断、地板和欧几里得除法一致;x >= 0y > 0
  • 如果 和 ,则截断除法和欧几里得除法一致;x >= 0y < 0
  • 如果 和 ,则 floored 和 Euclidee 划分一致;x <= 0y > 0
  • 如果 和 ,则截断的除法和下限的除法一致。x <= 0y < 0

建议选择欧几里得除法而不是截断和地板除法来定义函数,并且根据 Raymond Boute 的论文“函数 div 和 mod 的欧几里得定义”divmod

在本文中,我们澄清了各种定义之间的差异,特别是那些基于截断除法(T定义)和Knuth定义的基于地板除法(F定义)的定义。我们还提出了另一个定义,我们称之为欧几里得定义,因为它基于欧几里得定理(E-definition)。这种替代方案在文献中很少讨论,但仔细分析,无论是在理论上还是在实际使用中,它在规律性和有用的数学性质方面都是有利的。欧几里得定义通常是最直接的选择,在各种具有代表性的应用领域中,我们体验到了对div-mod函数对的需求。

2赞 Anil Ram 9/22/2023 #21

我们可以使用以下方法。

quotient = dividend / divisor | 0;

以及我们可以通过模运算符获得提醒的任何方式

remainder = dividend % divisor;