【问题标题】:How to perform an integer division, and separately get the remainder, in JavaScript?如何在 JavaScript 中执行整数除法并分别获取余数?
【发布时间】:2011-05-12 19:37:03
【问题描述】:

JavaScript 中,我如何获得:

  1. 给定整数进入另一个整数的次数?
  2. 剩下的?

【问题讨论】:

    标签: javascript math modulo integer-division


    【解决方案1】:

    对于某个数 y 和某个除数 x,计算商 (quotient) 和余数 (remainder) 为:

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

    【讨论】:

    • % 适用于 JavaScript 中的浮点数(这与许多其他语言不同),这可能不是我们所希望的:3.5 % 2 的计算结果为 1.5。确保按要求处理(parseInt、floor 等)
    • 数学中-4.5的整数部分是-5,因为-5是“仍然低于-4.5的最大可能整数”。
    • 但是,无论您决定对负数做什么,它都应该在商和余数之间保持一致。以这种方式同时使用floor% 并不一致。使用trunc 代替floor(从而允许负余数)或使用减法得到余数(rem = y - div * x)。
    • 1.如果无论如何你要计算余数rem,你可以在没有地板的情况下更快地得到商div(y - rem) / x。 2. 顺便说一下,Donald Knuth 推荐的定义(符号匹配除数,不是余数,即欧几里得模数,也不是 JavaScript 符号匹配除数)的模运算是我们可以在 JavaScript 中编码为function mod (a, n) { return a % n + (Math.sign(a) !== Math.sign(n) ? n : 0); }。跨度>
    • -9 / 2 = -4.5。然后你取 -4.5 的地板,即 -5。请记住,-5 小于 -4.5,地板运算定义为小于给定值的最大整数。
    【解决方案2】:
     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 Quotient of two value 
      console.log(divide.division)     //to get Floating division of two value 
      console.log(divide.Remainder)     //to get Remainder of two value 
      console.log(divide.calculate())   //to get object containing all the values
    

    【讨论】:

      【解决方案3】:
      const idivmod = (a, b) => [a/b |0, a%b];
      

      还有一个正在研究的提案 Modulus and Additional Integer Math

      【讨论】:

        【解决方案4】:

        这是一种方法。 (我个人不会这样做,但认为这是一个有趣的例子)

        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);

        【讨论】:

          【解决方案5】:

          我通常使用:

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

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

          【讨论】:

          • 很好的解决方案,因为它避免了解析或截断浮点数的丑陋。
          • 如果您需要商和余数,请先计算余数,然后在商的表达式中重复使用该值,即商 = (a - 余数) / b;
          • 余数 = a % b;商 = (a - 余数) / b;
          【解决方案6】:

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

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

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

          str = '123456789123456789123456789'
          

          您现在需要将字符串分成更小的部分,足够小,以便任何余数和一段字符串的串联可以容纳 9 位数字。

          digits = 9 - String(divisor).length
          

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

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

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

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

          它匹配最大长度为 7 的非空子字符串,其后跟((?=...) 是正向前瞻)多个 7 的字符。“g”是让表达式贯穿所有字符串,不会在第一场比赛就停下来。

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

          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);
          }
          

          【讨论】:

            【解决方案7】:

            Math.floor(operation) 返回运算的向下舍入值。

            1st 问题示例:

            var x = 5;
            var y = 10.4;
            var z = Math.floor(x + y);
            
            console.log(z);
            

            控制台:

            15

            2nd 问题示例:

            var x = 14;
            var y = 5;
            var z = Math.floor(x%y);
            
            console.log(x);
            

            控制台:

            4

            【讨论】:

              【解决方案8】:

              计算页数可以一步完成: 数学.ceil(x/y)

              【讨论】:

              • 我不明白这如何提供剩余部分。
              【解决方案9】:

              如果你只是用 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];
              }
              

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

              【讨论】:

              • 一般情况下,function divideByPowerOf2(num, exponent) { return [num >> exponent, num & ((1 << exponent) - 1)]; }
              【解决方案10】:

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

              对于来自 Google 搜索 divmod 的 Rubyists,您可以这样实现它:

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

              结果:

              // [2, 33]
              

              【讨论】:

              • 通常,divmod 使用地板除法 (Math.floor),这与涉及负数时的截断除法 (Math.trunc) 不同。 NPM divmod packageRuby divmodSWI-Prolog divmod 以及可能许多其他实现也是如此。
              • 截断除法比下除法提供更自然的结果,但兼容性胜过这一点,IMO。也许,使用地板除法也有数学或性能方面的原因。请注意,divmod 通常存在,因为它的执行速度是分别计算这两个操作的两倍。提供这样的功能而没有这种性能优势可能会令人困惑。
              【解决方案11】:

              这将始终截断为零。 不知道是否为时已晚,但这里是:

              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
                  };
              }
              

              【讨论】:

                【解决方案12】:

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

                parseInt(a/b)
                

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

                a%b
                

                parseInt 对字符串有一些陷阱,以避免使用基数为 10 的基数参数

                parseInt("09", 10)
                

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

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

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

                【讨论】:

                • parseInt 应尽可能避免。这是 Douglas Crockford 的警告:“如果字符串的第一个字符是 0,则字符串以 8 为基数而不是 10 为基数计算。在 8 基数中,8 和 9 不是数字,因此 parseInt("08") 和 parseInt ("09") 结果为 0。此错误会导致解析日期和时间的程序出现问题。幸运的是,parseInt 可以带一个基数参数,因此 parseInt("08", 10) 产生 8。我建议您始终提供基数参数。” archive.oreilly.com/pub/a/javascript/excerpts/…
                • 在除法中,我希望收到一个数字,而不是字符串,但这是一个好点。
                • @Powers 所以添加基数。他没有说应该避免parseInt;只是有一些问题需要注意。 您必须意识到这些事情并做好应对的准备。
                • 永远不要使用数字参数调用parseIntparseInt 应该解析部分数字字符串,而不是截断数字。
                • 仅仅因为事物最初并不打算以某种方式使用,并不意味着您不应该这样做。这个答案有效。
                【解决方案13】:

                您也可以使用三进制来决定如何处理正整数和负整数值。

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

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

                【讨论】:

                  【解决方案14】:

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

                  var num = ~~(a / b);
                  

                  这也适用于负数,而Math.floor() 将朝错误的方向舍入。

                  这似乎也是正确的:

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

                  【讨论】:

                  • 另一个我刚刚花了 20 分钟才弄清楚的目的,显然是 a/b | 0
                  • @user113716 @BlueRaja 按位运算仅对整数类型有意义,而 JS(当然)知道这一点。 ~~intint | 0int >> 0 不修改初始参数,而是让解释器将不可分割的部分传递给运算符。
                  • floor 几乎不会在错误的方向上四舍五入,因为它的名字 - 只是不是人们通常想要的方向!
                  • 那是buu buu。 a = 12447132275286670000; b = 128 Math.floor(a/b) -> 97243220900677100~~(a/b) -> -1231452688.
                  • 注意优先级。 ~~(5/2) --> 2(5/2)>>0 --> 2 一样,但 ~~(5/2) + 1 --> 3,而 ~~(5/2)>>0 + 1 --> 1~~ 是一个不错的选择,因为优先级更合适。
                  【解决方案15】:

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

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

                  请注意,Math 方法比位运算符的优势在于它们可以处理超过 231 的数字。

                  【讨论】:

                  • var y =18014398509481984;变量 x= 5;分区 = ? - 错误?
                  • @4esn0k 这不是错误。您的号码有太多位数,在 64 位二进制格式的 IEEE 754 号码中不能有那么高的精度。例如,18014398509481984 == 18014398509481985
                  • 18014398509481984 == 2**54,我特地使用了这个数字,因为它完全用 binary64 格式表示。答案也很准确
                  • 我认为选择很简单:您需要支持高达 32 位的有符号数字吗?使用~~(x/y)。需要支持最大 54 位签名的更大数字?如果有,请使用Math.trunc,否则使用Math.floor(对负数更正)。需要支持更大的数字吗?使用一些大数字库。
                  • 对于从谷歌搜索divmod的rubyists,您可以这样实现它:function divmod(x, y) { var div = Math.trunc(x/y); var rem = x % y; return [div, rem]; }
                  【解决方案16】:

                  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:进入 = -28,余数 = -0.3800000000000079

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

                  【讨论】:

                    【解决方案17】:

                    我在 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 万次。

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

                    【讨论】:

                    • 我发现 Math.floor() 的性能比其他的更稳定。它不那么上下
                    • 请注意,优化整数除法以提高速度只有在您大量进行时才有意义。在任何其他情况下,我建议选择最简单的一种(以您和您的同事认为最简单的一种为准)。
                    • @m01 完全同意——网上对这类东西的关注太多了
                    • @m01 但哪个更难:了解 Math.floor 和谁知道有多少其他 API 函数,或者了解 ~(按位非)运算符以及如何按位运算在JS中工作然后理解双波浪号的效果?
                    • 好吧,如果你的同事不是用汇编程序编程芯片,他们可能会更好地理解Math.floor。即使没有,这个也可以用谷歌搜索。
                    【解决方案18】:
                    var remainder = x % y;
                    return (x - remainder) / y;
                    

                    【讨论】:

                    • 不幸的是,这个版本在 x = -100 时未能通过测试,因为它返回 -34 而不是 -33。
                    • “var x = 0.3; var y = 0.01;”怎么样? (感谢github.com/JuliaLang/julia/issues/4156#issuecomment-23324163
                    • 其实@Samuel,在负值的情况下,这个方法返回正确的结果,或者至少它返回的值和使用Math.trunc的方法一样:)。我检查了 100,3; -100,3; 100,-3 和 -100,-3。当然,距离您的评论和事情发生变化已经过去了很长时间。
                    猜你喜欢
                    • 1970-01-01
                    • 2021-02-15
                    • 1970-01-01
                    • 1970-01-01
                    • 2013-09-26
                    • 2015-12-23
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多