如何使用递归求解模数(不能使用*,%,/或Math运算符)

时间:2018-01-19 19:49:20

标签: javascript recursion

下面是我的代码完全正常,但我不允许使用'*'运算符。但在这种情况下,我不知道如何将负数转换为正数进行比较。一种选择是使用Math.abs,但我也不允许使用它。

var modulo = function(x, y) {

    if ( x === 0 && y ===0 ) return NaN;
    if ( x === y ) return 0;
    if ( x === 0 ) return 0;
    if (x > 0 && y > 0) {
        return x < y ? x : modulo(x-y,y);    
    }

    if ( x < 0 && y < 0 ) {

        return x*-1 < y*-1 ? x : modulo(x-y,y);
    }

    if( x > 0 && y < 0 ) {
        return x < y*-1 ? x : modulo(x+y,y);    
    }

    if ( x < 0 && y >0) {
        return x*-1 < y ? x : modulo(x+y,y);
    }
};

4 个答案:

答案 0 :(得分:2)

您可以使用一元减号运算符(-value)或从零(0 - value)减去数字来翻转数字符号。

无论哪种方式,都可以以比现在更简洁的方式实现模数:

var modulo = function(x, y) {
    if (y === 0) { return NaN; }

    if (x < 0) { return -modulo(-x,  y); }  // -27 %  4  -> -(27 % 4)

    if (y < 0) { return  modulo( x, -y); }  //  27 % -4  ->   27 % 4

    if (x < y) { return  x; }
    
    return modulo(x - y, y);
};

console.log(modulo( 27,  4));  //  3
console.log(modulo(-27,  4));  // -3
console.log(modulo( 27, -4));  //  3
console.log(modulo(-27, -4));  // -3
console.log(modulo(-32,  8));  //  0

仅用于奖励积分,这里是“真实”数学模的实现,也是在没有/*%的情况下实现的:

var mathModulo = function(x, y) {
    if (y <= 0) { return NaN; }

    if (x >= 0 && x < y) { return x; }
    
    return mathModulo(x - (x > 0 ? y : -y), y);
};

console.log(mathModulo( 27,  4));   // 3
console.log(mathModulo(-27,  4));   // 1
console.log(mathModulo( 27, -4));   // NaN
console.log(mathModulo(-27, -4));   // NaN
console.log(mathModulo(-32,  8));   // 0

答案 1 :(得分:1)

这是我怎么做的。你基本上只有几个案例:

  • 如果y0,请返回NaN
  • 如果y为负数,则转换为正数。
  • 如果x为否定,则答案为-modulo(-x,y)
  • 如果x小于y,则答案为x
  • 否则,答案与x - y modulo y相同(这是递归部分)

&#13;
&#13;
var modulo = function(x, y) {
    if (y === 0) return NaN;
    
    if (y < 0) y = -y;
    if (x < 0) return -modulo(-x, y);
    
    if (x < y) return x;
    return modulo(x - y, y);
};

console.log(modulo(4, 3), modulo(4, 3) === 4 % 3) // 1, true
console.log(modulo(-4, 3), modulo(-4, 3) === -4 % 3) // -1, true
console.log(modulo(4, -3), modulo(4, -3) === 4 % -3) // 1, true
console.log(modulo(-4, -3), modulo(-4, -3) === -4 % -3) // -1, true
&#13;
&#13;
&#13;

答案 2 :(得分:1)

我在Brainfuck完成了这项工作,你只有增量,减量和非零。以下是您如何做到这一点:

&#13;
&#13;
function modulo(n, m) {
  function helper(acc, steps, diff) {
    if (steps === 0) {
      return helper(acc, m, 0);
    } else if( acc === 0 ) {
      return diff;
    } else {
      return helper(acc - 1, steps - 1, diff + 1);
    }
  }
  return helper(n, m, 0);
}

console.log(12 % 5);
console.log(modulo(12, 5));
&#13;
&#13;
&#13;

我想你可以做这样的事情从消极变为积极:

function negToPos(a, b = 0) {
  return a === 0 ? b : negToPos(a+1, b+1);
}

以下是Brainfuck的样子:

[->-[>+>>]>[+[-<+>]>+>>]<<<<<]

参数传递就像当前单元格一样,下一个包含divident和divizor,你得到第三个模数,第四个除以模数。想象一下,我已经完成了sqrt并在这里做了一个lisp解释器:-O

你不会在任何这些中获得零分,但它会让你在冬天保持温暖。 (需要ES6,因为它会在没有TCO的情况下炸掉堆栈)

更新在撰写本文时,我不知道有任何ES6实施。只有部分完成,与标准相比,某些功能会出现异常。大多数实现缺少的功能之一是TCO,但这并不会使我的ES6语句错误,因为它们不是ES6实现,如果不是100%标准兼容的话。对于尚未开发的ES6实现,您可以看到他们在compatibility table

中实施的语言是什么部分

答案 3 :(得分:0)

您可以使用否定运算符。例如:

if ( x < 0 && y < 0 ) {

    return -x < -y ? x : modulo(x-y,y);
}