CONVERSION D'UN NOMBRE ENTIER EN SA REPRÉSENTATION BINAIRE

Messages postés
702
Date d'inscription
vendredi 21 mars 2003
Statut
Membre
Dernière intervention
1 octobre 2009
- - Dernière réponse : f0xi
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
- 3 mai 2006 à 14:15
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/21707-conversion-d-un-nombre-entier-en-sa-representation-binaire

f0xi
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26 -
tiens ça m'a fait reflechir,
donc petite variante avec un case of pour IntToBinStr

ce qui nous descend les performances a :

60..65ms pour 100000 appels et 500..520ms pour 1 millions d'appels...
soit un gain de 10 et 100 ms environ ... je savais bien qu'il y avait un probleme avec mes ensembles ...

function IntToBinStr(const I : int64) : string;
var N : integer;
T4 : $0..$f;
PRS : PChar;
begin
if I = -1 then begin
Result := DupeChar('1',64);
exit;
end;
Result := DupeChar('0',64);
if I = 0 then exit;
PRS := PChar(Result);
for N := 15 downto 0 do begin
T4 := (I shr (N*4)) and $f;
Case T4 of
$1 : begin PRS[3]:='1'; end;
$2 : begin PRS[2]:='1'; end;
$3 : begin PRS[2]:='1'; PRS[3]:='1'; end;
$4 : begin PRS[1]:='1'; end;
$5 : begin PRS[1]:='1'; PRS[3]:='1'; end;
$6 : begin PRS[1]:='1'; PRS[2]:='1'; end;
$7 : begin PRS[1]:='1'; PRS[2]:='1'; PRS[3]:='1'; end;
$8 : begin PRS[0]:='1'; end;
$9 : begin PRS[0]:='1'; PRS[3]:='1'; end;
$A : begin PRS[0]:='1'; PRS[2]:='1'; end;
$B : begin PRS[0]:='1'; PRS[2]:='1'; PRS[3]:='1'; end;
$C : begin PRS[0]:='1'; PRS[1]:='1'; end;
$D : begin PRS[0]:='1'; PRS[1]:='1'; PRS[3]:='1'; end;
$E : begin PRS[0]:='1'; PRS[1]:='1'; PRS[2]:='1'; end;
$F : begin PRS[0]:='1'; PRS[1]:='1'; PRS[2]:='1'; PRS[3]:='1'; end;
end;
inc(PRS,4);
end;
end;
f0xi
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26 -
je pense que c'est une erreur du site Gulber ... > est un symbol HTML qui correspond a "<" ou ">" je sais plus...

sinon un test de performances, les gars, vous etes grave a la ramasse :
pour 100000 convertions de la valeur 65535 en binaire

Psycho81 : 800..850 ms raisonnable mais peut mieux faire...

