[英]How to minimize Math calls? (Javascript)
我正在執行Codewars挑戰 ,其中我必須創建一個參數a,b和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)中可以防止多次調用它來評估表達式並將值分配給變量。 但是事實並非如此。
所以我有幾個問題:
添加當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));
一種簡單的方法是使用備忘錄 。 使用閉包來保留使用的值的靜態列表,這樣就不必為已計算出的值調用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;
}
}
關鍵是在x === 0
且x === b^2
時避免Math.sqrt(x)
,因為已知答案。 當b^2 === 4ac
和4ac === 0
,會發生這兩種情況,因此代碼需要將這兩種情況短路,以避免額外的Math.sqrt()
調用。
因此,所有特殊情況是:
b^2 - 4ac < 0
或a === 0 && b === 0
,答案undefined
。 a === 0
(在這種情況下,方程是線性的,不是二次方程)時,答案是-c / b
。 c === 0
,使4ac === 0
所以它只是-b / a
和0
。 b^2 - 4ac === 0
時,答案僅為-b / (2 * a)
使用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)];
}
}
這是一個基於上述版本的版本,並從Juan的答案中添加了緩存。 在初始標准測試中,這僅報告一個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;
}
}
})();
對於判別為零的情況,您應該添加快捷方式。
...
else if (b*b == 4*a*c) return [-b / (2*a)];
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.