Una semplice funzione C per radici quadrate di numeri interi
Quando si lavora con i microcontrollori, spesso il coprocessore matematico per la virgola mobile (Floating Point) non è disponibile in hardware. Le toolchain, di solito, al giorno d'oggi forniscono una simulazione software dei numeri in virgola mobile e delle funzioni matematiche più comuni: questo però risulta piuttosto oneroso in termini di tempo computazionale, e può essere inutile dal punto di vista pratico, dato che i dati in ingresso sono normalmente numeri interi (ad esempio, gli ingressi di un convertitore A/D).
Nonostante ciò, alcune funzioni matematiche avanzate sono spesso necessarie. Una di esse è la radice quadrata. Il metodo di Newton-Raphson è probabilmente il più semplice ed efficace modo per calcolarla. Andando dritti al punto, questo è il codice C che può essere utile:
#define X_INIT (1 << 8) /* Arbitrary initial value for x */ unsigned long newton_sqrt(unsigned long z) { unsigned long x; unsigned long x_next = X_INIT; int maxiter = 8 * sizeof(z); while (x != x_next && maxiter-- > 0) { x = x_next; x_next = (x + z / x) / 2; } return x; }
Segue una breve spiegazione matematica.
Detto \(z\) il numero di cui si vuole trovare la radice quadrata, il problema è equivalente a trovare la soluzione dell'equazione: \(x ^ 2 - z = 0\)
In altre parole, detta \(y(x) = x ^ 2 - z\), stiamo cercando gli zeri di \(y(x)\). Ciò può essere ottenuto con il metodo di Newton-Raphson, che, per la nostra \(y(x)\), converge per ogni \(z\) >= 0. Tralasciando ogni dimostrazione, la formula iterativa è:
Siccome \(f'(x_{k}) = 2x_{k}\), si ottiene:
Tornando alla funzione C scritta sopra, la variabile x
è
\(x_{k}\), x_next
è \(x_{k+1}\), e il loop è ripetuto fino al
numero di bit del nostro numero intero.
L'unico parametro da essere scelto e ottimizzato è il valore iniziale
X_INIT
: dovrebbe essere scelto in maniera di essere il più vicino
possibile ai risultati tipici che ci aspettiamo.
Seguirà in futuro un altro articolo che analizzerà le prestazioni, accuratezza
e i possibili miglioramenti per la funzione newton_sqrt
.