2010-04-11 7 views
2

Je rencontre des problèmes de vitesse avec mon programme C# et j'ai constaté que ce calcul de pourcentage provoquait un ralentissement. Le calcul est simplement n/d * 100. Le numérateur et le dénominateur peuvent être n'importe quel nombre entier. Le numérateur ne peut jamais être supérieur au dénominateur et n'est jamais négatif. Par conséquent, le résultat est toujours de 0-100. À l'heure actuelle, cela se fait simplement en utilisant les mathématiques à virgule flottante et est un peu lent, car il est calculé des dizaines de millions de fois. Je n'ai vraiment besoin de rien de plus précis que le 0,1 pour cent le plus proche. Et, j'utilise simplement cette valeur calculée pour voir si elle est plus grande qu'une valeur constante fixe. Je pense que tout devrait être gardé comme un entier, donc la gamme avec une précision de 0,1 serait 0-1000. Y at-il un moyen de calculer ce pourcentage sans calcul à virgule flottante?Division à la première décimale près sans calcul à virgule flottante?

Voici la boucle que j'utilise avec le calcul:

for (int i = 0; i < simulationList.Count; i++) 
{ 
    for (int j = i + 1; j < simulationList.Count; j++) 
    { 
     int matches = GetMatchCount(simulationList[i], simulationList[j]); 
     if ((float)matches/(float)simulationList[j].Catchments.Count > thresPercent) 
     { 
      simulationList[j].IsOverThreshold = true; 
     } 
    } 
} 
+0

Je suppose que c'est une boucle assez clairsemée/serrée où cela pourrait causer un tel goulot d'étranglement. Pouvons-nous le voir? – spender

+1

Je suppose que si c'est vraiment ce qui ralentit votre programme, les effets de cache joueront probablement un aussi grand rôle que la différence entre les maths entiers et flottants. En outre boxe/unboxing ou toute autre chose qui pourrait causer l'allocation je m'attendrais à avoir un effet plus grand que les opérations de maths. – Weeble

+0

Je viens d'ajouter la boucle que j'utilise au message. –

Répondre

6

Au lieu de n/d > c, vous pouvez utiliser n > d * c (en supposant que d > 0).
(c est la valeur constante que vous comparez à.)

De cette façon, vous n'avez pas besoin division du tout.

Cependant, faites attention aux débordements.

+1

C'est bien, car il supprime même complètement la division, ce qui est généralement plus cher que la multiplication. –

+3

De nos jours, la division et la multiplication coûtent la même chose sur les processeurs modenr. –

+0

@Loadmaster: la multiplication d'entier n'est-elle pas moins coûteuse que la conversion d'ints en floats et division en virgule flottante? – Vlad

0

Si vos unités sont en dixièmes au lieu de ceux, alors vous pouvez obtenir votre précision en utilisant l'arithmétique 0,1 entier:

Au lieu de:

for (...) 
{ 
    float n = ...; 
    float d = ...; 

    if (n/d > 1.4) // greater than 140% ? 

... faire quelque chose comme:

for (...) 
{ 
    int n = 10 * ...; 
    int d = ...; 
    if (n/d > 14) // greater than 140% ? 
+0

Pour la vitesse, utilisez 'double' au lieu de' float'. –

+1

... ou même int :-) – Vlad

0

Au lieu d'écrire

if ((float)matches/(float)simulationList[j].Catchments.Count > thresPercent) 

écrire ceci:

if (matches * theresPercent_Denominator > simulationList[j].Catchments.Count * thresPercent_Numerator) 

De cette façon, vous débarrasser des points flottants.

Note: thresPercent peut être exprimé comme thresPercent_Numerator/theresPercent_Denominator, tant que le nombre est un nombre rationnel.) Je pense que c'est la façon optimale sur PC. Pour une autre plate-forme, vous pouvez encore l'optimiser en décalant vers la gauche ou vers la droite, si theresPercent_Denominator et/ou thresPercent_Numerator sont la puissance de 2. (Normalement, le décalage vers la gauche suffit, mais peut-être utiliser le décalage vers la droite pour réorganiser l'équation en division, pour éviter le débordement)

Questions connexes