C# Perché la divisione è più lenta della moltiplicazione?
Nei linguaggi di programmazione e in particolare C# ci sono 4 operazioni aritmetiche che possono essere eseguite: addizione, sottrazione, moltiplicazione e divisione.
E da una prospettiva esterna, può sembrare che siano tutti simili in termini di prestazioni, ma risulta che uno di loro è molto più lento rispetto agli altri 3.
Quale è più lento potresti chiedere? Divisione.
Secondo questo documento HP:
La divisione in virgola mobile e la radice quadrata richiedono molto più tempo per essere calcolate rispetto all'addizione e alla moltiplicazione. Gli ultimi due vengono calcolati direttamente mentre i primi vengono solitamente calcolati con un algoritmo iterativo. L'approccio più comune consiste nell'utilizzare un'iterazione Newton-Raphson senza divisioni per ottenere un'approssimazione al reciproco del denominatore (divisione) o della radice quadrata reciproca, quindi moltiplicare per il numeratore (divisione) o l'argomento di input (radice quadrata).
Per verificare quanto affermato sopra ho deciso di eseguire un semplice test utilizzando il codice seguente:
//Generate two random numbers
var rand = new System.Random();
float a = rand.Next();
float b = rand.Next();
Debug.Log("Number a: " + a + " Number b: " + b);
System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
watch.Start();
//Addition
for (int i = 1; i < 1000000; i++)
{
float tmp = a + b;
}
watch.Stop();
//Output
Debug.Log("Addition took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");
watch.Reset();
watch.Start();
//Subtraction
for (int i = 1; i < 1000000; i++)
{
float tmp = a - b;
}
watch.Stop();
//Output
Debug.Log("Subtraction took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");
watch.Reset();
watch.Start();
//Multiplication
for (int i = 1; i < 1000000; i++)
{
float tmp = a * b;
}
watch.Stop();
//Output
Debug.Log("Multiplication took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");
watch.Reset();
watch.Start();
//Division
for (int i = 1; i < 1000000; i++)
{
float tmp = a / b;
}
watch.Stop();
//Division
Debug.Log("Division took: " + watch.Elapsed.TotalSeconds.ToString("0.0000") + " seconds");
Fondamentalmente, ho eseguito un milione di addizioni, sottrazioni, moltiplicazioni e divisioni per i due numeri casuali e ho misurato il tempo impiegato da ciascuno di essi per elaborarli, il test è stato ripetuto 5 volte ed ecco il risultato:
- L'aggiunta ha richiesto in media 0,0004 secondi
- La sottrazione ha richiesto in media 0,0003 secondi
- La moltiplicazione ha richiesto in media 0,0003 secondi
- La divisione ha richiesto in media 0,0044 secondi
Il risultato ha mostrato che addizione, sottrazione e moltiplicazione sono simili in termini di prestazioni, ma la divisione sembra essere più lenta di circa il 1100%.
Una differenza non da poco, che porta a concludere che è sempre meglio usare, quando possibile, la moltiplicazione anziché la divisione. Ad esempio, quando devi dividere il numero per 2, è meglio moltiplicarlo per 0,5.