Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 27/02/2014, à 12:57

Bigcake

[C] Votre avis : fonction longue ou courte ?

Bonjour,

Juste pour vous demander votre avis sur une fonction que j'ai écrite et qui fait 58 lignes

static unsigned char     GetSizeFlag(unsigned int blen)
{
  if (blen < (unsigned int) (1 << 5))
    return (SIZE_FILL_3);
  else if (blen < (unsigned int)(1 << 6))
    return (SIZE_FILL_2);
  else if (blen < (unsigned int)(1 << 7))
    return (SIZE_FILL_1);
  else if (blen < (unsigned int)(1 << 8))
    return (SIZE_NO_FILL);
  else if (blen < (unsigned int)(1 << 9))
    return (SIZE_FILL_7);
  else if (blen < (unsigned int)(1 << 10))
    return (SIZE_FILL_6);
  else if (blen < (unsigned int)(1 << 11))
    return (SIZE_FILL_5);
  else if (blen < (unsigned int)(1 << 12))
    return (SIZE_FILL_4);
  else if (blen < (unsigned int)(1 << 13))
    return (SIZE_FILL_3);
  else if (blen < (unsigned int)(1 << 14))
    return (SIZE_FILL_2);
  else if (blen < (unsigned int)(1 << 15))
    return (SIZE_FILL_1);
  else if (blen < (unsigned int)(1 << 16))
    return (SIZE_NO_FILL);
  else if (blen < (unsigned int)(1 << 17))
    return (SIZE_FILL_7);
  else if (blen < (unsigned int)(1 << 18))
    return (SIZE_FILL_6);
  else if (blen < (unsigned int)(1 << 19))
    return (SIZE_FILL_5);
  else if (blen < (unsigned int)(1 << 20))
    return (SIZE_FILL_4);
  else if (blen < (unsigned int)(1 << 21))
    return (SIZE_FILL_3);
  else if (blen < (unsigned int)(1 << 22))
    return (SIZE_FILL_2);
  else if (blen < (unsigned int)(1 << 23))
    return (SIZE_FILL_1);
  else if (blen < (unsigned int)(1 << 24))
    return (SIZE_NO_FILL);
  else if (blen < (unsigned int)(1 << 25))
    return (SIZE_FILL_7);
  else if (blen < (unsigned int)(1 << 26))
    return (SIZE_FILL_6);
  else if (blen < (unsigned int)(1 << 27))
    return (SIZE_FILL_5);
  else if (blen < (unsigned int)(1 << 28))
    return (SIZE_FILL_4);
  else if (blen < (unsigned int)(1 << 29))
    return (SIZE_FILL_3);
  else if (blen < (unsigned int)(1 << 30))
    return (SIZE_FILL_2);
  else if (blen < (unsigned int)(1 << 31))
    return (SIZE_FILL_1);
  return (SIZE_NO_FILL);
}
#define SIZE_NO_FILL  0
#define SIZE_FILL_1   1 
#define SIZE_FILL_2   2 
#define SIZE_FILL_3   3 
#define SIZE_FILL_4   4 
#define SIZE_FILL_5   5 
#define SIZE_FILL_6   6 
#define SIZE_FILL_7   7 

J'ai réduit cette fonction à 9 lignes :

static unsigned char     GetSizeFlag(unsigned int blen)
{
  unsigned char          a;

  for (a = 5; a < 32; ++a)
    if (blen < (unsigned int)(1 << a))
      return (8 - (a % 8)); /* SIZE_FILL_ */
  return (0);
}

Je trouve la première fonction beaucoup plus lisible  mais horriblement longue, et techniquement,  plus rapide que la seconde solution

Votre avis de développeur : comment écririez-vous cette fonction ?

Dernière modification par Bigcake (Le 27/02/2014, à 13:05)


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne

#2 Le 27/02/2014, à 13:44

telliam

Re : [C] Votre avis : fonction longue ou courte ?

je préfère la 2eme
la 1er, plus ta valeur est élevé, plus tu passes par un nombre de if important


"- Un intellectuel assis va moins loin qu'un con qui marche."
Maurice Biraud - Un Taxi pour Tobrouk
Michel Audiard

Hors ligne

#3 Le 27/02/2014, à 13:46

pires57

Re : [C] Votre avis : fonction longue ou courte ?

idem, la deuxième fonctions est la plus intéressante pour moi aussi


Utilisateur d'Archlinux, Ubuntu et Kali Linux
Administrateur système et réseau spécialisé Linux.
LinkedIn

Hors ligne

#4 Le 27/02/2014, à 14:11

pingouinux

Re : [C] Votre avis : fonction longue ou courte ?

Bonjour,
Ta fonction 2 ne donne pas le même résultat que la 1 lorsque a%8 == 0.
Tu peux aussi faire comme ceci. Les résultats sont identiques à ta fonction 1.

static unsigned char GetSizeFlag(unsigned int blen)
{
  unsigned char a=32;

  while(blen) { a-=1; blen>>=1; }
  if(a>27) a=27;
  return a%8;
}

