Défi: optimisation d'une fonction de convertion (Bin => Dec)

lcprog Messages postés 41 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 11 septembre 2006 - 4 janv. 2005 à 14:47
JoePatent Messages postés 171 Date d'inscription jeudi 30 janvier 2003 Statut Membre Dernière intervention 20 juillet 2008 - 4 janv. 2005 à 21:39
Salut!


J'ai besoin dans un programme d'avoir une fonction qui me converti en nombre entier une chaine de caractères représentative d'un nombre binaire strictement positif compris entre 0 et 511 ex: "100110100" (codage sur 9 bits).


Cette fonction doit être appelée environ 9 000 000 de fois à la suite. Il me faut donc qu'elle soit le plus rapide possible. Je poste la fonction que je me suis programmé mais que je voudrais optimiser.
Si vous avez des idée pour augmenter la rapidité du code je vous serai reconnaissant.
Merci!


Loïc





Private Function BinToNum(sBinary As String) As Long
   Dim nValue As Long
   Dim nCpt As Long
   Dim nPow As Byte
   
   nValue = 0
   nCpt = 1
   While nCpt <= Len(sBinary)
       If Mid(sBinary, nCpt, 1) = "1" Then
          nPow = Len(sBinary) - nCpt
          nValue = nValue + (2 ^ nPow)
       End If
       nCpt = nCpt + 1
   Wend
   
   BinToNum = nValue
End Function

11 réponses

K@zuya Messages postés 306 Date d'inscription vendredi 21 février 2003 Statut Membre Dernière intervention 15 février 2016
4 janv. 2005 à 15:21
Salut, j'ai déjà eut exactement le même genre de PB et j'ai trouvé une solution pas mal du tout, on ne peut pas faire plus rapide, c'est imposible.

il te faut ecrire une fonction dans ce goût la:

Private Function BinToNum(sBinary As String) As Long
Select Case sBinary
Case "000000000"
BinToNum = 0
Case "000000001"
BinToNum = 1
Case "000000010"
BinToNum = 2
Case "000000011"
BinToNum = 3

etc.....
End Select
End Function

Oui mais tu va m'dire, hein, fo écrire tout ça, c'est trop long !!!
C'est pourquoi moi, j'ai d'abord écrit un petit programme qui m'écrit la fonction toute faite dans un fichier puis je fais un copier/coller, c'est pas plus compliqué que ça.

K@zuya
0
Zigarn Messages postés 106 Date d'inscription mardi 13 juillet 2004 Statut Membre Dernière intervention 26 janvier 2005
4 janv. 2005 à 15:37
Et si tu utilisait le même algo que pour convertir une chaine représentant un décimal en un entier :

tu lis tes caractères depuis la gauche et à chaque caractère tu multiplie par 2 et tu ajoute la valeur du caractère :


Private Function BinToNum(sBinary As String) As Long
Dim nValue As Long
Dim nCpt As Long


Dim nMax As Long




nMax =
Len(sBinary)


nValue = 0
nCpt = 1
While nCpt <= nMax

nValue = 2*nValue
If Mid(sBinary, nCpt, 1) = "1" Then
nValue = nValue + 1
End If
nCpt = nCpt + 1
Wend

BinToNum = nValue
End Function



C'est plus "algorithmique" come solution et tu n'utilise pas de calcul de puissance donc plus rapide que ta solution

-------------------------------------------------
Débutant ... mais pas pour longtemps !
0
Zigarn Messages postés 106 Date d'inscription mardi 13 juillet 2004 Statut Membre Dernière intervention 26 janvier 2005
4 janv. 2005 à 15:41
En fait cela utilise le fait que 100110b = ((((1*2+0)*2+0)*2+1)*2+1)*2+0

tout comme 123 = (1*10+2)*10+3

-------------------------------------------------
Débutant ... mais pas pour longtemps !
0
lcprog Messages postés 41 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 11 septembre 2006
4 janv. 2005 à 16:23
la solution de Kazuya me plait bien. je testerai ce soir...
Sinon un gars sur hardware.fr m'a beaucoup aidé. Voici où on a abouti (presque 50% de gain de temps).

private nPowerArray(1 to 9) as long

Private Function Bin9BitsToNum(sBinary As String) As Long
Dim nValue As Long
Dim nCpt As Long

nValue = 0
nCpt = 9

While nCpt > 0
If AscW(Mid$(sBinary, nCpt, 1)) = 49 Then
nValue = nValue + nPowerArray(nCpt)
End If
nCpt = nCpt - 1
Wend

Bin9BitsToNum = nValue
End Function


Private Sub Class_Initialize()
nLevel = 1
nPowerArray(1) = 256
nPowerArray(2) = 128
nPowerArray(3) = 64
nPowerArray(4) = 32
nPowerArray(5) = 16
nPowerArray(6) = 8
nPowerArray(7) = 4
nPowerArray(8) = 2
nPowerArray(9) = 1
End Sub
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
JoePatent Messages postés 171 Date d'inscription jeudi 30 janvier 2003 Statut Membre Dernière intervention 20 juillet 2008
4 janv. 2005 à 16:44
"Salut, j'ai déjà eut exactement le même genre de PB et j'ai trouvé une solution pas mal du tout, on ne peut pas faire plus rapide, c'est imposible."

Cette solution n'est pas la plus rapide. Chaque 'case' sera verifier dans le cas de 511 par exemple.

Tant qu'a procéder ainsi, fait 9 if indépendant pour tester chaque BIT un a un. Plus rapide, plus simple, plus court, plus stable. Toujours et uniquement 9 conditions. Aucune boucle, aucune incémentation de variable etc etc.

