关于数学:整数除法与JavaScript中的余数?

Integer division with remainder in JavaScript?

在javascript中,我如何获得:

  • 一个给定整数进入另一个整数的整数?
  • 剩下的?

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

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


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

    1
    var num = ~~(a / b);

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

    这似乎也是正确的:

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


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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    -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万个试验为每个。

    结论:使用EDCX1〔5〕(或EDCOX1×6)或EDCOX1〔7〕,可获得约20%的增益。同时,当EDCX1为9时,它们都与EDCX1〔8〕不一致。


    ES6引入了新的Math.trunc方法。这样可以修正@markelliot的答案,使其也适用于负数:

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

    注意,与位运算符相比,Math方法的优点在于,它们使用的数字超过231。


    1
    2
    var remainder = x % y;
    return (x - remainder) / y;


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

    1
    parseInt(a/b)

    要获取余数,请使用mod operator:

    1
    a%b

    parseint有一些字符串的缺陷,以避免使用基数为10的基数参数。

    1
    parseInt("09", 10)

    在某些情况下,数字的字符串表示可以是一个科学的符号,在这种情况下,parseint将产生错误的结果。

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

    此调用将产生1。


    javascript根据负数的数学定义,正确计算负数和非整数的余数。

    楼层定义为"小于参数的最大整数",因此:

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

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

    javascript确实按预期计算了所有的东西,所以程序员必须小心地提出正确的问题(人们应该小心地回答被问到的问题!)雅林的第一个问题不是"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、Windows7或我的CPU的FPU的问题)。但是对于Yarin的问题,它只涉及整数,gammax的代码工作得很好。


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

    第一个问题示例:

    1
    2
    3
    4
    5
    var x = 5;
    var y = 10.4;
    var z = Math.floor(x + y);

    console.log(z);

    慰问:

    15

    第二个问题的例子:

    1
    2
    3
    4
    5
    var x = 14;
    var y = 5;
    var z = Math.floor(x%y);

    console.log(x);

    慰问:

    4


    亚历克斯·摩尔·尼米的评论作为答案:

    对于google搜索divmod中的ruby用户,您可以这样实现它:

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

    结果:

    1
    // [2, 33]


    我通常使用:

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

    它可能不是最优雅的,但它很管用。


    计算页数可以一步完成:数学,CEL(X/Y)


    如果只使用两个幂除,则可以使用位运算符:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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];
    }

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


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

    这对于检查日常生活中的许多情况(银行帐号、信用卡等)中出现的许多支票数字的情况尤其重要。

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

    1
    str = '123456789123456789123456789'

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

    1
    digits = 9 - String(divisor).length

    准备正则表达式以拆分字符串

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

    例如,如果digits为7,则regexp为

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

    它匹配一个最大长度为7的非空子字符串,该子字符串的后面((?=...)是一个正的lookahead),是7的倍数。"g"是使表达式在所有字符串中运行,而不是在第一次匹配时停止。

    现在,将每个部分转换为整数,并用reduce计算余数(加上前一个余数-或0-乘以正确的10次方):

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

    这将工作,因为"减法"余数算法:

    1
    n mod d = (n - kd) mod d

    它允许用余数代替数字的小数表示的任何"初始部分",而不影响最终余数。

    最后的代码看起来像:

    1
    2
    3
    4
    5
    6
    7
    8
    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);
    }

    这将始终截断为零。不确定是不是太迟了,但接下来是:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    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
        };
    }

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

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

    如果数字是正数,一切都好。如果数字是负数,那么它将加1,因为math.floor处理负数的方式。