There is a fast square root approach through a linear equation:
L(x) = f(a) + f'(a)*(x-a)
For a given value a
where the function has a known value and f'(_)
being the derivative of the function. By coincidence, the derivative of the square root is half the inverse of the square root.
The square root value is fully known in perfect squares, so let’s treat a
as a perfect square, and f(a)
its entire root.
So the approximation formula can be transformed like this:
(x-a)
sqrt_approx(x) = sqrt_int(a) + -------------
2*sqrt_int(a)
For the approach to work, I need to choose a a
close enough to x
.
So our algorithm now boils down to:
- find
a
perfect square (and its entire root sqrt_int(a)
) closest to x
- apply the formula
Roughly speaking, that would be:
function sqrt_approx(x) {
let sqrt_a = raiz_do_quadrado_mais_proximo(x);
let a = sqrt_a * sqrt_a;
// se x for um quadrado perfeito, x-a resultará em zero e a resposta será sqrt_a
return sqrt_a + (x-a)/(2*sqrt_a);
}
Great, now we just need to define who is the closest square to x
. Since we’re dealing with real numbers, it doesn’t make sense to investigate negative number roots, so I’m going to reduce the search set to positive ones only. The idea is very simple: from 0 to infinity, checking the distance from the square of the iteration variable to the x
. At the moment there is an inflection (ie, the distance ceases to be negative and becomes positive), return either the current element of the iteration or the previous element, according to the square closest to x
:
function raiz_do_quadrado_mais_proximo(x) {
let i = 0;
while (true) {
let ii = i * i;
if (ii - x > 0) {
let dist_ii = x - ii;
let dist_ant = x - (i-1)*(i-1);
if (dist_ii < 0) {
dist_ii *= -1;
}
if (dist_ant < 0) {
dist_ant *= -1;
}
return dist_ant < dist_ii? i-1: i;
}
}
}
The above code can be trivially optimized for:
function raiz_do_quadrado_mais_proximo(x) {
let i = 0;
while (i*i < x) { // itera até a inflexão
i++;
}
let dist_ii = i*i - x; // i*i >= x garantido, depois da inflexão, daí dist_ii está sendo calculado já positivo
let dist_ant = x - (i-1)*(i-1); // antes da inflexão, x será maior que o quadrado, daí dist_ant está sendo calculado já positivo
return dist_ant < dist_ii? i-1: i;
}
Put it all together, we got:
function faz_leitura(form) {
let x = Number(document.getElementById("quad").value);
let raiz_apprx = sqrt_approx(x);
let err = x - (raiz_apprx * raiz_apprx);
if (err < 0) {
err = -err;
}
document.write("<div>Raiz quadrada aproimada de " + x + " é " + raiz_apprx + ", com erro de " + err + "</div>");
}
function raiz_do_quadrado_mais_proximo(x) {
let i = 0;
while (i*i < x) {
i++;
}
let dist_ii = i*i - x;
let dist_ant = x - (i-1)*(i-1);
return dist_ant < dist_ii? i-1: i;
}
function sqrt_approx(x) {
let sqrt_a = raiz_do_quadrado_mais_proximo(x);
let a = sqrt_a * sqrt_a;
// se x for um quadrado perfeito, x-a resultará em zero e a resposta será sqrt_a
return sqrt_a + (x-a)/(2*sqrt_a);
}
<form onsubmit="faz_leitura(this); return false;">
<div>
<input required type="text" id="quad"/>
<label>valor a ser calculada a raiz</label>
</div>
<button type="submit">SQRT</button>
</form>
Puts
var resultado
outside thefor
and onlyresultado = ...
within.– Sergio
If it is to be "manually" there is no reason to use javascript, just paper and pencil.
– anonimo
Are you trying to make a
do{...}while(...);
or awhile(...){...}
?– fernandosavio
Manually in order not to use Math.sqrt() @anonimo
– Samuel Barbosa