如何最小化数学通话? (JavaScript)的

时间:2015-01-05 19:16:06

标签: javascript math

我正在做Codewars challenge,我必须使用参数a,b和amp;创建一个函数。 c对应于二次方程ax ^ 2 + bx + c = 0并求解x。目标不仅是解决x,还要尽可能减少花费的Math.sqrt调用次数。 (您还必须返回具有唯一解决方案的数组)。

我想出了一个解决方案:

function solveQuadratic(a, b, c) {
  if ((4*a*c > b*b) || ((a === 0) && (b === 0))) { return undefined;}
  else if (a === 0) {return [-c/b];}
  else {
   var xVals = [];
   var sqrt = Math.sqrt(b*b - 4*a*c);
   xVals.push((-b - sqrt)/2*a);
   xVals.push((-b + sqrt)/2*a);
   if (xVals[0] === xVals[1]) {xVals.pop();}
   return xVals;
  }
}

我收到了错误消息:

  

您使用6个Math.sqrt调用传递了测试。   您应该能够通过4次或更少次Math.sqrt调用传递这些测试。

我认为将表达式的平方根部分的结果存储在变量(sqrt)中会阻止它被多次调用以评估表达式并为变量赋值。但事实并非如此。

所以我有几个问题:

  • 有没有办法存储(静态)值,以便在您的代码中使用它时不需要重新评估它?
  • 这个解决方案中是否有一些显而易见的东西,除了它制作太多的Math.sqrt电话之外?

4 个答案:

答案 0 :(得分:3)

添加c为零时的案例:

....
var sqrt = c==0?Math.abs(b):Math.sqrt(b*b - 4*a*c);
....

<强> [编辑]

此外,要通过所有测试,您的解决方案在分割时需要括号:

xVals.push((-b - sqrt)/(2*a));
xVals.push((-b + sqrt)/(2*a));

答案 1 :(得分:2)

一种简单的方法是使用memoization。使用闭包来保留使用的静态值列表,这样就不会为已经计算的值调用Math.sqrt

var cachingSqrt = (function() {
    var inputs = {};
    return function(val) {
        if (inputs.hasOwnProperty(val)) {
            return inputs[val];
        } else {
            return inputs[val] = Math.sqrt(val);
        }
    }
})();

这个过程的概括将是

function createCachedResults(fn, scope) {
    var inputs = {};
    return function(val) {
        if (inputs.hasOwnProperty(val)) {
            return inputs[val];
        } else {
            return inputs[val] = fn.call(scope, val);
        }
    }
}

cachingSqrt  = createCachedResults(Math.sqrt, Math);

你可以像

一样使用它
var cachingSquareRoot = createCachedResults(Math.sqrt, Math);
function solveQuadratic(a, b, c) {
    if ((4*a*c > b*b) || ((a === 0) && (b === 0))) { 
        return undefined;
    }
    else if (a === 0) {
         return [-c/b];
    } else {
        var xVals = [];
        var sqrt = cachingSquareRoot(b*b - 4*a*c);
        xVals.push((-b - sqrt)/2*a);
        xVals.push((-b + sqrt)/2*a);
        if (xVals[0] === xVals[1]) { 
            xVals.pop();
        }
        return xVals;
    }
}

答案 2 :(得分:2)

关键是在Math.sqrt(x)x === 0时避免x === b^2,因为答案已经知道。这两种情况发生在b^2 === 4ac4ac === 0时,因此代码需要将这两种情况短路以避免额外的Math.sqrt()次调用。

所以,所有特殊情况都是:

  • b^2 - 4ac < 0a === 0 && b === 0回答undefined
  • a === 0时(在这种情况下,等式是线性的,而不是二次的)所以答案是-c / b
  • c === 0 4ac === 0 -b / a只有0b^2 - 4ac === 0
  • -b / (2 * a)在哪种情况下答案只是Math.sqrt()

结合使用Ruud的建议和Joanvo建议的固定版本,它只会传递4个function solveQuadratic(a, b, c) { var delta = (b * b) - (4 * a * c), sqrt; if ((delta < 0) || ((a === 0) && (b === 0))) { return undefined; } else if (a === 0) { return [-c / b]; } else if (c === 0) { return b === 0 ? [0] : [-b / a, 0]; } else if (delta == 0) { return [-b / (2 * a)]; } else { sqrt = Math.sqrt(delta); return [(-b - sqrt) / (2 * a), (-b + sqrt) / (2 * a)]; } } 来电:

Math.sqrt()

这是一个基于上述版本的版本,并添加了Juan的答案中的缓存。在初始标准测试中,仅报告一次function solveQuadratic(a, b, c) { var delta = (b * b) - (4 * a * c), sqrt; if ((delta < 0) || ((a === 0) && (b === 0))) { return undefined; } else if (a === 0) { return [-c / b]; } else if (c === 0) { return b === 0 ? [0] : [-b / a, 0]; } else if (delta == 0) { return [-b / (2 * a)]; } else { sqrt = sqrt2(delta); return [(-b - sqrt) / (2 * a), (-b + sqrt) / (2 * a)]; } } var sqrt2 = (function() { var cache = {0:0, 1:1, 4:2, 9:3}; return function(x) { if (cache.hasOwnProperty(x)) { return cache[x]; } else { var result = Math.sqrt(x); cache[x] = result; return result; } } })(); 操作。

{{1}}

答案 3 :(得分:1)

您应该为discriminant为零的情况添加快捷方式。

...
else if (b*b == 4*a*c) return [-b / (2*a)];
...