简体   繁体   English

如何减少数学调用? (JavaScript)

[英]How to minimize Math calls? (Javascript)

I'm doing a Codewars challenge in which I have to create a function with the parameters a, b & c corresponding to the quadratic equation ax^2 + bx + c = 0 and solve for x. 我正在执行Codewars挑战 ,其中我必须创建一个参数a,b和c与对应于二次方程ax ^ 2 + bx + c = 0的函数,并求解x。 The goal is not only to solve for x, but to minimize the number of spendy Math.sqrt calls. 目标不仅是解决x,而且还应尽量减少浪费的Math.sqrt调用次数。 (You also have to return an array with the unique solution(s)). (您还必须返回具有唯一解决方案的数组)。

I came up with a solution: 我想出了一个解决方案:

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

I got the error message: 我收到错误消息:

You passed the tests using 6 Math.sqrt calls. 您通过6个Math.sqrt调用通过了测试。 You should be able to pass these tests with 4 Math.sqrt calls or less. 您应该能够通过4个Math.sqrt调用或更少调用来通过这些测试。

I thought storing the result of the square root part of the expression in a variable (sqrt) would prevent it from being called more than that one time to evaluate the expression and assign a value to the variable. 我认为将表达式的平方根部分的结果存储在变量(sqrt)中可以防止多次调用它来评估表达式并将值分配给变量。 But that's not the case. 但是事实并非如此。

So I have a couple of questions: 所以我有几个问题:

  • Is there a way to store a (static) value so that it doesn't need to be reevaluated any time it's used in your code? 有没有一种方法可以存储(静态)值,以便在您的代码中使用它时无需重新评估它?
  • Is there something obvious I'm missing from this solution besides the fact that it's making too many Math.sqrt calls? 除了它调用Math.sqrt太多之外,该解决方案还缺少其他明显的东西吗?

Add a case for when c is zero: 添加当c为零时的情况:

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

[Edit] [编辑]

Also, to pass all the tests, your solution needs parenthesis when dividing here: 另外,要通过所有测试,请在此处进行拆分时,解决方案需要带括号:

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

An easy way is to use memoization . 一种简单的方法是使用备忘录 Use a closure to keep a static list of values used so you don't call Math.sqrt for values you've already calculated 使用闭包来保留使用的值的静态列表,这样就不必为已计算出的值调用Math.sqrt

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

A generalization of this process would be 这个过程的概括将是

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

And you could use it like 你可以像这样使用它

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

The key is to avoid Math.sqrt(x) when x === 0 and when x === b^2 since the answer is already known. 关键是在x === 0x === b^2时避免Math.sqrt(x) ,因为已知答案。 These two situations occur when b^2 === 4ac and when 4ac === 0 , so the code needs to short circuit those two cases to avoid the extra Math.sqrt() calls. b^2 === 4ac4ac === 0 ,会发生这两种情况,因此代码需要将这两种情况短路,以避免额外的Math.sqrt()调用。

So, all the special cases are: 因此,所有特殊情况是:

  • When b^2 - 4ac < 0 or a === 0 && b === 0 which make the answer undefined . b^2 - 4ac < 0a === 0 && b === 0 ,答案undefined
  • When a === 0 (in which case the equation is linear, not quadratic) so the answer is -c / b . a === 0 (在这种情况下,方程是线性的,不是二次方程)时,答案是-c / b
  • When c === 0 which makes 4ac === 0 so it's just -b / a and 0 . c === 0 ,使4ac === 0所以它只是-b / a0
  • When b^2 - 4ac === 0 in which case the answer is just -b / (2 * a) b^2 - 4ac === 0时,答案仅为-b / (2 * a)

Using a combination of Ruud's suggestion and a fixed version of Joanvo's suggestion, it will pass with only 4 Math.sqrt() calls with this: 使用Ruud的建议和Joanvo的建议的固定版本的组合,它将仅通过以下四个Math.sqrt()调用来传递:

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

Here's a version that builds on the above version and adds the cache from Juan's answer. 这是一个基于上述版本的版本,并从Juan的答案中添加了缓存。 In the initial standard test, this reports only one Math.sqrt() operation. 在初始标准测试中,这仅报告一个Math.sqrt()操作。

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

You should add a shortcut for cases where the discriminant is zero. 对于判别为零的情况,您应该添加快捷方式。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM