random_sequence()
Jeudi 28 octobre 2004 20:09 - Code
Où l'auteur se prend le chou sur la réécriture de la fonction dont le nom a servi de titre.
Ladite fonction a une fonction (ça tombe bien) nette et précise, retourner une chaîne de caractères (de taille n) contenant des caractères hexadécimaux aléatoires.
L'implémentation d'origine était grosso modo la suivante:
char* random_sequence(int n)
{
int i, val;
char *s;
s = malloc(n+1);
for (i=0; i<n; i++) {
val = rand() & 0xf;
if (val < 10) {
s[i] = 48 + val;
} else {
s[i] = 65 + val-10;
}
}
s[n] = 0;
return s;
}
J'étais un peu ennuyé par tous les appels à rand(); cette fonction retourne un entier qui fait quand même une floppée de bits et il n'en était gardé que quatre (c'est ce que fait le & 0xf, la version originale utilise en fait la GLib qui vient avec une fonction retournant un entier entre deux bornes); dommage, il fallait trouver un moyen de les utiliser tous.
Autre idée; pourquoi coder la conversion du nombre en caractère hexa ? Pourquoi ne pas utiliser sprintf() ?
Tsk. Mauvaise idée. sprintf est un gouffre. Voyons quand même.
char* random_sequence(int n)
{
char *s, *t;
s = t = malloc(n+sizeof(int)+1);
while (t-s < n) {
sprintf(t, "%0X", rand());
t += sizeof(int);
}
s[n] = 0;
return s;
}
C'est tout joli mais remplacer quelques appels à rand() par un peu moins d'appels à sprintf, ça ne mène nulle part.
Virer sprintf, donc.
char* random_sequence(int n)
{
char *s, *t;
int rnd, i;
s = t = malloc(n+sizeof(int)+1);
while (t-s < n) {
rnd = rand();
for (i=0; i<sizeof(int); i++) {
*(t++) = '0' + ((rnd>>i*4)&0xf);
if (*(t-1) > '9') *(t-1) += 7;
}
}
s[n] = 0;
return s;
}
Et hop. Il reste à en taper un petit million (de taille 60) et à mesurer le temps que ça prend (via time, quelques appels et une moyenne).
- Version originale: 3,314s
- Version "sprintf": 8,689s (wouh, 2,6x plus lent)
- Version finale: 1,996s (1,6x plus rapide)
Ce n'est pas négligeable mais la lisibilité du code souffre un peu, je ne sais qu'en faire.