2016-01-18 1 views
3

Je travaille sur une fonction gamma qui génère une "courbe S". Je dois l'exécuter dans un environnement en temps réel, donc je dois l'accélérer autant que possible.Comment puis-je optimiser cette fonction de courbe en S?

Le code est le suivant:

float Gamma = 2.0f; //Input Variable 

float GammaMult = pow(0.5f, 1.0f-Gamma); 
if(Input<1.0f && Input>0.0f) 
{ 
    if(Input<0.5f) 
    { 
     Output = pow(Input,Gamma)*GammaMult; 
    } 
    else 
    { 
     Output = 1.0f-pow(1.0f-Input,Gamma)*GammaMult; 
    } 
} 
else 
{ 
    Output = Input; 
} 

Est-il possible que je peux optimiser ce code?

+0

flotteur Gamma = 2,0f; // La variable d'entrée devrait être dynamique, n'est-ce pas? –

+0

sa dynamique oui, juste configurer comme ceci à des fins d'exemple. – user2339945

+1

3 mots: LUT :) – Rotem

Répondre

3

Vous pouvez éviter pipeline stalls en éliminant la ramification sur Input<1.0f && Input>0.0f si le jeu d'instructions prend en charge saturation arithmetic ou utiliser max/min intrinsics, par exemple x86 MAXSS

Vous devez également éliminer l'autre ramification en arrondissant le Input saturé. Algorithme complet:

float GammaMult = pow(0.5f, 1.0f-Gamma); 
Input = saturate(Input); // saturate via assembly or intrinsics 
// Input is now in [0, 1] 
Rounded = round(Input); // round via assembly or intrinsics 
Coeff = 1 - 2 * Rounded 
Output = Rounded + Coeff * pow(Rounded + Coeff * Input,Gamma)*GammaMult; 

L'arrondi doit être effectué via asm/intrinsics as well.

Si vous utilisez cette fonction par ex. les valeurs successives d'un tableau que vous devriez envisager de vectoriser si l'architecture cible supporte SIMD.

+0

Quel est l'avantage d'arrondir ici? Le code original ne semble pas vouloir que le résultat soit arrondi à un nombre entier, et vous n'obtiendrez pas plus de performances en évitant les opérations à virgule flottante en faveur des opérations entières tant que vous utilisez l'instruction 'FRNDINT' car cela laisse le résultat sur la pile de virgule flottante. –

+0

@CodyGray rounding est utilisé pour générer les coefficients de sorte qu'il n'aura pas besoin de se brancher sur 'Input <0.5'. Par exemple: 'Coeff = 1 - 2 * Rounded' sera 1 si' Input <0.5' et -1 si 'Input> 0.5', donc ce qui était une branche dans l'algorithme original devient une instruction round, un multiple virgule flottante et un ajout à virgule flottante -> pipelining ne souffrira pas. –

+0

Oh, bien sûr! Très intelligent. J'avais manqué cela dans ma lecture rapide. –

0

Votre code semble bien. Le goulot d'étranglement, s'il existe, est la fonction pow. La seule solution est d'aller un peu plus loin dans les détails de bas niveau et d'essayer d'implémenter votre propre fonction pow. Par exemple, si 2 chiffres flottants sont suffisants pour vous, vous pouvez trouver des algorithmes basés sur l'approximation qui sont plus rapides.

Voir ceci: The most efficient way of implementing pow() function in floating point

+1

Une autre bonne référence pour implémenter une fonction pow optimisée personnalisée est ici: http://stackoverflow.com/a/16782797 –