Suche (schnelle) Funktion zum Umrechnen ins Dual- oder Hexadezimalsystem

  • Moin,
    Das eigentliche Thema wurde bereits zufriedenstellend gelöst (eine sehr Schnelle Methode ist in Post 15 zu finden), nun gibt es leider ein weiteres Problem mit Dezimal und Dualzahlen (oder Hexadezimalzahlen).

    -----------------------------------------------------------------------------------------------
    Ich stehle hiermit mal meinen eigenen Thread und ändere das Thema leicht ab.

    Es geht jetzt um Folgendes:
    Suche (schnelle) Funktion zum umrechnen ins Dual- oder Hexadezimalsystem
    Problemstellung:
    Mein Arithmetischer Kodierer spuckt mir einen String im Dezimalsystem entgegen. Dieser String enthält je nach Input hunderte bis zehntausende Zahlen. Um diesen Spaß anständig zu speichern wird er im Dualsystem gebraucht. (Der Header der daraus entstehenden "Datei" ist im Dualsystem, da einzelne Bits entscheidend sind, die Kodierung der Wahrscheinlichkeiten ist im Dualsystem usw usw. Also muss auch der kodierte String ins Dualsystem. Dann schön alles zusammensetzen und als Binary zurückgeben)

    Wie funktioniert soetwas ?
    Der Ansatz mit den hier diskutierten Methoden läuft jedenfalls nicht, da man nicht jedes Mal die komplette endlos lange Dezimalzahl durch 2 Teilen kann. Die Subtraktionsmethode fällt ebenfalls flach, da man nicht immer mit so enormen Zahlen potenzieren kann und anschließend 2 riesige Zeichenketten voneinander abziehen kann. Die restlichen Methoden bauen darauf auf die Dezimalzahl erstmal per Hex zu verarbeiten, sodass weitere Schritte sehr einfach sind; läuft bei großen Zahlen auch nicht.

    Ich bitte daher um einen Ansatz, wie man eine große Dezimalzahl stück für Stück umwandeln kann.

    Edit:

    Funktion für kleine Zahlen (< 2^31)
    [autoit]

    Global $a_[256], $b_[256], $c_[11111112]

    [/autoit] [autoit][/autoit] [autoit]

    _DecToBin_Startup()

    [/autoit] [autoit][/autoit] [autoit]

    Global $sDec = '123456789'
    Global $sBin = _DecToBin($sDec)
    Global $sDec2 = _BinToDec($sBin)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('Original: ' & $sDec & @CRLF & 'Binär: ' & $sBin & @CRLF & 'Dezimal: ' & $sDec2 & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    ; <Func>--------------------------------------------------|
    ; Wandelt eine Dualzahl in eine Dezimalzahl um |
    ; --------------------------------------------------------|
    Func _BinToDec($s)
    Local $l = StringLen($s)
    Return $l<9?$c_[$s]:$l<17?$c_[StringTrimRight($s,8)]*256+$c_[StringRight($s,8)]:$l<25?$c_[StringTrimRight($s,16)]*65536+$c_[StringRight(StringTrimRight($s,8),8)]*256+ $c_[StringRight($s,8)]:BitShift($c_[StringTrimRight($s,24)],-24)+$c_[StringRight(StringTrimRight($s,16),8)]*65536+$c_[StringRight(StringTrimRight($s,8),8)]*256+$c_[StringRight($s,8)]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; <Func>--------------------------------------------------|
    ; Ermittelt eine Dualzahl (0101) aus einer Dezimalzahl |
    ; Die Dezimalzahl muss kleiner als 2^31 sein |
    ; --------------------------------------------------------|
    Func _DecToBin($d)
    Return $d<256?$a_[$d]:$d<65536?$a_[$d/256]&$b_[BitAND($d,255)]:$d<16777216?$a_[$d/65536]&$b_[BitAND($d/256,255)]&$b_[BitAND($d,255)]:$a_[BitShift($d,24)]&$b_[BitAND($d/65536,255)]&$b_[BitAND($d/256,255)]&$b_[BitAND($d,255)]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    ; <Func>--------------------------------------------------|
    ; Initialisiert die DecToBin UDF |
    ; --------------------------------------------------------|
    Func _DecToBin_Startup()
    Local $t = DllStructCreate('char[64]'), $p = _
    DllStructGetPtr($t), $hDll = DllOpen('msvcrt.dll')
    For $i = 0 To 255 Step 1
    DllCall($hDll, 'ptr:cdecl', '_i64toa', 'int64', _
    $i, 'ptr', $p, 'int', 2)
    $a_[$i] = DllStructGetData($t, 1)
    $b_[$i] = StringRight('0000000' & $a_[$i], 8)
    $c_[$a_[$i]] = $i
    Next
    DllClose($hDll)
    EndFunc

    [/autoit]
    Funktion für beliebig große Strings
    [autoit]


    ; Sämtlicher Code ist von Make-Grafik.

    [/autoit] [autoit][/autoit] [autoit]

    Global $sDec = '1234567890123456789012345678901234567890'
    Global $sHex = _Big_DecToHex($sDec)
    Global $sDec2 = _Big_HexToDec($sHex)

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('Original: ' & $sDec & @CRLF & 'Hexadezimal: ' & StringTrimLeft($sHex, 2) & @CRLF & 'Dezimal: ' & $sDec2 & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Func _Big_DecToHex($sInteger)
    Local $i, $bp, $carry, $n, $aiInt[1], $product
    For $i = 1 To StringLen($sInteger)
    $bp = 0
    $carry = StringMid($sInteger, $i, 1)
    For $n = 0 To UBound($aiInt) -1
    $product = $aiInt[$n] & $carry
    $aiInt[$bp] = BitAND($product, 0x00FF)
    $carry = BitAND($product, 0xFF00) / 0x0100
    $bp += 1
    Next
    If $carry Then
    ReDim $aiInt[$bp +1]
    $aiInt[$bp] = $carry
    EndIf
    Next
    Return StringToBinary(StringFromASCIIArray($aiInt, 0, Default, 1))
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _Big_HexToDec($aiInt)
    $aiInt = StringToASCIIArray(BinaryToString($aiInt), 0, Default, 1)
    Local $carry, $i, $product, $sInteger
    Local $index = UBound($aiInt) -1
    Do
    $carry = StringRight($aiInt[$index], 1)
    $aiInt[$index] = Floor($aiInt[$index] / 10)
    For $i = $index -1 To 0 Step -1
    $product = $carry * 0x0100 + $aiInt[$i]
    $aiInt[$i] = Floor($product / 10)
    $carry = StringRight($product, 1)
    Next
    $sInteger &= $carry
    If Not $aiInt[$index] Then
    ReDim $aiInt[$index]
    $index -= 1
    EndIf
    Until $index = -1
    Return StringReverse($sInteger)
    EndFunc

    [/autoit]


    Eine ASM Version von DecToBin (kann auch in Hex oder Str umwandeln) gibts von eukalyptus in Post36

    lg
    M
    -----------------------------------------------------------------------------------------------

    Originaler Inhalt des #1 Post


    Moin

    Geschwindigkeit ist wie immer König im Haus.
    Es geht um die Umrechnung von 32Bit Ganzzahlen (int) ins Dualsystem (0101010)
    Aus Wikipedia habe ich die Divisions und die Subtraktions-Methode angesehen und festgestellt, dass diese in AutoIt auch wunderbar funktionieren.

    Problematisch wird es nun bei wirklich großen Zahlen. Da dauert der Aufruf schonmal 0.14 ms wenn man sich auf diese Methoden stützt.
    Also habe ich etwas gebastelt und eine Methode entdeckt, mit der der Spaß immer nahezu konstant in 0.08ms erledigt wird. (Fast doppelt so schnell)
    (logisch, eigentlich sind die anderen Methoden weitaus schneller, aber in AutoIt ist die Welt eben manchmal verkehrt^^)

    Bei kleinen Zahlen ist diese Methode den Wikipediamethoden weit unterlegen (Faktor ca. 4:1), bei großen Zahlen aber überlegen.

    Jetzt interessiert es mich, falls jemand hier ab und zu mal sowas nutzt, welche Funktion für die Umwandlung benutzt wird und wie schnell diese ist.

    Gesucht wird die schnellste Funktion die eine beliebige 32Bit Int Zahl ins Dualsystem (010101) bringt.
    Dabei muss keine Rücksicht auf nativen AutoIt Code genommen werden. Sollte es eine Dll-Func geben die ich nicht kenne bin ich natürlich erfreut mit dieser Bekanntschaft zu machen :)

    Code
    [autoit][/autoit] [autoit][/autoit] [autoit]

    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Local $a[3], $t, $r, $Zeitbedarf[3], $Versuche = 5000, $Schritte = 0
    Local $Excel = False

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then Sleep(5000)

    [/autoit] [autoit][/autoit] [autoit]

    While $Schritte < 2 ^ 31 - 1
    ConsoleWrite('Zahl: ' & $Schritte & @CRLF)
    If $Excel Then
    Send($Schritte, 1)
    Sleep(100)
    Send('{RIGHT}')
    Sleep(100)
    EndIf
    For $i = 0 To $Versuche Step 1
    $r = $Schritte
    $t = TimerInit()
    $a[0] = _DecToBin_1($r) ; Divisionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[0] += $t
    $t = TimerInit()
    $a[1] = _DecToBin_2($r) ; Subtraktionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[1] += $t
    $t = TimerInit()
    $a[2] = _DecToBin_3($r) ; Ausgedacht 1
    $t = TimerDiff($t)
    $Zeitbedarf[2] += $t
    If ($a[0] <> $a[1]) Or ($a[0] <> $a[2]) Then
    ConsoleWrite('Error: ' & @CRLF & 'Int: ' & $r & @CRLF & ' 1.Bin: ' & $a[0] & @CRLF & ' 2.Bin: ' & $a[1] & @CRLF & ' 3.Bin: ' & $a[2])
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then
    Send(Round(($Zeitbedarf[0] / $Versuche) * 1000, 0), 1)
    Sleep(100)
    Send('{RIGHT}')
    Sleep(100)
    Send(Round(($Zeitbedarf[1] / $Versuche) * 1000, 0), 1)
    Sleep(100)
    Send('{RIGHT}')
    Sleep(100)
    Send(Round(($Zeitbedarf[2] / $Versuche) * 1000, 0), 1)
    Sleep(100)
    Send('{ENTER}')
    Sleep(100)
    Send('{LEFT}')
    Sleep(100)
    Send('{LEFT}')
    Sleep(100)
    Send('{LEFT}')
    Sleep(100)
    Else
    ConsoleWrite('Func 1: ' & Round($Zeitbedarf[0] / $Versuche, 5) & ' ms' & @CRLF & 'Func 2: ' & Round($Zeitbedarf[1] / $Versuche, 5) & ' ms' & @CRLF & 'Func 3: ' & Round($Zeitbedarf[2] / $Versuche, 5) & ' ms' & @CRLF)
    EndIf
    $Zeitbedarf[0] = 0
    $Zeitbedarf[1] = 0
    $Zeitbedarf[2] = 0

    [/autoit] [autoit][/autoit] [autoit]

    $Schritte += 1
    $Schritte *= 1.5
    $Schritte = Int($Schritte)

    [/autoit] [autoit][/autoit] [autoit]

    WEnd
    EndFunc ;==>_Main

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iDec) ; Ausgedachte Methode 1
    Local $sHex = Hex($iDec), $sRet, $aBin[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sHex, 1) = '0'
    $sHex = StringTrimLeft($sHex, 1)
    WEnd
    For $i = 1 To StringLen($sHex) Step 1
    $sRet &= $aBin[Int('0x' & StringMid($sHex, $i, 1))]
    Next
    While StringLeft($sRet, 1) = '0'
    $sRet = StringTrimLeft($sRet, 1)
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_3

    [/autoit]


    Anbei eine kleine Tabelle mit einem Geschwindigkeitsvergleich.

    Hier drin

    [Blockierte Grafik: http://i.imgur.com/QEjhm.png]

    lg
    Mars(i)


    -----------------------------------------------------------------------------------------------

  • Da ist aber jemand sehr anspruchsvoll wenn ihm 0.08ms nicht reichen. 8|
    Aber weshalb machst du es überhaupt als String? Wenn du es wirklich binär willst dann nimm doch einfach 'Binary()'. (Weis jetzt auch nicht wie schnell das ist)
    Wenn du es dann anzeigst hast dus halt in Hex. Aber ich weis ja jetzt nicht wozu man sowas brauchen kann... Wenn dus aber wirklich so willst
    wie du es gemacht hast, wird es wahrscheinlich schwierig da noch Geschwindigkeit rauszuholen.

  • Weil ich jetzt nicht so viel Zeit habe Abends habe ich den Spaß mal mit "nur" 1000 Versuchen durchlaufen lassen.

    Was die Textmenge angeht ist Bugfix' Version deutlich kleiner, Geschwindigkeitsmäßig kommt sie aber gegen die Divisionsmethode nicht an.
    (ich verstehe aber eigentlich nicht warum, da sie ja nichts anderes als diese tut...)

    Der Zahlenraum der Gemessen wird ist jetzt von 0 bis 2^31 - 1. (Vorher hat das Prog den Letzten Wert immer unterschlagen.)

    Code
    [autoit][/autoit] [autoit][/autoit] [autoit]

    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Local $Anz_Funktionen = 4
    Local $a[$Anz_Funktionen], $t, $r, $Zeitbedarf[$Anz_Funktionen], $Versuche = 1000, $Schritte = 0
    Local $Excel = False, $Letzte_Runde = False

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then Sleep(3000)

    [/autoit] [autoit][/autoit] [autoit]

    While $Schritte <= 2 ^ 31 - 1
    ConsoleWrite('Zahl: ' & $Schritte & @CRLF)
    If $Excel Then
    Send($Schritte, 1)
    Sleep(100)
    Send('{RIGHT}')
    Sleep(100)
    EndIf
    For $i = 0 To $Versuche Step 1
    $r = $Schritte
    $t = TimerInit()
    $a[0] = _DecToBin_1($r) ; Divisionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[0] += $t
    $t = TimerInit()
    $a[1] = _DecToBin_2($r) ; Subtraktionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[1] += $t
    $t = TimerInit()
    $a[2] = _DecToBin_3($r) ; Ausgedacht 1
    $t = TimerDiff($t)
    $Zeitbedarf[2] += $t
    $t = TimerInit()
    $a[3] = _IntToBin($r) ; Von Bugfix
    $t = TimerDiff($t)
    $Zeitbedarf[3] += $t
    If ($a[0] <> $a[1]) Or ($a[0] <> $a[2]) Or ($a[0] <> $a[3]) Then ; Falls Abweichende Ergebnisse vorkommen ist eine Funktion falsch !
    ConsoleWrite('Error: ' & @CRLF & 'Int: ' & $r & @CRLF & ' 1.Bin: ' & $a[0] & @CRLF & ' 2.Bin: ' & $a[1] & @CRLF & ' 3.Bin: ' & $a[2] & @CRLF & ' 4.Bin: ' & $a[3] & @CRLF)
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then
    For $_i = 0 To $Anz_Funktionen - 1 Step 1
    Send(Round(($Zeitbedarf[$_i] / $Versuche) * 1000, 0), 1)
    Sleep(70)
    Send('{RIGHT}')
    Sleep(70)
    Next
    Send('{ENTER}')
    For $_i = 0 To $Anz_Funktionen Step 1
    Sleep(70)
    Send('{LEFT}')
    Next
    Else
    ConsoleWrite('Func 1: ' & Round($Zeitbedarf[0] / $Versuche, 5) & ' ms' & @CRLF & 'Func 2: ' & Round($Zeitbedarf[1] / $Versuche, 5) & ' ms' & @CRLF & 'Func 3: ' & Round($Zeitbedarf[2] / $Versuche, 5) & ' ms' & @CRLF & 'Func 4: ' & Round($Zeitbedarf[3] / $Versuche, 5) & ' ms' & @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $_i = 0 To $Anz_Funktionen - 1
    $Zeitbedarf[$_i] = 0
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Schritte += 1
    $Schritte *= 1.4
    $Schritte = Int($Schritte)

    [/autoit] [autoit][/autoit] [autoit]

    If $Letzte_Runde Then ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    If $Schritte > 2^31 - 1 Then
    $Schritte = 2^31 - 1
    $Letzte_Runde = True
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    WEnd
    EndFunc ;==>_Main

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iDec) ; Ausgedachte Methode 1
    Local $sHex = Hex($iDec), $sRet, $aBin[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sHex, 1) = '0'
    $sHex = StringTrimLeft($sHex, 1)
    WEnd
    For $i = 1 To StringLen($sHex) Step 1
    $sRet &= $aBin[Int('0x' & StringMid($sHex, $i, 1))]
    Next
    While StringLeft($sRet, 1) = '0'
    $sRet = StringTrimLeft($sRet, 1)
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func _IntToBin($Value); von BugFix
    Local $bin
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Int($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_IntToBin

    [/autoit]
    Diagramm

    [Blockierte Grafik: http://i.imgur.com/lkCOC.png]

    Wenn man alle Funktionen kombiniert (mittels der eingangszahl zur jeweils dafür schnellsten Funktion switcht) müsste sich eine Funktion bauen lassen die immer knapp oberhalb der bisherigen Bestzeiten liegt.

    lg
    Mars(i)

  • Hier noch eine Methode
    bei Zahlen < 65536 wird Methode 1 angewendet, da sie bei mir am schnellsten war...

    Spoiler anzeigen
    [autoit]

    Func _DecToBin_4($iD)
    Local $sR
    If $iD < 65536 Then
    While Not $iD = 0
    $iD /= 2
    If IsInt($iD) Then
    $sR = '0' & $sR
    Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndIf
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $aS = StringSplit(Hex($iD), "")
    For $i = 1 To $aS[0]
    Switch $aS[$i]
    Case "0"
    $sR &= "0000"
    Case "1"
    $sR &= "0001"
    Case "2"
    $sR &= "0010"
    Case "3"
    $sR &= "0011"
    Case "4"
    $sR &= "0100"
    Case "5"
    $sR &= "0101"
    Case "6"
    $sR &= "0110"
    Case "7"
    $sR &= "0111"
    Case "8"
    $sR &= "1000"
    Case "9"
    $sR &= "1001"
    Case "A"
    $sR &= "1010"
    Case "B"
    $sR &= "1011"
    Case "C"
    $sR &= "1100"
    Case "D"
    $sR &= "1101"
    Case "E"
    $sR &= "1110"
    Case "F"
    $sR &= "1111"
    EndSwitch
    Next
    Return StringRegExpReplace($sR, "^0+([^0]|0$)", "\1", 1)
    EndIf
    EndFunc ;==>_DecToBin_4

    [/autoit]

    Edit: Deine Version ist allerdings am schnellsten, wenn man die Variablenamen noch kürzt und das Array als Static deklariert

    Spoiler anzeigen
    [autoit]

    Func _DecToBin_3($iD) ; Ausgedachte Methode 1
    Local $sR
    If $iD < 65536 Then
    While Not $iD = 0
    $iD /= 2
    If IsInt($iD) Then
    $sR = '0' & $sR
    Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndIf
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sH, 1) = '0'
    $sH = StringTrimLeft($sH, 1)
    WEnd
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    While StringLeft($sR, 1) = '0'
    $sR = StringTrimLeft($sR, 1)
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    EndIf
    EndFunc ;==>_DecToBin_3

    [/autoit]
  • Bei ganz kleinen Zahlen zwar etwas langsamer, aber ansonsten die schnellste Funktion ist diese hier:

    [autoit]

    Func _IntToBin($iInt)
    Local $tChr = DllStructCreate("char[64];")
    DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iInt, "ptr", DllStructGetPtr($tChr), "int", 2)
    If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_IntToBin

    [/autoit]


    Und hier auch noch gleich eine Funktion um verschiedene Systeme umzuwandeln:

    [autoit]

    Func _TranslateBase($sNumber, $iOldBase = 10, $iNewBase = 2)
    ;by eukalyptus
    If $iOldBase < 2 Or $iOldBase > 36 Or $iNewBase < 2 Or $iNewBase > 36 Then Return SetError(1, 1, False)

    [/autoit][autoit][/autoit][autoit]

    Local $iNum, $aRes, $tChr = DllStructCreate("char[64];")

    [/autoit][autoit][/autoit][autoit]

    If $iOldBase <> 10 Then
    $aRes = DllCall("msvcrt.dll", "uint64:cdecl", "_strtoui64", "str", $sNumber, "ptr", 0, "int", $iOldBase)
    If @error Then Return SetError(1, 2, False)
    $iNum = $aRes[0]
    Else
    $iNum = Int($sNumber)
    EndIf

    [/autoit][autoit][/autoit][autoit]

    $aRes = DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iNum, "ptr", DllStructGetPtr($tChr), "int", $iNewBase)
    If @error Then Return SetError(1, 3, False)

    [/autoit][autoit][/autoit][autoit]

    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_TranslateBase

    [/autoit]
  • Habs jetzt mal mit einer hohen Anzahl Durchläufe (5000) und einer engen Abfrage (1.1 Als Multiplikator) alles aufgezeichnet.

    Ich bedanke mich für die Vielen Funktionen die hier gezeigt wurden.
    Daran erkennt man doch auf wie vielen Wegen doch das gleiche (einfache) Ziel erreicht werden kann !

    Wie es zu erwarten war ist die Optimierte Kombinationsmethode (Bei kleinen Zahlen Division und bei Großen die Ausgedachte Methode) am Flottesten, wenn man auf DllCalls verzichtet.
    Der DllCall lässt aber alles alt aussehen. Ab einer Dezimalzahl > 16 liegt der Call mit der Nase vorne.

    Spoiler anzeigen
    [autoit]


    Global $MSVCRT_Dll = DllOpen('msvcrt.dll')

    [/autoit] [autoit][/autoit] [autoit]

    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    DllClose($MSVCRT_Dll)

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Local $Anz_Funktionen = 6
    Local $a[$Anz_Funktionen], $t, $r, $Zeitbedarf[$Anz_Funktionen], $Schritte = 0, $Letzte_Runde = False, $Werte = 0

    [/autoit] [autoit][/autoit] [autoit]

    Local $Versuche = 500, $Excel = False, $Multiplikator = 1.1

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then Sleep(3000)

    [/autoit] [autoit][/autoit] [autoit]

    While $Schritte <= 2 ^ 31 - 1
    ConsoleWrite('Zahl: ' & $Schritte & @CRLF)
    If $Excel Then
    Send($Schritte, 1)
    Sleep(100)
    Send('{RIGHT}')
    Sleep(100)
    EndIf
    For $i = 0 To $Versuche Step 1
    $r = $Schritte
    $t = TimerInit()
    $a[0] = _DecToBin_1($r) ; Divisionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[0] += $t
    $t = TimerInit()
    $a[1] = _DecToBin_2($r) ; Subtraktionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[1] += $t
    $t = TimerInit()
    $a[2] = _DecToBin_3($r) ; Ausgedacht 1
    $t = TimerDiff($t)
    $Zeitbedarf[2] += $t
    $t = TimerInit()
    $a[3] = _IntToBin($r) ; Von Bugfix
    $t = TimerDiff($t)
    $Zeitbedarf[3] += $t
    $t = TimerInit()
    $a[4] = _DecToBin_4($r) ; Kombination der Divisionsmethode und der Ausgedachten.
    $t = TimerDiff($t)
    $Zeitbedarf[4] += $t
    $t = TimerInit()
    $a[5] = _IntToBin_2($r) ; Funktion mit DllCall
    $t = TimerDiff($t)
    $Zeitbedarf[5] += $t
    If ($a[0] <> $a[1]) Or ($a[0] <> $a[2]) Or ($a[0] <> $a[3]) Or ($a[0] <> $a[4]) Or ($a[0] <> $a[5]) Then ; Falls Abweichende Ergebnisse vorkommen ist eine Funktion falsch !
    ConsoleWrite('Error: ' & @CRLF & 'Int: ' & $r & @CRLF & ' 1.Bin: ' & $a[0] & _
    @CRLF & ' 2.Bin: ' & $a[1] & _
    @CRLF & ' 3.Bin: ' & $a[2] & _
    @CRLF & ' 4.Bin: ' & $a[3] & _
    @CRLF & ' 5.Bin: ' & $a[4] & _
    @CRLF & ' 6.Bin: ' & $a[5] & _
    @CRLF)
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then
    For $_i = 0 To $Anz_Funktionen - 1 Step 1
    Send(Round(($Zeitbedarf[$_i] / $Versuche) * 10000, 0), 1)
    Sleep(70)
    Send('{RIGHT}')
    Sleep(70)
    Next
    Send('{ENTER}')
    For $_i = 0 To $Anz_Funktionen Step 1
    Sleep(70)
    Send('{LEFT}')
    Next
    Else
    ConsoleWrite('Func 1: ' & Round($Zeitbedarf[0] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 2: ' & Round($Zeitbedarf[1] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 3: ' & Round($Zeitbedarf[2] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 4: ' & Round($Zeitbedarf[3] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 5: ' & Round($Zeitbedarf[4] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 6: ' & Round($Zeitbedarf[5] / $Versuche, 6)*1000 & ' µs' & _
    @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $_i = 0 To $Anz_Funktionen - 1
    $Zeitbedarf[$_i] = 0
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Schritte = Int(($Schritte+1)*$Multiplikator)

    [/autoit] [autoit][/autoit] [autoit]

    $Werte += 1

    [/autoit] [autoit][/autoit] [autoit]

    If $Letzte_Runde Then ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    If $Schritte > 2^31 - 1 Then
    $Schritte = 2^31 - 1
    $Letzte_Runde = True
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('Erfasste Werte: ' & $Werte & @CRLF)
    EndFunc ;==>_Main

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iDec) ; Ausgedachte Methode 1
    Local $sHex = Hex($iDec), $sRet, $aBin[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sHex, 1) = '0'
    $sHex = StringTrimLeft($sHex, 1)
    WEnd
    For $i = 1 To StringLen($sHex) Step 1
    $sRet &= $aBin[Int('0x' & StringMid($sHex, $i, 1))]
    Next
    While StringLeft($sRet, 1) = '0'
    $sRet = StringTrimLeft($sRet, 1)
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func _IntToBin($Value); von BugFix
    Local $bin
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Int($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_IntToBin

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_4($iD) ; Kombination von Methode 1 und 3 mit kleinen Optimierungen
    Local $sR
    If $iD < 65536 Then
    While Not $iD = 0
    $iD /= 2
    If IsInt($iD) Then
    $sR = '0' & $sR
    Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndIf
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sH, 1) = '0'
    $sH = StringTrimLeft($sH, 1)
    WEnd
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    While StringLeft($sR, 1) = '0'
    $sR = StringTrimLeft($sR, 1)
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    EndIf
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit]

    Func _IntToBin_2($iInt)
    Local $tChr = DllStructCreate('char[64]')
    DllCall($MSVCRT_Dll, 'ptr:cdecl', '_i64toa', 'int64', $iInt, 'ptr', DllStructGetPtr($tChr), 'int', 2)
    ;~ If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_IntToBin

    [/autoit]

    Ich habe aber schon eine Idee, wie evtl noch mehr rauszuholen ist. Mal sehen ons klappt^^

    lg
    Mars(i)

    Spoiler anzeigen

    [Blockierte Grafik: http://i.imgur.com/JHOIH.png]

    Edit:
    Habe grade versucht ein Array mit 256*256*256 Elementen zu machen.
    Das klappte auch wunderbar, bis AutoIt bei 2,04 GB Ramverbrauch ankam und Abbrach.
    WOZU braucht AutoIt 2GB bei 16.777.216 Elementen ? Das sind über 127KB/Element !

    Edit2:
    Wenn einem eine kleine Startzeit keine Umstände macht habe ich eine recht flotte Funktion gefunden.
    Es werden 2 Arrays mit Binärzahlen von 0 bis 256*256 gefüllt, ein Mal mit den vielen Nullen vorne und einmal ohne.
    Anschließend teilt man die mit Hex($iDec) bearbeitete Zahl in 2x 2Byte (2x 256*256).
    Anschließend wird nur noch das Array abgerufen.

    Ergebnis: Bei zahlen kleiner 256² dauert die Funktion nur 8 bis 9 µs (liegt weit unterhalb allem was wir bisher hatten)
    Ab 256² braucht die Funktion ca. 19-21 µs, und ist damit einen Schritt schneller als der DllCall.

    Nachteil: Eine Ladezeit von ca. 7 Sek bei volllast.

    Spoiler anzeigen
    [autoit]


    Global $MSVCRT_Dll = DllOpen('msvcrt.dll')
    Global $aOhneNull[256*256], $aMitNull[256*256]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 0 To 256*256 - 1 Step 1
    $aOhneNull[$i] = _IntToBin_2($i)
    $aMitNull[$i] = _DecToBin_3_Mit($i)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    _Main()

    [/autoit] [autoit][/autoit] [autoit]

    DllClose($MSVCRT_Dll)

    [/autoit] [autoit][/autoit] [autoit]

    Func _Main()

    [/autoit] [autoit][/autoit] [autoit]

    Local $Anz_Funktionen = 6
    Local $a[$Anz_Funktionen], $t, $r, $Zeitbedarf[$Anz_Funktionen], $Schritte = 0, $Letzte_Runde = False, $Werte = 0

    [/autoit] [autoit][/autoit] [autoit]

    Local $Versuche = 1500, $Excel = False, $Multiplikator = 1.25

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then Sleep(3000)

    [/autoit] [autoit][/autoit] [autoit]

    While $Schritte <= 2 ^ 31 - 1
    ConsoleWrite('Zahl: ' & $Schritte & @CRLF)
    If $Excel Then
    Send($Schritte, 1)
    Sleep(100)
    Send('{RIGHT}')
    Sleep(100)
    EndIf
    For $i = 0 To $Versuche Step 1
    $r = $Schritte
    $t = TimerInit()
    $a[0] = _DecToBin_1($r) ; Divisionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[0] += $t
    $t = TimerInit()
    $a[1] = _DecToBin_2($r) ; Subtraktionsmethode
    $t = TimerDiff($t)
    $Zeitbedarf[1] += $t
    $t = TimerInit()
    $a[2] = _DecToBin_3($r) ; Arrayabruffunktion
    $t = TimerDiff($t)
    $Zeitbedarf[2] += $t
    $t = TimerInit()
    $a[3] = _IntToBin($r) ; Von Bugfix
    $t = TimerDiff($t)
    $Zeitbedarf[3] += $t
    $t = TimerInit()
    $a[4] = _DecToBin_4($r) ; Kombination der Divisionsmethode und der Ausgedachten.
    $t = TimerDiff($t)
    $Zeitbedarf[4] += $t
    $t = TimerInit()
    $a[5] = _IntToBin_2($r) ; Funktion mit DllCall
    $t = TimerDiff($t)
    $Zeitbedarf[5] += $t
    If ($a[0] <> $a[1]) Or ($a[0] <> $a[2]) Or ($a[0] <> $a[3]) Or ($a[0] <> $a[4]) Or ($a[0] <> $a[5]) Then ; Falls Abweichende Ergebnisse vorkommen ist eine Funktion falsch !
    ConsoleWrite('Error: ' & @CRLF & 'Int: ' & $r & @CRLF & ' 1.Bin: ' & $a[0] & _
    @CRLF & ' 2.Bin: ' & $a[1] & _
    @CRLF & ' 3.Bin: ' & $a[2] & _
    @CRLF & ' 4.Bin: ' & $a[3] & _
    @CRLF & ' 5.Bin: ' & $a[4] & _
    @CRLF & ' 6.Bin: ' & $a[5] & _
    @CRLF)
    ExitLoop
    EndIf
    Next

    [/autoit] [autoit][/autoit] [autoit]

    If $Excel Then
    For $_i = 0 To $Anz_Funktionen - 1 Step 1
    Send(Round(($Zeitbedarf[$_i] / $Versuche) * 10000, 0), 1)
    Sleep(70)
    Send('{RIGHT}')
    Sleep(70)
    Next
    Send('{ENTER}')
    For $_i = 0 To $Anz_Funktionen Step 1
    Sleep(70)
    Send('{LEFT}')
    Next
    Else
    ConsoleWrite('Func 1: ' & Round($Zeitbedarf[0] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 2: ' & Round($Zeitbedarf[1] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 3: ' & Round($Zeitbedarf[2] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 4: ' & Round($Zeitbedarf[3] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 5: ' & Round($Zeitbedarf[4] / $Versuche, 6)*1000 & ' µs' & @CRLF & _
    'Func 6: ' & Round($Zeitbedarf[5] / $Versuche, 6)*1000 & ' µs' & _
    @CRLF)
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    For $_i = 0 To $Anz_Funktionen - 1
    $Zeitbedarf[$_i] = 0
    Next

    [/autoit] [autoit][/autoit] [autoit]

    $Schritte = Int(($Schritte+1)*$Multiplikator)

    [/autoit] [autoit][/autoit] [autoit]

    $Werte += 1

    [/autoit] [autoit][/autoit] [autoit]

    If $Letzte_Runde Then ExitLoop

    [/autoit] [autoit][/autoit] [autoit]

    If $Schritte > 2^31 - 1 Then
    $Schritte = 2^31 - 1
    $Letzte_Runde = True
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite('Erfasste Werte: ' & $Werte & @CRLF)
    EndFunc ;==>_Main

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iDec) ; Ausgedachte Methode 2
    If $iDec < 65536 Then Return $aOhneNull[$iDec]
    Local $sHex = Hex($iDec)
    Return $aOhneNull[Int('0x' & StringLeft($sHex, 4))] & $aMitNull[Int('0x' & StringRight($sHex, 4))]
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3_Mit($iDec) ; Ausgedachte Methode 1
    Local $sHex = Hex($iDec), $sRet, $aBin[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To 8 Step 1
    $sRet &= $aBin[Int('0x' & StringMid($sHex, $i, 1))]
    Next
    If Not $sRet Then Return '0'
    Return StringRight($sRet, 16)
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func _IntToBin($Value); von BugFix
    Local $bin
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Int($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_IntToBin

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_4($iD) ; Kombination von Methode 1 und 3 mit kleinen Optimierungen
    Local $sR
    If $iD < 65536 Then
    While Not $iD = 0
    $iD /= 2
    If IsInt($iD) Then
    $sR = '0' & $sR
    Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndIf
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sH, 1) = '0'
    $sH = StringTrimLeft($sH, 1)
    WEnd
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    While StringLeft($sR, 1) = '0'
    $sR = StringTrimLeft($sR, 1)
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    EndIf
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit]

    Func _IntToBin_2($iInt)
    Local $tChr = DllStructCreate('char[64]')
    DllCall($MSVCRT_Dll, 'ptr:cdecl', '_i64toa', 'int64', $iInt, 'ptr', DllStructGetPtr($tChr), 'int', 2)
    ;~ If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_IntToBin

    [/autoit]
    Spoiler anzeigen

    [Blockierte Grafik: http://i.imgur.com/CFAYA.png]Y-Skalierung: 0.1 µs

  • Also wenn ich das heir starte ist meine Function die schnellste...
    :thumbup:

    Spoiler anzeigen
    [autoit]

    $timeinsgesammt =''
    $Forschleifebis = 2^31-1
    For $a = 1 To $Forschleifebis
    $time = TimerInit()
    convert($a)
    $timeinsgesammt += TimerDiff($time)
    Next
    ConsoleWrite("Meine Funktion: "&Round($timeinsgesammt / $a, 3) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $timeinsgesammt =''
    For $a = 1 To $Forschleifebis
    $time = TimerInit()
    convert1($a)
    $timeinsgesammt += TimerDiff($time)
    Next
    ConsoleWrite("Kombination von Methode 1 und 3 mit kleinen Optimierungen: "&Round($timeinsgesammt / $a, 3) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $timeinsgesammt =''
    For $a = 1 To $Forschleifebis
    $time = TimerInit()
    convert2($a)
    $timeinsgesammt += TimerDiff($time)
    Next
    ConsoleWrite("von BugFix: "&Round($timeinsgesammt / $a, 3) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $timeinsgesammt =''
    For $a = 1 To $Forschleifebis
    $time = TimerInit()
    convert3($a)
    $timeinsgesammt += TimerDiff($time)
    Next
    ConsoleWrite("Ausgedachte Methode 1: "&Round($timeinsgesammt / $a, 3) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $timeinsgesammt =''
    For $a = 1 To $Forschleifebis
    $time = TimerInit()
    convert4($a)
    $timeinsgesammt += TimerDiff($time)
    Next
    ConsoleWrite("Subtraktionsmethode: "&Round($timeinsgesammt / $a, 3) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    $timeinsgesammt =''
    For $a = 1 To $Forschleifebis
    $time = TimerInit()
    convert5($a)
    $timeinsgesammt += TimerDiff($time)
    Next
    ConsoleWrite("Divisionsmethode: "&Round($timeinsgesammt / $a, 3) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    While 1

    [/autoit] [autoit][/autoit] [autoit]

    WEnd
    Func convert($quelle)
    $bin = Hex($quelle)
    $aBin = StringSplit($bin, "")
    local $return = ""
    For $i = 1 To 8 Step +1
    Switch $aBin[$i]
    Case "0"
    $return &= "0000"
    Case "1"
    $return &= "0001"
    Case "2"
    $return &= "0010"
    Case "3"
    $return &= "0011"
    Case "4"
    $return &= "0100"
    Case "5"
    $return &= "0101"
    Case "6"
    $return &= "0110"
    Case "7"
    $return &= "0111"
    Case "8"
    $return &= "1000"
    Case "9"
    $return &= "1001"
    Case "A"
    $return &= "1010"
    Case "B"
    $return &= "1011"
    Case "C"
    $return &= "1100"
    Case "D"
    $return &= "1101"
    Case "E"
    $return &= "1110"
    Case "F"
    $return &= "1111"
    EndSwitch
    Next
    Return $return
    EndFunc ;==>convert1

    [/autoit] [autoit][/autoit] [autoit]

    Func convert1($iD) ; Kombination von Methode 1 und 3 mit kleinen Optimierungen
    Local $sR
    If $iD < 65536 Then
    While Not $iD = 0
    $iD /= 2
    If IsInt($iD) Then
    $sR = '0' & $sR
    Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndIf
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sH, 1) = '0'
    $sH = StringTrimLeft($sH, 1)
    WEnd
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    While StringLeft($sR, 1) = '0'
    $sR = StringTrimLeft($sR, 1)
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    EndIf
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit]

    Func Convert2($Value); von BugFix
    Local $bin
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Int($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_IntToBin

    [/autoit] [autoit][/autoit] [autoit]

    Func Convert3($iDec) ; Ausgedachte Methode 1
    Local $sHex = Hex($iDec), $sRet, $aBin[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    While StringLeft($sHex, 1) = '0'
    $sHex = StringTrimLeft($sHex, 1)
    WEnd
    For $i = 1 To StringLen($sHex) Step 1
    $sRet &= $aBin[Int('0x' & StringMid($sHex, $i, 1))]
    Next
    While StringLeft($sRet, 1) = '0'
    $sRet = StringTrimLeft($sRet, 1)
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func convert4($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit]

    Func convert5($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit]
  • Du bist leider nur an 4 Stelle!
    (Und das, obwohl du auch nicht die führenden Nullen wegmachst)

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>
    Global $tChr = DllStructCreate("char[64];")
    Global $pChr = DllStructGetPtr($tChr)
    Global $hDll = DllOpen("msvcrt.dll")

    [/autoit] [autoit][/autoit] [autoit]

    Global $iLoops = 500
    Global $iTestCnt = 7

    [/autoit] [autoit][/autoit] [autoit]

    Global $aTime[$iTestCnt + 1][2]
    $aTime[1][1] = "Divisionsmethode"
    $aTime[2][1] = "Subtraktionsmethode"
    $aTime[3][1] = "Ausgedachte Methode mit Optimierung"
    $aTime[4][1] = "DllCall"
    $aTime[5][1] = "DllCall mit Optimierung"
    $aTime[6][1] = "Buphx"
    $aTime[7][1] = "BugFix"

    [/autoit] [autoit][/autoit] [autoit]

    Global $iTimer, $iInt, $bDif
    Global $aRes[$iTestCnt + 1]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 31
    For $j = 1 To $iLoops
    $iInt = Int(2 ^ $i) + Random(0, 2 ^ ($i - 1), 1)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[1] = _DecToBin_1($iInt)
    $aTime[1][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[2] = _DecToBin_2($iInt)
    $aTime[2][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[3] = _DecToBin_3($iInt)
    $aTime[3][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[4] = _DecToBin_4($iInt)
    $aTime[4][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[5] = _DecToBin_5($iInt)
    $aTime[5][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[6] = _DecToBin_6($iInt)
    $aTime[6][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[7] = _DecToBin_7($iInt)
    $aTime[7][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $bDif = False
    For $x = 1 To $iTestCnt
    For $y = $x To $iTestCnt
    If $aRes[$x] <> $aRes[$y] Then
    $bDif = True
    ExitLoop 2
    EndIf
    Next
    Next
    If $bDif Then
    ConsoleWrite("! at least one result not correct: ")
    For $x = 1 To $iTestCnt
    ConsoleWrite($x & ":" & $aRes[$x] & " | ")
    Next
    ConsoleWrite(@CRLF)
    Else
    ConsoleWrite("+ all results correct: " & $iInt & " = " & $aRes[1] & @CRLF)
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _ArraySort($aTime)
    For $i = 1 To $iTestCnt
    ConsoleWrite("> " & Round($aTime[$i][0]) & " " & $aTime[$i][1] & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iD) ; Ausgedachte Methode 1
    Local $sR
    If $iD < 65536 Then
    While $iD
    $iD /= 2
    Switch IsInt($iD)
    Case True
    $sR = '0' & $sR
    Case Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndSwitch
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    Return StringRegExpReplace($sR, "^0+([^0]|0$)", "\1", 1)
    EndIf
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_4($iD)
    Local $tChr = DllStructCreate("char[64];")
    DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", DllStructGetPtr($tChr), "int", 2)
    If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_5($iD)
    DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", $pChr, "int", 2)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_5

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_6($quelle)
    $bin = Hex($quelle)
    $aBin = StringSplit($bin, "")
    Local $return = ""
    For $i = 1 To 8 Step +1
    Switch $aBin[$i]
    Case "0"
    $return &= "0000"
    Case "1"
    $return &= "0001"
    Case "2"
    $return &= "0010"
    Case "3"
    $return &= "0011"
    Case "4"
    $return &= "0100"
    Case "5"
    $return &= "0101"
    Case "6"
    $return &= "0110"
    Case "7"
    $return &= "0111"
    Case "8"
    $return &= "1000"
    Case "9"
    $return &= "1001"
    Case "A"
    $return &= "1010"
    Case "B"
    $return &= "1011"
    Case "C"
    $return &= "1100"
    Case "D"
    $return &= "1101"
    Case "E"
    $return &= "1110"
    Case "F"
    $return &= "1111"
    EndSwitch
    Next
    ;Return $return
    Return StringRegExpReplace($return, "^0+([^0]|0$)", "\1", 1)
    EndFunc ;==>_DecToBin_6

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_7($Value); von BugFix
    $bin = ''
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Floor($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_DecToBin_7

    [/autoit]


    Die Funktion von James1337 konnte ich leider nicht dazunehmen, da sie eine fixe Längenangabe verwendet...

    Ergebnis:

    Code
    > 458 DllCall mit Optimierung
    > 624 DllCall
    > 876 Ausgedachte Methode mit Optimierung
    > 1103 Buphx
    > 1131 Subtraktionsmethode
    > 1230 Divisionsmethode
    > 1334 BugFix

    E

  • Das ist bei mit noch faster also deine Func mit minimalen nderungen switch zu if abfrage usw

    Spoiler anzeigen
    [autoit]

    Func _DecToBin_3($iD) ; Ausgedachte Methode 1
    $sR =''
    If $iD < 65536 Then
    While $iD
    $iD /= 2
    if IsInt($iD) then
    $sR = '0' & $sR
    Else
    $sR = '1' & $sR
    $iD -= 0.5
    Endif
    WEnd
    Return $sR
    Else
    $sH = Hex($iD)
    Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    Return StringRegExpReplace($sR, "^0+([^0]|0$)", "\1", 1)
    EndIf
    EndFunc ;==>_DecToBin_3

    [/autoit]
  • Ich habe die Überlegung mit dem Array etwas weiterverfolgt und daraus eine Neue Funktion erstellt.

    Durch den Aufbau bedingt wird nun alles nur EIN Mal berechnet. d.h. Beim ersten Funktionsaufruf mit der Zahl 10 wird das Ergebnis in einem Array abgelegt. Bei einem weiteren Funktionsaufruf mit der 10 wird nur noch das Array ausgelesen.

    Bei meinem PC ist die Funktion mit 500 Durchläufen (Beim Skript von Eukalyptus) an 3ter Stelle. (also die schnellste native AutoIt Funktion).
    (Das liegt daran, dass vorallem zu Beginn immer wieder die gleichen Zahlen verwendet werden und daher einiges an Tempo rausgeholt werden kann)

    Wenn das Array aber erstmal voll ist, ist die Funktion sogar noch eine Ecke schneller als der Optimierte DllCall.
    Man hat also wie Wahl die Funktion zu initialisieren um sie direkt sehr schnell zu haben, oder sie einfach so zu nutzen.
    (Zeile 9 Auskommentieren)

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $tChr = DllStructCreate("char[64];")
    Global $pChr = DllStructGetPtr($tChr)
    Global $hDll = DllOpen("msvcrt.dll")
    Global $a[65536], $b[65536] ; Die nötigen globalen Variablen
    Global $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']

    [/autoit] [autoit][/autoit] [autoit]

    _ArraysFuellen() ; Füllt die Arrays mit Werten.

    [/autoit] [autoit][/autoit] [autoit]

    Global $iLoops = 500
    Global $iTestCnt = 8
    Global $bDebug = True

    [/autoit] [autoit][/autoit] [autoit]

    Global $aTime[$iTestCnt + 1][2]
    $aTime[1][1] = "Divisionsmethode"
    $aTime[2][1] = "Subtraktionsmethode"
    $aTime[3][1] = "Ausgedachte Methode mit Optimierung"
    $aTime[4][1] = "DllCall"
    $aTime[5][1] = "DllCall mit Optimierung"
    $aTime[6][1] = "Buphx"
    $aTime[7][1] = "BugFix"
    $aTime[8][1] = "Array"

    [/autoit] [autoit][/autoit] [autoit]

    Global $iTimer, $iInt, $bDif, $iCounter
    Global $aRes[$iTestCnt + 1]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 31
    $iCounter += 1
    For $j = 1 To $iLoops
    $iInt = Int(2 ^ $i) + Random(0, 2 ^ ($i - 1), 1)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[1] = _DecToBin_1($iInt)
    $aTime[1][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[2] = _DecToBin_2($iInt)
    $aTime[2][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[3] = _DecToBin_3($iInt)
    $aTime[3][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[4] = _DecToBin_4($iInt)
    $aTime[4][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[5] = _DecToBin_5($iInt)
    $aTime[5][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[6] = _DecToBin_6($iInt)
    $aTime[6][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[7] = _DecToBin_7($iInt)
    $aTime[7][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[8] = _DecToBin_8($iInt)
    $aTime[8][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $bDif = False
    For $x = 1 To $iTestCnt
    For $y = $x To $iTestCnt
    If $aRes[$x] <> $aRes[$y] Then
    $bDif = True
    ExitLoop 2
    EndIf
    Next
    Next
    If $bDebug Then
    If $bDif Then
    ConsoleWrite("! at least one result not correct: ")
    For $x = 1 To $iTestCnt
    ConsoleWrite($x & ":" & $aRes[$x] & " | ")
    Next
    ConsoleWrite(@CRLF)
    Else
    ConsoleWrite("+ all results correct: " & $iInt & " = " & $aRes[1] & @CRLF)
    EndIf
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _ArraySort($aTime)
    For $i = 1 To $iTestCnt
    ConsoleWrite("> " & Round($aTime[$i][0]) & " ms " & $aTime[$i][1] & " (" & Round(($aTime[$i][0]*1000)/($iLoops*$iCounter), 2) & "µs)" & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    DllClose($hDll)
    $tChr = 0

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($iDec) ; Subtraktionsmethode
    Local $sRet
    $iDec += 1
    For $i = Ceiling(Log($iDec) / Log(2)) To 0 Step -1
    If $iDec - 2 ^ $i > 0 Then
    $sRet &= '1'
    $iDec -= 2 ^ $i
    Else
    If $sRet Then $sRet &= '0'
    EndIf
    Next
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_2

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iD) ; Ausgedachte Methode 1
    Local $sR
    If $iD < 65536 Then
    While $iD
    $iD /= 2
    Switch IsInt($iD)
    Case True
    $sR = '0' & $sR
    Case Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndSwitch
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    Return StringRegExpReplace($sR, "^0+([^0]|0$)", "\1", 1)
    EndIf
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_4($iD)
    Local $tChr = DllStructCreate("char[64];")
    DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", DllStructGetPtr($tChr), "int", 2)
    If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_5($iD)
    DllCall($hDll, "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", $pChr, "int", 2)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_5

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_6($quelle)
    $bin = Hex($quelle)
    $aBin = StringSplit($bin, "")
    Local $return = ""
    For $i = 1 To 8 Step +1
    Switch $aBin[$i]
    Case "0"
    $return &= "0000"
    Case "1"
    $return &= "0001"
    Case "2"
    $return &= "0010"
    Case "3"
    $return &= "0011"
    Case "4"
    $return &= "0100"
    Case "5"
    $return &= "0101"
    Case "6"
    $return &= "0110"
    Case "7"
    $return &= "0111"
    Case "8"
    $return &= "1000"
    Case "9"
    $return &= "1001"
    Case "A"
    $return &= "1010"
    Case "B"
    $return &= "1011"
    Case "C"
    $return &= "1100"
    Case "D"
    $return &= "1101"
    Case "E"
    $return &= "1110"
    Case "F"
    $return &= "1111"
    EndSwitch
    Next
    ;Return $return
    Return StringRegExpReplace($return, "^0+([^0]|0$)", "\1", 1)
    EndFunc ;==>_DecToBin_6

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_7($Value); von BugFix
    $bin = ''
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Floor($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_DecToBin_7

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_8($iD)

    [/autoit] [autoit][/autoit] [autoit]

    If $iD < 65536 Then ; Wenn die Zahl kleiner ist, passt sie in das Array $a
    If $a[$iD] Then Return $a[$iD]
    Local $sH = StringRight(Hex($iD), 4)
    ;~ Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To StringLen($sH) Step 1
    $a[$iD] &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    $a[$iD] = StringRegExpReplace($a[$iD], '^0+([^0]|0$)', '\1', 1)
    Return $a[$iD]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    ;Die Zahl ist nicht kleiner -> Sie muss in 2 Teile (0xFFFF) geteilt werden, da ein einziges Array zu groß würde um alle Werte zu speichern.

    [/autoit] [autoit][/autoit] [autoit]

    Local $sH = Hex($iD), $1 = Int('0x' & StringLeft($sH, 4)), $2 = Int('0x' & StringRight($sH, 4))

    [/autoit] [autoit][/autoit] [autoit]

    If $a[$1] Then ; Wenn der erste Teil bereits erzeugt wurde

    [/autoit] [autoit][/autoit] [autoit]

    If $b[$2] Then ; Wenn auch der 2te Teil bereits vorliegt, ist alles klar -> Return !
    Return $a[$1] & $b[$2]
    Else ; 2ter Teil liegt noch nicht vor -> Erzeugen !
    ;~ Local Static $aD[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    $sH = StringRight(Hex($2), 4)
    For $i = 1 To StringLen($sH) Step 1
    $b[$2] &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    $b[$2] = StringRight($b[$2], 16)
    Return $a[$1] & $b[$2]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    Else ; Der erste Teil liegt nich nicht vor...

    [/autoit] [autoit][/autoit] [autoit]

    ;~ Local Static $aC[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    $sH = StringRight(Hex($1), 4)
    For $i = 1 To StringLen($sH) Step 1
    $a[$1] &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    $a[$1] = StringRegExpReplace($a[$1], '^0+([^0]|0$)', '\1', 1)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ; Der Erste Teil ist nun fertig.

    [/autoit] [autoit][/autoit] [autoit]

    If $b[$2] Then ; Wenn auch der 2te da ist -> Ret
    Return $a[$1] & $b[$2]
    Else ; Sonst -> Den 2ten erzeugen.
    ;~ Local Static $aE[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    $sH = StringRight(Hex($2), 4)
    For $i = 1 To StringLen($sH) Step 1
    $b[$2] &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    $b[$2] = StringRight($b[$2], 16)
    Return $a[$1] & $b[$2]
    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    EndIf

    [/autoit] [autoit][/autoit] [autoit]

    EndFunc ;==>_DecToBin_8

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArraysFuellen() ; Füllt $a und $b mit Werten
    Local $sH
    For $i = 0 To 65535
    $sH = Hex($i)
    For $_i = 1 To StringLen($sH) Step 1
    $b[$i] &= $aB[Int('0x' & StringMid($sH, $_i, 1))]
    Next
    $b[$i] = StringRight($b[$i], 16)
    For $_i = 1 To StringLen($sH) Step 1
    $a[$i] &= $aB[Int('0x' & StringMid($sH, $_i, 1))]
    Next
    $a[$i] = StringRegExpReplace($a[$i], '^0+([^0]|0$)', '\1', 1)
    Next
    EndFunc ;==>_ArraysFuellen

    [/autoit]
    Code
    > 329ms Array (21.22µs)
    > 418ms DllCall mit Optimierung (26.95µs)
    > 655ms DllCall (42.27µs)
    > 942ms Ausgedachte Methode mit Optimierung (60.8µs)
    > 1201ms Buphx (77.46µs)
    > 1227ms Subtraktionsmethode (79.14µs)
    > 1276ms Divisionsmethode (82.3µs)
    > 1488ms BugFix (95.97µs)

    lg
    Mars(i)

  • Moin,

    Hätte selbst nicht erwartet, dass ich diesen Thread nochmal ausgrabe...
    Der Anlass ist der TernäreOperator, AutoIt 3.3.10.x, usw usw. Es hat sich viel getan.
    Die Computer sind schneller geworden, AutoIt eventuell auch, und wir können besser Programmieren.

    Änderungen zum Vorpost:
    Meine wunderschöne Arraymethode funktioniert mit 3.3.10.x nicht mehr für Zahlen über 256^2.
    Aus mir noch nicht ganz klaren Gründen lief auch die Subtraktionsmethode nicht mehr. Da diese aber sowieso im Abstiegskampf ist habe ich sie einfach mal rausgeworfen.
    Die Methode von Buphx hat auch irgendeinen Fehler gehabt...

    Neu:
    Optimierte Array Methode.
    - Ladezeit nun im 1ms Bereich (vorher ca. 2s), es muss wieder mit einer externen Funktion geladen werden !
    - Geschwindigkeit ca. 2x höher
    - Läuft mit Zahlen bis 2^31 - 1
    - Nur eine Hand voll Codezeilen

    Wer also Dualzahlen braucht hat nun eine doppelt so schnelle Funktion (quasi ohne Ladezeit) :)

    Neuer Vergleich
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $tChr = DllStructCreate("char[64];")
    Global $pChr = DllStructGetPtr($tChr)
    Global $hDll = DllOpen("msvcrt.dll")
    Global $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    Global $_aBin256[256], $_bBin256[256]

    [/autoit] [autoit][/autoit] [autoit]

    _ArraysFuellen()

    [/autoit] [autoit][/autoit] [autoit]

    Global $iLoops = 500
    Global $iTestCnt = 7
    Global $bDebug = True

    [/autoit] [autoit][/autoit] [autoit]

    Global $aTime[$iTestCnt + 1][2]
    $aTime[1][1] = "Divisionsmethode"
    $aTime[2][1] = "Array mit Optimierung"
    $aTime[3][1] = "Ausgedachte Methode mit Optimierung"
    $aTime[4][1] = "DllCall"
    $aTime[5][1] = "DllCall mit Optimierung"
    $aTime[6][1] = "BugFix"
    $aTime[7][1] = "Array mit Optimierung und Ternärem Operator"

    [/autoit] [autoit][/autoit] [autoit]

    Global $iTimer, $iInt, $bDif, $iCounter
    Global $aRes[$iTestCnt + 1]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 31
    $iCounter += 1
    For $j = 1 To $iLoops
    $iInt = Random(2^($i-1)-1, 2^$i-1, 1)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[1] = _DecToBin_1($iInt)
    $aTime[1][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[2] = _DecToBin_2($iInt)
    $aTime[2][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[3] = _DecToBin_3($iInt)
    $aTime[3][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[4] = _DecToBin_4($iInt)
    $aTime[4][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[5] = _DecToBin_5($iInt)
    $aTime[5][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[6] = _DecToBin_6($iInt)
    $aTime[6][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[7] = _DecToBin_7($iInt)
    $aTime[7][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $bDif = False
    For $x = 1 To $iTestCnt
    For $y = $x To $iTestCnt
    If $aRes[$x] <> $aRes[$y] Then
    $bDif = True
    ExitLoop 2
    EndIf
    Next
    Next
    If $bDebug Then
    If $bDif Then
    ConsoleWrite("! at least one result not correct: ")
    For $x = 1 To $iTestCnt
    ConsoleWrite($x & ":" & $aRes[$x] & " | ")
    Next
    ConsoleWrite(@CRLF)
    Else
    ConsoleWrite("+ all results correct: " & $iInt & " = " & $aRes[1] & @CRLF)
    EndIf
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _ArraySort($aTime)
    For $i = 1 To $iTestCnt
    ConsoleWrite("> " & Round($aTime[$i][0]) & " ms " & $aTime[$i][1] & " (" & Round(($aTime[$i][0]*1000)/($iLoops*$iCounter), 2) & "µs)" & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    DllClose($hDll)
    $tChr = 0

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($d)
    If $d < 256 Then Return $_aBin256[$d]
    If $d < 65536 Then Return $_aBin256[BitShift($d,8)] & $_bBin256[BitAND($d, 255)]
    If $d < 16777216 Then Return $_aBin256[BitShift($d,16)] & $_bBin256[BitAND(BitShift($d,8), 255)] & $_bBin256[BitAND($d, 255)]
    Return $_aBin256[BitShift($d,24)] & $_bBin256[BitAND(BitShift($d,16), 255)] & $_bBin256[BitAND(BitShift($d,8), 255)] & $_bBin256[BitAND($d, 255)]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_7($d)
    Return $d<256?$_aBin256[$d]:$d<65536?$_aBin256[BitShift($d,8)]& _
    $_bBin256[BitAND($d,255)]:$d<16777216?$_aBin256[BitShift($d,16) _
    ]&$_bBin256[BitAND(BitShift($d,8),255)]&$_bBin256[BitAND($d,255 _
    )]:$_aBin256[BitShift($d,24)]&$_bBin256[BitAND(BitShift($d,16), _
    255)]&$_bBin256[BitAND(BitShift($d,8),255)]&$_bBin256[BitAND($d,255)]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iD) ; Ausgedachte Methode 1
    Local $sR
    If $iD < 65536 Then
    While $iD
    $iD /= 2
    Switch IsInt($iD)
    Case True
    $sR = '0' & $sR
    Case Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndSwitch
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    Return StringRegExpReplace($sR, "^0+([^0]|0$)", "\1", 1)
    EndIf
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_4($iD)
    Local $tChr = DllStructCreate("char[64];")
    DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", DllStructGetPtr($tChr), "int", 2)
    If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_5($iD)
    DllCall($hDll, "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", $pChr, "int", 2)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_5

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_6($Value); von BugFix
    $bin = ''
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Floor($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_DecToBin_7

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArraysFuellen() ; Damit alle Werte von 0 bis 255 direkt vorliegen und keine Berechnungen nötig sind.
    For $i = 0 To 255 Step 1
    $_aBin256[$i] = _DecToBin_6($i)
    $_bBin256[$i] = StringRight('0000000' & _DecToBin_6($i), 8)
    Next
    EndFunc ;==>_ArrayFuellen

    [/autoit]
    Code
    > 87 ms Array mit Optimierung und Ternärem Operator (5.59µs)
    > 112 ms Array mit Optimierung (7.26µs)
    > 200 ms DllCall mit Optimierung (12.88µs)
    > 311 ms DllCall (20.08µs)
    > 390 ms Ausgedachte Methode mit Optimierung (25.19µs)
    > 542 ms Divisionsmethode (34.98µs)
    > 598 ms BugFix (38.58µs)

    lg
    Mars

  • Man kann BugFix' Methode ein bisschen pimpen:

    [autoit]


    Func _DecToBin_6($Value); von BugFix
    Local $bin = '', $bs
    Do
    $bs = BitShift($Value, 1)
    $bin = $Value - $bs * 2 & $bin
    $Value = $bs
    Until Not $Value
    Return $bin
    EndFunc ;==>_DecToBin_7

    [/autoit]

    Ist zwar immer noch die Langsamste (auf meinem Rechner), aber ein paar µ Sekunden schneller.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    Einmal editiert, zuletzt von UEZ (9. Januar 2014 um 00:25)

  • Hi,
    ich habe das mal "klassisch", also wie schon vor ca. 30 Jahren auf dem IBM-XT (8088@4.77Mhz) mit Assembler gelöst.
    Prinzip ist einfach, der Integer steht im Prozessorregister, und die einzelnen Bits lassen sich per Shift-Befehl (in diesem Fall nach links) aus dem Register schieben.
    Dabei landet das "herausgeschobene" Bit im Carryflag CF und kann somit einfachst abgefragt werden. 32Bytes als String im ASM-Programm reservieren, eine Schleife, welche 32x ein Bit shiftet, und wenn Carryflag=1 dann eine "1" in den String schreiben, Pointer auf den String zurückgeben, fertig. 5 Minuten Arbeit....

    Um nicht "extern" 32 Bytes an Speicher für den Rückgabe-String reservieren zu müssen, habe ich zunächst 32 Bytes direkt im Assemblerprogramm reserviert. Vorteil: Es wird nur der Integer übergeben, und als Rückgabe bekommt man einen String, sehr geschmeidig. Ich habe allerdings nicht schlecht gestaunt, als die Laufzeit zwischen (festhalten) 20.000 und hunderttausend Takten lag! Über den Daumen gepeilt hatte ich schlimmstenfalls mit 200 Takten gerechnet... ?( DAS musste besser werden! Da kann man mal sehen, wie bekloppt man ist, die Laufzeit betrug "langsam" 0.04 Millisekunden :rolleyes:

    Erst gab ich meinem Prozessor bzw. Windows die Schuld, die beiden haben sich nämlich, wenn sonst nichts großartiges anliegt, darauf geeinigt, Prozessorkerne aus energiesparpolitischen Gründen permanent im Tiefschlaf zu halten. Ich vermutete, dass das kurze ASM-Progrämmchen (passt komplett in eine Pipeline) nicht in der Lage ist, den Prozessor zu "wecken". Dem war aber nicht so!
    Letztendlich hat nur geholfen, AutoIt eine "externe" Struct für den Rückgabestring erstellen zu lassen, in welche das ASM-Programm das Ergebnis schreibt. Damit war die Laufzeit bei ca. 150-200 Takten, was im Vergleich zu den vorliegenden Scripten zu Platz 3 gereicht hat :D
    Wahrscheinlich stellt sich Windows quer, wenn Speicher im Code- statt im Datensegment beschrieben/gelesen werden soll.....keine Ahnung, ob da spezielle Schutz-Mechanismen greifen und deshalb Schreib/Lesebefehle so lange dauern... :wacko:

    Spoiler anzeigen
    [autoit]

    #AutoIt3Wrapper_UseX64=n
    ;#include "AssembleIt2.au3"

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;Assemblercode wandelt Integerzahl in Binärdarstellung
    ;nur bei Verwendung von AssembleIt2() nötig
    #cs int2dec
    use32 ;32-Bitmode

    [/autoit] [autoit][/autoit] [autoit]

    mov edi,[esp+4] ;integer
    mov edx,[esp+8] ;pointer auf Rückgabestring

    [/autoit] [autoit][/autoit] [autoit]

    mov ecx,-1 ;32 bit shiften, bei null gehts los...

    [/autoit] [autoit][/autoit] [autoit]

    shiften:
    add ecx,1 ;nächstes shift

    [/autoit] [autoit][/autoit] [autoit]

    cmp ecx,32 ;wenn 32 bit geshiftet...
    je ende ;dann ende

    [/autoit] [autoit][/autoit] [autoit]

    shl edi,1 ;nach links shiften
    jnc shiften ;wenn keine 1 im carryflag=> weitershiften

    [/autoit] [autoit][/autoit] [autoit]

    eins: ;1 im Carryflag
    mov byte[edx+ecx],'1' ;1 in retstring
    jmp shiften ;nächstes bit shiften

    [/autoit] [autoit][/autoit] [autoit]

    ende: ;32 Bits wurden geshiftet

    [/autoit] [autoit][/autoit] [autoit]

    mov ecx,-1 ;welches ist die erste 1 im string, dort pointeradresse

    [/autoit] [autoit][/autoit] [autoit]

    schleife:
    add ecx,1
    cmp ecx,31 ;31 bytes erreicht?
    je raus ;dann ist ecx+edx der pointer
    cmp byte [edx+ecx],'1' ;ist byte im Rückgabestring eine '1'?
    jne schleife ;wenn keine 1, dann nächstes byte im string

    [/autoit] [autoit][/autoit] [autoit]

    raus:
    add edx,ecx ;pointer auf erste 1 im string, ab dort darstellen
    mov eax,edx ;pointer auf rückgabestring zurückgeben

    [/autoit] [autoit][/autoit] [autoit]

    ret

    [/autoit] [autoit][/autoit] [autoit]

    #ce

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    ;assemblercode in den Speicher schreiben, die folgenden Zeilen wurden von AssembleIt2() erstellt
    $ret_asm = "0x8B7C24048B542408B9FFFFFFFF83C10183F920740AD1E773F4C6040A31EBEEB9FFFFFFFF83C10183F91F7406803C0A3175F201CA89D0C3"
    $struct_asm = DllStructCreate("byte[" & StringLen($ret_asm) / 2 - 1 & "]") ;platz für asmcode im speicher
    $ptr_asm = DllStructGetPtr($struct_asm) ;pointer asmcode
    DllStructSetData($struct_asm, 1, $ret_asm) ;asmcode in struct schreiben

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $int = 0xDEADBEEF ;integer

    [/autoit] [autoit][/autoit] [autoit]

    ;rückgabe
    $struct = DllStructCreate("char [32];int");32 Byte string plus Nullbyte als Stringende
    $addr = DllStructGetPtr($struct)

    [/autoit] [autoit][/autoit] [autoit]

    ;~ DllStructSetData($struct, 1, "00000000000000000000000000000000") ;string mit Nullen erstellen
    ;~ $ret = _AssembleIt2("str*", "int2dec", "int", $int,"ptr",$addr)
    ;~ ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    DllStructSetData($struct, 1, "00000000000000000000000000000000") ;string mit Nullen erstellen
    $ret = DllCallAddress("str*:cdecl", $ptr_asm, "int", $int, "ptr", $addr) ;int nach bin
    ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ret = ' & $ret[0] & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console

    [/autoit] [autoit][/autoit] [autoit][/autoit]

    Bei der Verwendung anderer Prozessorbefehle geht das alles auch noch viel kürzer und ggf. auch schneller, aber so bleibe ich wieder mal bei den maximal 10 von mir verwendeten ASM-Befehlen. Damit kann man alles machen. Mehr braucht man nicht 8o

  • 30% Der Aufrufzeit deiner Funktion gehen durch das DllStructSetData flöten. Aber egal ob mit- oder ohne den Aufruf: Die Asm Methode ist trotz enormem DllCallAdress Overhead die schnellste die es tatsächlich berechnet. Die Arraymethode ist ja im Prinzip Schummelei. Um das Array vorzubereiten braucht man sowieso eine "richtige" Methode. Und da ist die ASM-Methode mit dem Tempo gut geeignet :)

    Spoiler anzeigen
    [autoit]

    #include <Array.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Global $tChr = DllStructCreate("char[64];")
    Global $pChr = DllStructGetPtr($tChr)
    Global $hDll = DllOpen("msvcrt.dll")
    Global $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    Global $_aBin256[256], $_bBin256[256]
    Global $vStr8 = DllStructCreate('char [32];int')
    Global $iAddr8 = DllStructGetPtr($vStr8)

    [/autoit] [autoit][/autoit] [autoit]

    Global $ret_asm = "0x8B7C24048B542408B9FFFFFFFF83C10183F920740AD1E773F4C6040A31EBEEB9FFFFFFFF83C10183F91F7406803C0A3175F201CA89D0C3"
    Global $struct_asm = DllStructCreate("byte[" & StringLen($ret_asm) / 2 - 1 & "]") ;platz für asmcode im speicher
    Global $iPtr8 = DllStructGetPtr($struct_asm) ;pointer asmcode
    DllStructSetData($struct_asm, 1, $ret_asm)

    [/autoit] [autoit][/autoit] [autoit]

    _ArraysFuellen()

    [/autoit] [autoit][/autoit] [autoit]

    Global $iLoops = 500
    Global $iTestCnt = 8
    Global $bDebug = False

    [/autoit] [autoit][/autoit] [autoit]

    Global $aTime[$iTestCnt + 1][2]
    $aTime[1][1] = "Divisionsmethode"
    $aTime[2][1] = "Array mit Optimierung"
    $aTime[3][1] = "Ausgedachte Methode mit Optimierung"
    $aTime[4][1] = "DllCall"
    $aTime[5][1] = "DllCall mit Optimierung"
    $aTime[6][1] = "BugFix"
    $aTime[7][1] = "Array mit Optimierung und Ternärem Operator"
    $aTime[8][1] = "Assembler von Andy"

    [/autoit] [autoit][/autoit] [autoit]

    Global $iTimer, $iInt, $bDif, $iCounter
    Global $aRes[$iTestCnt + 1]

    [/autoit] [autoit][/autoit] [autoit]

    For $i = 1 To 31
    $iCounter += 1
    For $j = 1 To $iLoops
    $iInt = Random(2^($i-1)-1, 2^$i-1, 1)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[1] = _DecToBin_1($iInt)
    $aTime[1][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[2] = _DecToBin_2($iInt)
    $aTime[2][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[3] = _DecToBin_3($iInt)
    $aTime[3][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[4] = _DecToBin_4($iInt)
    $aTime[4][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[5] = _DecToBin_5($iInt)
    $aTime[5][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[6] = _DecToBin_6($iInt)
    $aTime[6][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[7] = _DecToBin_7($iInt)
    $aTime[7][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit]

    $iTimer = TimerInit()
    $aRes[8] = _DecToBin_8($iInt)
    $aTime[8][0] += TimerDiff($iTimer)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $bDif = False
    For $x = 1 To $iTestCnt
    For $y = $x To $iTestCnt
    If $aRes[$x] <> $aRes[$y] Then
    $bDif = True
    ExitLoop 2
    EndIf
    Next
    Next
    If $bDebug Then
    If $bDif Then
    ConsoleWrite("! at least one result not correct: ")
    For $x = 1 To $iTestCnt
    ConsoleWrite($x & ":" & $aRes[$x] & " | ")
    Next
    ConsoleWrite(@CRLF)
    Else
    ConsoleWrite("+ all results correct: " & $iInt & " = " & $aRes[1] & @CRLF)
    EndIf
    EndIf
    Next
    Next

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    _ArraySort($aTime)
    For $i = 1 To $iTestCnt
    ConsoleWrite("> " & Round($aTime[$i][0]) & " ms " & $aTime[$i][1] & " (" & Round(($aTime[$i][0]*1000)/($iLoops*$iCounter), 2) & "µs)" & @CRLF)
    Next

    [/autoit] [autoit][/autoit] [autoit]

    DllClose($hDll)
    $tChr = 0

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_8($iDec)
    DllStructSetData($vStr8, 1, '00000000000000000000000000000000')
    Return DllCallAddress('str*:cdecl', $iPtr8, 'int', $iDec, 'ptr', $iAddr8)[0]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_1($iDec) ; Divisionsmethode
    Local $sRet
    While Not $iDec = 0
    $iDec /= 2
    If IsInt($iDec) Then
    $sRet = '0' & $sRet
    Else
    $sRet = '1' & $sRet
    $iDec -= 0.5 ; Ohne den Rest gehts weiter
    EndIf
    WEnd
    If Not $sRet Then Return '0'
    Return $sRet
    EndFunc ;==>_DecToBin_1

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_2($d)
    If $d < 256 Then Return $_aBin256[$d]
    If $d < 65536 Then Return $_aBin256[BitShift($d,8)] & $_bBin256[BitAND($d, 255)]
    If $d < 16777216 Then Return $_aBin256[BitShift($d,16)] & $_bBin256[BitAND(BitShift($d,8), 255)] & $_bBin256[BitAND($d, 255)]
    Return $_aBin256[BitShift($d,24)] & $_bBin256[BitAND(BitShift($d,16), 255)] & $_bBin256[BitAND(BitShift($d,8), 255)] & $_bBin256[BitAND($d, 255)]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_7($d)
    Return $d<256?$_aBin256[$d]:$d<65536?$_aBin256[BitShift($d,8)]& _
    $_bBin256[BitAND($d,255)]:$d<16777216?$_aBin256[BitShift($d,16) _
    ]&$_bBin256[BitAND(BitShift($d,8),255)]&$_bBin256[BitAND($d,255 _
    )]:$_aBin256[BitShift($d,24)]&$_bBin256[BitAND(BitShift($d,16), _
    255)]&$_bBin256[BitAND(BitShift($d,8),255)]&$_bBin256[BitAND($d,255)]
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_3($iD) ; Ausgedachte Methode 1
    Local $sR
    If $iD < 65536 Then
    While $iD
    $iD /= 2
    Switch IsInt($iD)
    Case True
    $sR = '0' & $sR
    Case Else
    $sR = '1' & $sR
    $iD -= 0.5
    EndSwitch
    WEnd
    If Not $sR Then Return '0'
    Return $sR
    Else
    Local $sH = Hex($iD)
    Local Static $aB[16] = ['0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111', '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111']
    For $i = 1 To StringLen($sH) Step 1
    $sR &= $aB[Int('0x' & StringMid($sH, $i, 1))]
    Next
    Return StringRegExpReplace($sR, "^0+([^0]|0$)", "\1", 1)
    EndIf
    EndFunc ;==>_DecToBin_3

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_4($iD)
    Local $tChr = DllStructCreate("char[64];")
    DllCall("msvcrt.dll", "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", DllStructGetPtr($tChr), "int", 2)
    If @error Then Return SetError(1, 0, False)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_4

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_5($iD)
    DllCall($hDll, "ptr:cdecl", "_i64toa", "int64", $iD, "ptr", $pChr, "int", 2)
    Return DllStructGetData($tChr, 1)
    EndFunc ;==>_DecToBin_5

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin_6($Value); von BugFix
    $bin = ''
    Do
    $bin = Mod($Value, 2) & $bin
    $Value = Floor($Value / 2)
    Until $Value = 0
    Return $bin
    EndFunc ;==>_DecToBin_7

    [/autoit] [autoit][/autoit] [autoit]

    Func _ArraysFuellen() ; Damit alle Werte von 0 bis 255 direkt vorliegen und keine Berechnungen nötig sind.
    For $i = 0 To 255 Step 1
    $_aBin256[$i] = _DecToBin_6($i)
    $_bBin256[$i] = StringRight('0000000' & _DecToBin_6($i), 8)
    Next
    EndFunc ;==>_ArrayFuellen

    [/autoit]
    Code
    Berechnet mit meiner Intel Atom Möhre.
    > 721 ms Array mit Optimierung und Ternärem Operator (46.5µs)
    > 911 ms Array mit Optimierung (58.79µs)
    > 1355 ms Assembler von Andy (87.4µs)
    > 1516 ms DllCall mit Optimierung (97.8µs)
    > 2372 ms DllCall (153.02µs)
    > 3090 ms Ausgedachte Methode mit Optimierung (199.36µs)
    > 4373 ms Divisionsmethode (282.14µs)
    > 4721 ms BugFix (304.55µs)


    lg
    M

  • "Berechnet" wird in den "Array mit Optimierung"-Methoden sowieso nichts^^
    Da wird einfach über den eingegebenen Index in einem Array dessen Wert zurückgegeben.
    Schreibe diese "Werte" in eine LUT, greife per ASM darauf zu und du hast deinen 3-Zeiler :rofl:
    Schreibt man die LUT vorab in eine Struct, ist dllcalladdress bestimmt sauschnell 8o

    //EDIT habe AssembleIt2() übrigens von der Laufzeit extrem beschleunigt. Die dll wird nur noch einmal am Start des Scriptes geladen und somit nur gecalled. Damit reduziert sich ein _AssembleIt(Blablub....) auf ca 1-2ms...nicht schlecht, wenn man bedenkt, nun im ASM-code AutoIt-Variablen verwenden zu können^^

  • Ich stehle hiermit mal meinen eigenen Thread und ändere das Thema leicht ab.

    Es geht jetzt um Folgendes:
    Suche (schnelle) Funktion zum umrechnen ins Dual- oder Hexadezimalsystem
    Problemstellung:
    Mein Arithmetischer Kodierer spuckt mir einen String im Dezimalsystem entgegen. Dieser String enthält je nach Input hunderte bis zehntausende Zahlen. Um diesen Spaß anständig zu speichern wird er im Dualsystem gebraucht. (Der Header der daraus entstehenden "Datei" ist im Dualsystem, da einzelne Bits entscheidend sind, die Kodierung der Wahrscheinlichkeiten ist im Dualsystem usw usw. Also muss auch der kodierte String ins Dualsystem. Dann schön alles zusammensetzen und als Binary zurückgeben)

    Wie funktioniert soetwas ?
    Der Ansatz mit den hier diskutierten Methoden läuft jedenfalls nicht, da man nicht jedes Mal die komplette endlos lange Dezimalzahl durch 2 Teilen kann. Die Subtraktionsmethode fällt ebenfalls flach, da man nicht immer mit so enormen Zahlen potenzieren kann und anschließend 2 riesige Zeichenketten voneinander abziehen kann. Die restlichen Methoden bauen darauf auf die Dezimalzahl erstmal per Hex zu verarbeiten, sodass weitere Schritte sehr einfach sind; läuft bei großen Zahlen auch nicht.

    Ich bitte daher um einen Ansatz, wie man eine große Dezimalzahl stück für Stück umwandeln kann.

    lg
    M

  • Hey, ich hab das Thread nur so halb überflogen. Ich habe das gleiche Problem. ^^
    Es wird also derzeitig nach einer schnellen Lösung gesucht um jede Dezimalzahl (in Form eines Strings) in das Dualsystem umzurechnen?

    Ich hatte bisher das hier (wobei du mir auch geholfen hast xD) um dies zu erledigen:

    Spoiler anzeigen
    [autoit]

    $s = '2'
    For $i = 1 To 12
    $s &= $s
    Next

    [/autoit] [autoit][/autoit] [autoit]

    ConsoleWrite(_DecToBin($s) & @CRLF)

    [/autoit] [autoit][/autoit] [autoit]

    Func _DecToBin($sDez)
    Local $asBin = _StringDiv22($sDez)
    Local $sBin = $asBin[1]

    [/autoit] [autoit][/autoit] [autoit]

    While $asBin[0] <> '0'
    $asBin = _StringDiv22($asBin[0])
    $sBin &= $asBin[1]
    WEnd

    [/autoit] [autoit][/autoit] [autoit]

    Return StringReverse($sBin)
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _StringDiv22($sX)
    Local $sRet = "", $iRem = StringLeft($sX, 15), $iTmp = 0, $iTrm = 6, $iLen, $aRet[2]
    $sX = StringTrimLeft($sX, 15)
    $iTmp = Floor($iRem / 2)
    $sRet &= $iTmp
    $iRem -= $iTmp * 2
    While StringLen($sX) > 0
    $iTrm = 15 - StringLen($iRem)
    $iTmp = StringLeft($sX, $iTrm)
    $iLen = StringLen($iTmp)
    $iRem &= $iTmp
    $sX = StringTrimLeft($sX, $iTrm)
    $iTmp = Int($iRem / 2)
    $iTmp = StringRight('000000000000000' & $iTmp, $iLen)
    $sRet &= $iTmp
    $iRem -= $iTmp * 2
    WEnd
    $aRet[0] = StringRegExpReplace($sRet, '^0+([^0]|0$)', '\1', 1)
    $aRet[1] = Int($iRem = 1)
    Return $aRet
    EndFunc

    [/autoit]

    Ist mir aber auch zu langsam, bei ca. 4100 Zeichen dauert es schon etwa 25 Sekunden...
    Wenn mir was Gescheites einfällt sag ich Bescheid.

  • Genauso siehts bei mir auch grade aus (@Make) :D
    Bin jetzt wieder am schnellen Rechner und dennoch gehen 300ms ins Land, bis die 510 Dezimalzahlen in 1692 Nullen und Einsen verwandelt wurden.
    Zusätzlich ist die Komplexität nicht linear. Doppelter Input gibt 4 fache Rechenzeit. Ist also absolut ungeeignet...

    Man muss irgendwie die Dezimalzahl der Reihe nach durchgehen können und immer Nullen und Einsen ausspucken mit Linearer Komplexität. Ich finde aber keinen Ansatz.

    Edit: Kann man die große Dezimalzahl eventuell als riesen Integer im RAM ablegen ?
    Das würde das Problem schon lösen :)

    lg
    M

  • Du hast mich auf eine Idee gebracht. Hätte da einen Ansatz um die Dezimalzahl tatsächlich Ziffer für Ziffer durchzugehen. Allerdings flimmert dieser Gedanke in einer Ecke meines Gehirns herum. Ich muss erst einmal ein wenig herum testen. (Mein Bauch sagt mir dass ich auf den richtigen Weg bin ^^)

    Wenn ich dann was hab lass ich es dich wissen.