Sbe : relevée a plus de 12secondes pour seulement 5000 appels avec un facteur de *10 tout les 500 appels (c'est precis mon analyzer)

Kenavo : pas en forme mon ami relevée a plus de 1700 ms pour seulement 1000 appels avec un facteur de *10 toute les 200 appels

DelphiProg : relevée a plus de 12 secondes pour seulement 5000 appels avec un facteur de *10 toute les 500 appels ... comme la methode de SBE... je suis deçu la...

et je vous parle meme pas des fonctions binaire vers valeur ... c'est la cata...

aller je suis sympa je vous donne les methodes ... qui coté code sont pourtant d'une simplicitée enfantine et surtout etonnante quand a leurs performances...

IntToBinStr (convertis une valeur Int64 en sa representation binaire)
70..80 ms pour 100000 appels, 650..660ms pour 1 millions d'appels ...

BinStrToInt (convertis une representation binaire en une valeur Int64)
28..35ms pour 100000 appels, 135..145 ms pour 1 millions d'appels
(anecdote, quand j'ai vus le ~140 ms ... je me suis dis zut ... elle est pas trop top comparée a l'autre ... mais aprés relecture c'etait le temps pour 1 millions d'appels ... O.o )


{ DupeChar permet de créer une chaine de "Count" caractere "C", trés pratique pour remplir trés vite une chaine de "0" ou de "1" }

function DupeChar(const C : char; Count: Integer): string;
var
PResult: PChar;
begin
SetLength(Result, Count);
PResult := PChar(Result);
while Count > 0 do begin
PResult[0] := C;
Inc(PResult);
Dec(Count);
end;
PResult[0] := #0;
end;

{ convertis un chaine representant une valeur binaire en valeur Int64 }
function BinStrToInt(const S : string) : int64;
var N,B : integer;
begin
result := 0;
B := 1;
For N := Length(S) downto 1 do begin
if S[N] = '1' then
inc(result,B);
inc(B,B); { simple mais efficace on compte 1, 2, 4, 8, 16 etc... }
end;
end;

{ aaah, ici toute l'astuce reside dans le traitement par block de 4 bits }
function IntToBinStr(const I : int64) : string;
var N : integer;
T4 : $0..$f;
PRS : PChar;
begin
if I = -1 then begin
{ on sait que -1 = 11111111 ou encore $FF, High etant $7F et Low $80 }
Result := DupeChar('1',64);
exit;
end;
Result := DupeChar('0',64);
if I = 0 then
exit; {idem, on sait que 0 = 00000000 ou encore $00 }
PRS := PChar(Result); { on PCharize result}
for N := 15 downto 0 do begin
{ on SHRize I a N*4 et on $fize pour ne garder que le demi-octet }
T4 := (I shr (N*4)) and $f;
{ on tris un peu pour savoir quel bit on mets a 1, ici j'ai pas voulus croiser les cas
car c'est un peu inutile, de plus ça augmenterais les instructions }
if T4 in [$1,$3,$5,$7,$9,$B,$D,$F] then
PRS[3] := '1';
if T4 in [$2,$3,$6,$7,$A,$B,$E,$F] then
PRS[2] := '1';
if T4 in [$4,$5,$6,$7,$C,$D,$E,$F] then
PRS[1] := '1';
if T4 in [$8,$9,$A,$B,$C,$D,$E,$F] then
PRS[0] := '1';
{ vus qu'on travail par block de 4 bits on incremente la chaine de 4 }
inc(PRS,4);
end;
end;


et voila ... avec des methodes aussi performante, j'espere que vous serez content...
de plus elle sont facilement adaptable et permettent egalement (grace a leurs performances) d'ajouter un peu de code supplementaire pour traiter les cas 8, 16, 32 bits et plus de 64 ...

la ou vous avez tous fait une erreur c'est les appels trop nombreux a IntToStr ou a d'autre fonctions a l'interieur de vos boucle ... meme la methode a psycho qui fait appel a l'assembleur et completement degradée par IntToStr ... dommage c'etait une bonne idée cette petite fonction GetBit...

Quelque part je suis etonné que les fonctions que j'utilise depuis maintenant longtemps et qui ont été ameliorée au fur et a mesure, soit apparement les plus rapide.
et vous pouvez tester les cas des -1, high(int64), high(integer) ect... les resultats sont bon.

et comme je le rappel plus haut, pour les entiers signés :
-1 = $FF, $FFFF, 11111111
0 = $00, $0000, 00000000
High = $7F, $7FFF, 01111111
Low = $80, $8000, 10000000

amusant non ?
gulbeur
Messages postés
2
Date d'inscription
mardi 28 février 2006
Statut
Membre
Dernière intervention
28 mars 2006
-
bonjour SBE,
merci pour ton code mais
tu ecris :
if (Val and Masque)>0 then Etat := '1' else Etat := '0';
mais que veut dire : >0 ?
Mon delphi 6 ne compile pas cela il bloque au &.
merci
a+
gill
cs_sbe
Messages postés
2
Date d'inscription
mardi 8 avril 2003
Statut
Membre
Dernière intervention
19 novembre 2005
-
Bonjour Delphiprog,

Pourrais-tu m'expliquer en quoi mon code ne fonctionne pas avec les nombres négatif ?
J'ai essayé ca :

DecToBin(-1,16) donne 1111111111111111
DecToBin(-2,16) donne 1111111111111110

Tous cela me semble bien correcte.

Merci
@++
Steph

merci
psycho81
Messages postés
88
Date d'inscription
mardi 4 mai 2004
Statut
Membre
Dernière intervention
17 février 2008
-
Oups, quel sacrilège ! Etant trop habitué à la syntaxe VB j'ai fait une erreur ... grossière.

Ce n'est pas

Result[i] = IntToStr(GetBit(Value,31-i));

mais

Result[i] := IntToStr(GetBit(Value,31-i));


Ca restait compréhensible mais ... := c'est quand même le signe distinctif du Pascal :)