Ajouté :
J'ai fait un test en calculant 2**32-1 valeurs avec chaque fonction.
- fonction 1 :      58 s
- fonction 2 :    165 s
- ma fonction : 180 s

Dernière modification par pingouinux (Le 27/02/2014, à 14:55)

Hors ligne

#5 Le 27/02/2014, à 15:48

Bigcake

Re : [C] Votre avis : fonction longue ou courte ?

telliam a écrit :

la 1er, plus ta valeur est élevé, plus tu passes par un nombre de if important

Pour la même valeur, le déroulement du programme passe par autant de if, vu que ma boucle for fait son test if, puis incrémente a, puis le test if, etc...
Edit: en y refléchissant, la solution 2 a même 2 fois plus de if vu qu'elle test la valeur de a après chaque incrémentation

pingouinux a écrit :

Ta fonction 2 ne donne pas le même résultat que la 1 lorsque a%8 == 0.

Bien vu et merci ! J'ai un peu baclé le travail dans la précipitation !! (j'avais même pas encore testé ma fonction ...)

Même si elle est plus lente, je vais prendre la petite fonction (corrigé !), vu que le code est dans une partie d'initialisation, c'est pas trop grave

Ca me confirme mon ressenti sur cette grande fonction, merci à vous 3 pour vos réponses smile

Dernière modification par Bigcake (Le 27/02/2014, à 16:02)


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne

#6 Le 27/02/2014, à 22:59

telliam

Re : [C] Votre avis : fonction longue ou courte ?

si j'ai bien compris ton code tu recherches quel est la puissance de 2 plus grande que ta valeur.
au lieu de tester toute les puissances de 2, est ce que ça ne serait pas plus simple de trouver le bit le plus elevé de ta valeur et de faire une décalage de 1 ?


"- Un intellectuel assis va moins loin qu'un con qui marche."
Maurice Biraud - Un Taxi pour Tobrouk
Michel Audiard

Hors ligne

#7 Le 27/02/2014, à 23:20

tiramiseb

Re : [C] Votre avis : fonction longue ou courte ?

L'approche suggérée par telliam me semble très pertinente s'il a bien compris la problématique.
Peux-tu confirmer ou infirmer sa compréhension de ton problème ?
Peux-tu décrire le but de ton code ?

techniquement,  plus rapide que la seconde solution

Oui, mais cette rapidité est-elle nécessaire ? Si le bout de code en question ne va pas s'exécuter des centaines de fois par seconde, je doute que la différence de perf puisse se ressentir.

Hors ligne

#8 Le 28/02/2014, à 12:08

Bigcake

Re : [C] Votre avis : fonction longue ou courte ?

telliam a écrit :

si j'ai bien compris ton code tu recherches quel est la puissance de 2 plus grande que ta valeur.
au lieu de tester toute les puissances de 2, est ce que ça ne serait pas plus simple de trouver le bit le plus elevé de ta valeur et de faire une décalage de 1 ?

Chaque puissance de 2 correspondant à 1 bit de l'octet, c'est exactement ce que fait ma fonction, elle cherche le bit (donc la puissance de 2) au dessus de ma valeur
Je pars du plus "petit" bit au plus "grand" bit, ma valeur pouvant varier de +/-32 à 4294967290, partir du plus grand au plus petit changera pas grand chose.

Si ça ne réponds pas à ta proposition, je ne l'ai pas compris, ou je ne vois pas comment faire plus direct que ça.....

tiramiseb a écrit :

Peux-tu décrire le but de ton code ?
Oui, mais cette rapidité est-elle nécessaire ?

Le but de ma fonction est de déterminer à partir de quel bit je n'ai que des 0 dans mon int.

C'est une fonction lancée une seul fois en phase d'initialisation, la rapidité n'est donc pas nécessaire (à moins de lancer mon programme quelques milliards de fois à la suite...)
C'est pour ça que je vais prendre la 2ème, le code sera plus agréable et l'impact sera imperceptible

Dernière modification par Bigcake (Le 28/02/2014, à 12:11)


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne

#9 Le 28/02/2014, à 12:37

Nasman

Re : [C] Votre avis : fonction longue ou courte ?

Bigcake a écrit :

Le but de ma fonction est de déterminer à partir de quel bit je n'ai que des 0 dans mon int.

Ce type de fonction est très simple à effectuer en assembleur avec l'instruction shl (décalage des bits vers la gauche et récupération du bit le plus élevé dans le carry flag). Un simple test te dira à quel moment il y a un bit 1 qui apparaît.

Peut être en désassemblant ton exécutable, tu pourras choisir le meilleur code C - à moins que tu codes ta fonction en assembleur (intéressant si ce calcul est effectué de nombreuses fois).


PC fixe sous Bionic 64 bits et portable avec Focal 64 bits

Hors ligne

#10 Le 28/02/2014, à 13:35

pingouinux

Re : [C] Votre avis : fonction longue ou courte ?

