View Full Version : Divagazione sui massimi sistemi...
blackskop
27-12-2010, 21:06
Mi sono imbattuto in questa riga di codice
A) (x - y == 2 || x - y == -2)
e mi sono detto: "E' leggibile ma non sarebbe più efficiente in questo modo?"
B) Math.abs(x - y) == 2
e dopo un nanosecondo l'ho modificata in
C) (x - y) * -1 == -2
ma in conclusione ancora non riesco a capire qual è il giusto compromesso tra velocità e leggibilità.
A B C
Leggibilità: 3 2 1
Efficienza: 2 1 3
Se le empiriche considerazioni non sono errate, la tabellina mi porterebbe a scegliere la soluzione A ma, dato che non sono poi un microcefalo, pensando anche al famoso detto "in medio stat virtus", ho optato per la soluzione C.
Voi avete qualche altro suggerimento?
Concordo sulla scelta C , della leggibilità me ne frego (faccio i commenti sopra piuttosto) però il codice è molto meglio
Don[ITA]
27-12-2010, 22:16
Scusate, ma siete proprio sicuri che C sia equivalente ad A e B?
Se ad esempio:
x = 0
y = 2
A) (0 - 2 == 2 || 0 - 2 == -2) -> vero
B) Math.abs(0 - 2) == 2 -> vero
C) (0 - 2) * -1 == -2 -> falso
:mbe:
O sono solo ubriaco io?? :eek:
ma infatti la c è sbagliata
e secondo me la b non è più efficiente della a
ps: a supporto della tesi
public class Test {
static public void main(String[] args) {
long t[] = new long[3];
int x = 0, y = 2;
t[0] = System.nanoTime();
for (int i = 0; i < 500000; i++) {
if (x - y == 2 || x - y == -2)
continue;
}
t[1] = System.nanoTime();
for (int i = 0; i < 500000; i++) {
if (Math.abs(x - y) == 2)
continue;
}
t[2] = System.nanoTime();
System.out.println(t[1] - t[0]);
System.out.println(t[2] - t[1]);
}
}
output:
1729179
4147813
Supdario
27-12-2010, 22:48
Quoto, l'opzione più veloce è la A, la C mi sembra sbagliata, e se la B magari è più leggibile, è comunque più lenta della A.
Che FAIL ... non avevo letto il *-1 .. avevo visto *1... :zzz: :bsod:
sarebbe comunque sbagliata :E
blackskop
27-12-2010, 22:58
Si la C è sbagliata ma non ho detto che la B è più veloce della A. In teoria la più veloce dovrebbe essere la C, se fosse corretta! Quindi, alternative non ce ne sono?
public class Test {
static public void main(String[] args) {
long t[] = new long[4];
int x = 0, y = 2;
t[0] = System.nanoTime();
for (int i = 0; i < 500000; i++) {
if (x - y == 2 || x - y == -2)
continue;
}
t[1] = System.nanoTime();
for (int i = 0; i < 500000; i++) {
if (Math.abs(x - y) == 2)
continue;
}
t[2] = System.nanoTime();
for (int i = 0; i < 500000; i++) {
if ((x - y) * -1 == -2)
continue;
}
t[3] = System.nanoTime();
System.out.println(t[1] - t[0]);
System.out.println(t[2] - t[1]);
System.out.println(t[3] - t[2]);
}
}
2363279
5412704
949930
e grazie al cazzo, la C fa un controllo in meno :asd: tant'è che è sbagliata
che confronto è? :asd:
Supdario
27-12-2010, 23:52
In ogni caso non mi sembra il massimo prendere come riferimento il C# per misurare l'ottimizzazione. :asd: Magari con un compilatore C/C++ (e relative impostazioni di ottimizzazione attivate) avrebbe dato risultati diversi. Ma in questo caso sono scontate le opzioni, anche se la C è concettualmente sbagliata.
blackskop
27-12-2010, 23:53
e grazie al cazzo, la C fa un controllo in meno :asd: tant'è che è sbagliata
che confronto è? :asd:
Ma guarda che anche se inizializzi la y a -2 i tempi sono gli stessi.
P.s. potresti anche moderare un po' il linguaggio...
blackskop
27-12-2010, 23:54
In ogni caso non mi sembra il massimo prendere come riferimento il C# per misurare l'ottimizzazione. :asd: Magari con un compilatore C/C++ (e relative impostazioni di ottimizzazione attivate) avrebbe dato risultati diversi. Ma in questo caso sono scontate le opzioni, anche se la C è concettualmente sbagliata.
Si tratta di Java ma il ragionamento dovrebbe prescindere dal linguaggio e da ottimizzazioni specifiche.
Supdario
27-12-2010, 23:58
Si tratta di Java ma il ragionamento dovrebbe prescindere dal linguaggio e da ottimizzazioni specifiche.
Errore mio. :asd:
Quando si parla di semplici operazioni matematiche è facile capire, ma ad esempio richiamare il metodo Math.Abs in un linguaggio interpretato ha una velocità diversa dal richiamare "abs" in C/C++, ma in questo caso è abbastanza chiaro quale sia il più veloce.
Ma guarda che anche se inizializzi la y a -2 i tempi sono gli stessi.
P.s. potresti anche moderare un po' il linguaggio...ovviamente, perché in quel caso
questo if
if (x - y == 2 || x - y == -2)
fa un solo or, il primo che è true e quindi ritorna senza processare il secondo, perché tanto tutta l'espressione è sicuramente true
non a caso avevo scelto il caso pessimo
il punto è che il secondo controllo la C non lo fa
blackskop
28-12-2010, 01:00
ovviamente, perché in quel caso
questo if
if (x - y == 2 || x - y == -2)
fa un solo or, il primo che è true e quindi ritorna senza processare il secondo, perché tanto tutta l'espressione è sicuramente true
non a caso avevo scelto il caso pessimo
il punto è che il secondo controllo la C non lo fa
No se cambi il valore di inizializzazione della y il controllo lo fa e i tempi non cambiano affatto e sono circa 1/2 del caso A, mentre col valore attuale di y i tempi sono in media 1/3 ma è il caso A che varia!
Comunque a prescindere da questo, c'è un ulteriore modo più efficiente di A e B?
In ogni caso non mi sembra il massimo prendere come riferimento il C# per misurare l'ottimizzazione. :asd: Magari con un compilatore C/C++ (e relative impostazioni di ottimizzazione attivate) avrebbe dato risultati diversi. Ma in questo caso sono scontate le opzioni, anche se la C è concettualmente sbagliata.per curiosità ho voluto anche provare in C++, la differenza si è molto assottigliata, ma c'è una cosa abbastanza incredibile che vorrei che qualcuno mi spiegasse
ho scritto questo codice:
#include <climits>
#include <ctime>
#include <cmath>
#include <iostream>
#define N UINT_MAX
using namespace std;
int main(int argc, char *argv[])
{
clock_t t[3];
int x = 0, y = -2;
t[0] = clock();
for (unsigned int i = 0; i < N; i++)
{
if (x - y == 2 || x - y == -2)
continue;
}
t[1] = clock();
for (unsigned int i = 0; i < N; i++)
{
if (abs(x - y) == 2)
continue;
}
t[2] = clock();
cout << (double)(t[1] - t[0]) / CLOCKS_PER_SEC << "s" << endl;
cout << (double)(t[2] - t[1]) / CLOCKS_PER_SEC << "s" << endl;
return 0;
}
l'ho compilato con mingw con il comando
g++ -o asd.exe asd.cpp -lm
e l'ho eseguito, l'output è stato:
10.686s
13.005s
poi ho detto, va be', proviamo anche con le ottimizzazioni e ho compilato con
g++ -o asd.exe asd.cpp -O -lm
risultato:
1.833s
1.834s
la domanda è.. che cavolo di ottimizzazione ha fatto? O:
La B contiene una chiamata a funzione, che fa cose che non conosci.
Pure assumendo il caso ottimo che il compilatore riesce a realizzare l'inline, è sicuramente l'opzione più lenta.
La C invece è sbagliata.
Conclusione: meno massimi sistemi e più test dati alla mano :D
Supdario
28-12-2010, 12:25
per curiosità ho voluto anche provare in C++, la differenza si è molto assottigliata, ma c'è una cosa abbastanza incredibile che vorrei che qualcuno mi spiegasse
ho scritto questo codice:
#include <climits>
#include <ctime>
#include <cmath>
#include <iostream>
#define N UINT_MAX
using namespace std;
int main(int argc, char *argv[])
{
clock_t t[3];
int x = 0, y = -2;
t[0] = clock();
for (unsigned int i = 0; i < N; i++)
{
if (x - y == 2 || x - y == -2)
continue;
}
t[1] = clock();
for (unsigned int i = 0; i < N; i++)
{
if (abs(x - y) == 2)
continue;
}
t[2] = clock();
cout << (double)(t[1] - t[0]) / CLOCKS_PER_SEC << "s" << endl;
cout << (double)(t[2] - t[1]) / CLOCKS_PER_SEC << "s" << endl;
return 0;
}
l'ho compilato con mingw con il comando
g++ -o asd.exe asd.cpp -lm
e l'ho eseguito, l'output è stato:
10.686s
13.005s
poi ho detto, va be', proviamo anche con le ottimizzazioni e ho compilato con
g++ -o asd.exe asd.cpp -O -lm
risultato:
1.833s
1.834s
la domanda è.. che cavolo di ottimizzazione ha fatto? O:
In pratica ha eseguito un'ottimizzazione anche nelle zone limitrofe, ad esempio ha capito che x e y non cambiano mai, ed ha agito di conseguenza, traducendo il codice in questo modo:
int x = 0, y = -2;
int tmp = x-y; //Variabile temporanea
t[0] = clock();
bool condizione = (tmp == 2 || tmp == -2);
for (unsigned int i = 0; i < N; i++)
{
if (condizione)
continue;
}
t[1] = clock();
condizione = (abs(tmp) == 2);
for (unsigned int i = 0; i < N; i++)
{
if (condizione)
continue;
}
t[2] = clock();
Poi ovviamente la traduzione in codice macchina potrebbe aver subito ulteriori ottimizzazioni.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.