*****
LCPROG -> tu semble hardcodé le nombre de bit a 9 si je me fie au vecteur. Donc...
Private Function Bin9BitsToNum(sBinary As String) As Integer
Dim nValue As Integer ' Prit la liberté de réduire la taille des variable
Dim nCpt As Integer ' Prit la liberté de réduire la taille des variable


nValue = val(right&(sBinary, 1) ' Tant qu'a initialiser aussi bien couper une itération

for nCpt = 8 to 1 step -1 ' Pas convaincu que cette boucle est plus performante
nValue = nValue + (nPowerArray(nCpt) * val(mid$(sBinary, nCpt, 1)))
next j

Bin9BitsToNum = nValue
End Function

Private Sub Class_Initialize()
nLevel = 1 ' ???
nPowerArray(1) = 256
nPowerArray(2) = 128
nPowerArray(3) = 64
nPowerArray(4) = 32
nPowerArray(5) = 16
nPowerArray(6) = 8
nPowerArray(7) = 4
nPowerArray(8) = 2
nPowerArray(9) = 1
End Sub

http://www.joepatent.com
0
lcprog Messages postés 41 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 11 septembre 2006
4 janv. 2005 à 16:58
Voilà où j'en suis. J'ai pas trouvé plus rapide.

Private Function Bin9BitsToNum(sBinary As String) As Long
Dim nValue As Long

If AscW(Mid$(sBinary, 1, 1)) = 49 Then
nValue = nValue + 256
End If
If AscW(Mid$(sBinary, 2, 1)) = 49 Then
nValue = nValue + 128
End If
If AscW(Mid$(sBinary, 3, 1)) = 49 Then
nValue = nValue + 64
End If
If AscW(Mid$(sBinary, 4, 1)) = 49 Then
nValue = nValue + 32
End If
If AscW(Mid$(sBinary, 5, 1)) = 49 Then
nValue = nValue + 16
End If
If AscW(Mid$(sBinary, 6, 1)) = 49 Then
nValue = nValue + 8
End If
If AscW(Mid$(sBinary, 7, 1)) = 49 Then
nValue = nValue + 4
End If
If AscW(Mid$(sBinary, 8, 1)) = 49 Then
nValue = nValue + 2
End If
If AscW(Mid$(sBinary, 9, 1)) = 49 Then
nValue = nValue + 1
End If

Bin9BitsToNum = nValue
End Function

JoePatent, t'es sur pour l'integer ? J'ai lu qu'il fallait de préférence utiliser le tupe long en vb pour les processeurs 32 bits. Faut pas regarder la variable nLevel, c'est une propriété utilisée dans les autres méthodes de ma classe.
0
lcprog Messages postés 41 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 11 septembre 2006
4 janv. 2005 à 17:03
je confirme pour le long. ca me fait gagner 1.5 seconde sur un bench qui dure 43 secondes avec un integer
0
lcprog Messages postés 41 Date d'inscription mardi 23 septembre 2003 Statut Membre Dernière intervention 11 septembre 2006
4 janv. 2005 à 17:03
je confirme pour le long. ca me fait gagner 1.5 seconde sur un bench qui dure 43 secondes avec un integer
0
Gobillot Messages postés 3140 Date d'inscription vendredi 14 mai 2004 Statut Membre Dernière intervention 11 mars 2019 34
4 janv. 2005 à 18:30
l'accès direct est toujours le plus rapide, bien sûr ça prend énormément de place mais ensuite les temps sont negligeables.

Dim s As String
Dim i As Integer
Dim T() As Integer

ReDim T(111111111)
For i = 0 To 511
s = Byte2String(i)
T(Val(s)) = i
Next

Private Function Byte2String(n As Integer) As String
Dim x As Integer
Dim R As String
x = 256
Do If (n And x) Then R R + "1" Else R R + "0"
x = x \ 2
Loop Until x = 0
Byte2String = R
End Function

'pour l'utilsation accès directe dans la Table
Bin9BitsToNum = T(Val(sBinary))

Daniel
0
JoePatent Messages postés 171 Date d'inscription jeudi 30 janvier 2003 Statut Membre Dernière intervention 20 juillet 2008
4 janv. 2005 à 21:18
Très imaginatif !

J'ai testé et toutes les autres méthodes varient entre 29 secondes et 78 secondes (essai échoué avec VAL() et autres functions)

Ta fonction prend 10 secondes. Gourmande en memoire mais tres rapide ! :-)

*9 millions d'opérations.

http://www.joepatent.com
0
JoePatent Messages postés 171 Date d'inscription jeudi 30 janvier 2003 Statut Membre Dernière intervention 20 juillet 2008
4 janv. 2005 à 21:39
Voici une autre possibilité :
L'astuce est d'éliminer les manipulations de chaîne de caractère. Seul le VAL() demeure et est tres tres gourmand.

J'obtiens 20 secondes au lieu de 29. Toutefois, si je recois un long au lieu d'ue string je descend a 10 secondes. Mais on a pas le choix j'imagine de recevoir une string :-(

Voici :
Private Function DBin9BitsToNum(sbinary As String) As Integer
Dim z As Long
Dim nValue As Integer
z = Val(sbinary)
nValue = nValue + (1 * (z Mod 2))
z = z \ 10
nValue = nValue + (2 * (z Mod 2))
z = z \ 10
nValue = nValue + (4 * (z Mod 2))
z = z \ 10
nValue = nValue + (8 * (z Mod 2))
z = z \ 10
nValue = nValue + (16 * (z Mod 2))
z = z \ 10
nValue = nValue + (32 * (z Mod 2))
z = z \ 10
nValue = nValue + (64 * (z Mod 2))
z = z \ 10
nValue = nValue + (128 * (z Mod 2))
z = z \ 10
nValue = nValue + (256 * (z Mod 2))


DBin9BitsToNum = nValue
End Function

http://www.joepatent.com
0
Rejoignez-nous