janvier
2009
La semaine dernière, j’ai vu, dans notre base de code, le code suivant:
double result = _value / divisor;
return (int)result == result;
}
Sur le coup, je me suis demandé l’intérêt de la fonction. Apres un peu de recherches, c’était un bout de code écrit il y’a quelque temps par un stagiaire, pour optimiser les tests de division.
Par curiosité, j’ai fait le test suivant:
public static double _value;
public static void Main() {
int nbdiv = 0;
int nbdivV2 = 0;
DateTime start = DateTime.Now;
for (int i = 0; i < 100000; i++) {
_value = i;
for (int j = 1; j < 10; j++)
if (EstDivisiblePar(j)) nbdiv++;
}
TimeSpan elapsed = DateTime.Now - start;
Console.WriteLine(elapsed.TotalMilliseconds.ToString());
start = DateTime.Now;
for (int i = 0; i < 100000; i++) {
_value = i;
for (int j = 1; j < 10; j++)
if (EstDivisibleParV2(j)) nbdivV2++;
}
elapsed = DateTime.Now - start;
Console.WriteLine(elapsed.TotalMilliseconds.ToString());
Console.WriteLine(nbdiv);
Console.WriteLine(nbdivV2);
Console.ReadLine();
}
public static bool EstDivisiblePar(double diviseur) {
return (_value % diviseur == 0);
}
public static bool EstDivisibleParV2(double diviseur) {
double res = _value / diviseur;
return (int)res == res;
}
}
Sur 900 000 itérations, sur ma machine (avec tout qui tourne, un Visual Studio, un Lotus, et cætera, et cætera…), on arrive a une différence entre les deux fonctions de 15 millisecondes, sur une fonction, qui n’a probablement pas été utilisée autant en trois ans.
Sauf que…
Sauf que, si le reste de la division _value par diviseur est supérieur a int.MaxValue (ce qui est hautement improbable sur l’application d’origine), on va avoir un dépassement de capacité, et les valeurs de retour risquent d’être assez amusantes.
Et que je suis tombe sur cette fonction dans une bibliothèque qui est partagée entre plusieurs applications, dont une qui pourrait, éventuellement, causer ce genre de dépassement :/
Allez, on repasse au modulo
3 Commentaires + Ajouter un commentaire
Articles récents
Archives
- janvier 2014
- septembre 2013
- août 2013
- mai 2013
- avril 2013
- janvier 2013
- août 2012
- juin 2012
- mai 2012
- avril 2012
- mars 2012
- novembre 2011
- septembre 2011
- août 2011
- juillet 2011
- juin 2011
- mai 2011
- avril 2011
- février 2011
- janvier 2011
- novembre 2010
- octobre 2010
- septembre 2010
- août 2010
- juillet 2010
- juin 2010
- mai 2010
- avril 2010
- mars 2010
- février 2010
- janvier 2010
- décembre 2009
- novembre 2009
- octobre 2009
- septembre 2009
- août 2009
- juillet 2009
- juin 2009
- mai 2009
- avril 2009
- mars 2009
- février 2009
- janvier 2009
> la première règle de l’optimisation est simple : on n’optimise pas tant qu’on n’a pas trouvé l’origine exacte des mauvaises performances
+ int.MaxValue
> Pour les tests de perfs il est préférable d’utiliser System.Diagnostics.Stopwatch
Oui, c’est sur…c’était pour un test rapide d’ordre de grandeur avec SnippetCompiler, j’avais la flemme de retrouver le namespace pour le stopwatch (je sais, c’est mal)
Pour info, avec les durées stopwatch/datetime:
EstDivisiblePar : 48 / 46.8747
EstDivisibleParV2 : 29 / 31.2498
+1 concernant la remarque de Vincent Lainé !
Il me semble que le DateTime de C# correspond à peu près au System.currentTimeMillis() de Java, qui n’est réinitialisé que toutes les 15/16ms sous Windows…
Le gros problème des optimisations, c’est qu’elle sont souvent inutile et qu’elles peuvent amener à d’autres problèmes bugs…
Pourtant la première règle de l’optimisation est simple : on n’optimise pas tant qu’on n’a pas trouvé l’origine exacte des mauvaises performances
a++
Une petite chose par rapport au code utilisé pour le test. Il est dommage et même faux d’utiliser le DateTime pour effectuer le calcul du temps passé. En effet le DateTime.Now est soumis au bon vouloir de l’OS qui peux tout à fait reporter l’évaluation à plus tard.
Pour les tests de perfs il est préférable d’utiliser System.Diagnostics.Stopwatch