Grâce à Dark_Ebola qui m'a relancé, voici comment ceci fonctionne:

Envoyé par
Jean-Marc.Bourguet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv)
{
int i;
for (i = 1; i < argc; ++i)
{
char* end;
unsigned long n = strtol(argv[i], &end, 16);
if (*end != '\0') {
printf("%s is not a number\n", argv[i]);
} else {
n -= 0x33333;
if (((n - 0x11111) & 0x88888 & ~n) != 0) {
printf("%s\n", argv[i]);
}
}
}
return 0;
} |
Premièrement, j'évalue le nombre décimal en prétendant qu'il est en hexadécimal. Donc, j'ai en fait du BCD (décimal codé binaire). L'objectif est de trouver les 3. Ce qui va mettre des 0 (en décimal codé binaire) aux endroits où il y avait des trois et (bug, Gruik avait raison, il y a des problèmes) aussi où il y avait des quatre suivis d'un chiffre inférieur à 3.
Il faut donc savoir s'il y a un ou des 0. En soustrayant 0x11111 les 0 deviennent des 0xF, en prenant un et logique avec 0x88888 on se retrouve avec 0x8 là ou il y avait des 9, A, B, C, D, E, F, 0. En faisant un et logique avec ~n, on n'a plus des 0x8 que là où il y avait des 0 (il y a un autre cas quand il y a eu une retenue, mais ici s'il y a retenue ça veut dire qu'il y avait un 0 avant, donc pas de problème).
Le truc peut être employé pour chercher s'il y a au moins un octet à 0 dans un mot:
(n - ((unsigned) -1)/255) & ((unsigned) -1)/255*128) & ~n
(unsigned) -1)/255 va donner 0x01010101 avec des unsigned de 32 bits et 0x0101010101010101 avec des unsigned de 64 bits. Ça ne marche que pour des multiples de 8 bits.
Partager