J'ai amélioré ma fonction en #4, qui dans les mêmes conditions de test, tourne en 22 s (je ne comprends d'ailleurs pas la différence).

static unsigned char GetSizeFlag(unsigned int blen)
{
  unsigned char a=0;
  unsigned int b=(1<<31);
  if(blen<32) return 3;
  while(!(blen&b)) { a+=1; b>>=1; }
  return a%8;
}

Hors ligne

#11 Le 03/03/2014, à 18:38

darunia_goron

Re : [C] Votre avis : fonction longue ou courte ?

On peut encore faire un peu plus rapide (mais plus volumineux) :

#include <stdint.h>

static const uint8_t size_flag_tab[] =
  {
    7, 7, 6, 6, 5, 5, 5, 5,
    4, 4, 4, 4, 4, 4, 4, 4,
    3, 3, 3, 3, 3, 3, 3, 3,
    3, 3, 3, 3, 3, 3, 3, 3,
    2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0
  };

static uint8_t GetSizeFlag (uint32_t blen)
{
  if (blen & 0xFFFF0000)
    {
      if (blen & 0xFF000000)
	  return size_flag_tab[blen >> 24];
      else /* if (blen & 0xFF0000) */
	  return size_flag_tab[blen >> 16];
    }
  else
    {
      if (blen & 0xFF00)
	  return size_flag_tab[blen >> 8];
      else if (blen & 0xE0) /* if ((blen & 0xFF) && (blen >= 32)) */
	  return size_flag_tab[blen];
      else
	  return 3;
    }
}

Ou plus court (et bien plus lent) :

#include <stdint.h>
#include <math.h>

/* Valeur empirique pour éviter les erreurs d'arrondie. */
#define EPSILON 0.00000000000001

static uint8_t GetSizeFlag4 (uint32_t blen)
{
  if (blen < 32)
    return 3;

  return 7 - ((int)(log (blen) * (M_LOG2E + EPSILON)) & 0x07);
}

La première solution que je propose s'exécute, pour les 2^32-1 valeurs, en 13.20s (contre 18.85s pour celle de pingouinux) si les fonctions ne sont pas inline. Si elles sont inline, les temps deviennent respectivement à 5.72s et 10.04s. À noter que gcc inline la fonction de pingouinux par défaut mais pas la mienne.
Tout dépend de l'usage que tu feras de ton code. Si il est amené à être inclus dans une bibliothèque et être à fréquemment utilisé, je garderai ma solution. Dans les autres cas, je pense que je choisirai la solution de pingouinux.

La deuxième solution avec le log est extrêmement lente (plus de quatre minutes) et je ne la recommande pas. Je l'ai juste postée pour illustrer ce que je pense être un mauvais exemple de code court.

Hors ligne

#12 Le 04/03/2014, à 11:53

Luc Hermitte

Re : [C] Votre avis : fonction longue ou courte ?

__builtin_ctz ne répondrait pas à ton besoin ? (http://gcc.gnu.org/onlinedocs/gcc-4.3.4 … ltins.html)

Sinon, tu as ça aussi: http://graphics.stanford.edu/~seander/b … ightLinear

Hors ligne

#13 Le 04/03/2014, à 13:33

Bigcake

Re : [C] Votre avis : fonction longue ou courte ?

@darunia_goron : j'aime beaucoup l'approche différente que tu a eu dans ta 1ère fonction !

@Luc Hermitte : Merci ! Je connaissais pas les "builtin", ces 2 petits liens bien sympa sont gardés au chaud dans un coin !!

Même si le code est lancé une fois au lancement du programme, donc la vitesse n'est pas primordiale, j'ai fait quelques petits tests avec et sans l'option gcc -O3

Avec -O3
Ma 2ème fonction mets ~123s (Palme d'or de la lenteur !!! Merci public !!!!!)
Celle de pingouinux mets ~7s
La 1ère de darunia_goron mets ~0 sec
Et celle ci dessous mets ~0 sec (on a 2 concurrents)

Sans -O3
La 1ère de darunia_goron mets ~33 sec
Et celle ci dessous mets ~25 sec (Palme d'or de la vitesse !!! Merci public !!!!!)

static unsigned char GetSizeFlag(unsigned int blen)
{
    return ((__builtin_clz(blen)) % 8);
}

Je crois que je vais virer ma fonction GetSizeFlag() et la remplacer par (__builtin_clz(blen)) % 8 !!  La, je peux pas faire plus court big_smile

Merci à tous pour vos réponses smile

Dernière modification par Bigcake (Le 04/03/2014, à 13:38)


"Les gens" ne sont pas cons, ils ont été habitués à la facilité et à la désinformation. Le meilleur moyen de ne pas les aider, c'est de se moquer. Le meilleur moyen de les aider, c'est de les informer, encore et encore. La réflexion viendra. N'oubliez pas que vous aussi, vous êtes le con d'un autre.
Smartphone+GNU/Linux=Librem5

Hors ligne