1. Dashboard
  2. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team
    4. Mitgliedersuche
  3. Forenregeln
  4. Forum
    1. Unerledigte Themen
  • Anmelden
  • Registrieren
  • Suche
Alles
  • Alles
  • Artikel
  • Seiten
  • Forum
  • Erweiterte Suche
  1. AutoIt.de - Das deutschsprachige Forum.
  2. Mitglieder
  3. Mars

Beiträge von Mars

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

    • Mars
    • 26. Januar 2014 um 16:43

    Wenn ich das richtig sehe ist die Methode von Make ziemlich ähnlich.
    Habe diese mal so umgebaut, dass keine Stringoperationen mehr vorkommen (nur noch Arrays), das Redim rausgenommen, die Ubounds und Pointer vereinfacht usw. Im Endeffekt gab das aber kaum einen Tempovorteil zur Stringversion. Allerdings lässt sich die Arrayversion nahezu 1 zu 1 in ASM übersetzen.

    Skript
    [autoit]

    Global $sDec
    Global $iTimer, $iTime
    Global $iCnt = 1000
    Global $sHex

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

    For $i = 1 To $iCnt Step 1
    $sDec = _RandomDec(30)
    $iTimer = TimerInit()
    DecToBin($sDec) ; Einfach mal ohne Return. Ist ja nur zum Test
    $iTime += TimerDiff($iTimer)
    ToolTip($i & @CRLF)
    ;~ ConsoleWrite($sDec & ' -> ' & $sHex & @CRLF)
    Next
    ToolTip('')
    ConsoleWrite('Time: ' & Round(1000*$iTime/$iCnt,0) & ' µs' & @CRLF)

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

    Func _RandomDec($iLen)
    Local $sRet = ''
    For $i = 1 To $iLen Step 1
    $sRet &= Random(0, 9, 1)
    Next
    Return $sRet
    EndFunc

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

    Func DecToBin($sNumber)
    Local $aiBit[Ceiling(StringLen($sNumber)*0.41524101186092)], $product, $aDec = StringSplit($sNumber, ''), $u = 0
    For $i = 1 To $aDec[0]
    $carry = $aDec[$i]
    For $n = 0 To $u
    $product = $aiBit[$n] * 10 + $carry
    $aiBit[$n] = BitAND($product, 255)
    $carry = BitAND($product, 65280) / 256
    Next
    If $carry Then
    $u += 1
    $aiBit[$u] = $carry
    EndIf
    Next
    If UBound($aiBit) > $u Then ReDim $aiBit[$u + 1]
    Return StringReverse(StringFromASCIIArray($aiBit, 0, -1, 1))
    EndFunc

    [/autoit]


    Die Komplexität ist leider Quadratisch (schätze ich jedenfalls. ggf auch n*logn, das kann ich mit Wolfram Alpha nicht richtig fitten...
    [Blockierte Grafik: http://i.imgur.com/AkSe3vc.png]


    lg
    M

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

    • Mars
    • 24. Januar 2014 um 14:37

    Umwandlung von Hex in Bin ist "unendlich" schnell :)
    Selbst die AutoIt Version (mit LUT und Ternärem gedöns) braucht für 2 Byte nur 46µs, auf meinem Intel Atom.
    (Schätze ich mal, da 46µs im Schnitt gebraucht wurden, während die Zahlenlänge von 0 bis 31Bit erhöht wurde)
    Für 1KB = 1024 Byte sind das ca. 24ms
    In der Annahme, dass ASM ca. 500x schneller ist sind wie wieder bei unseren 46µs.
    Diese Zeit ist vernachlässigbar, wichtig ist die Umrechnung von Dec -> Base 8/16/24, was halt am besten läuft...

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

    • Mars
    • 24. Januar 2014 um 02:48

    Hab noch was schönes gefunden, und leider keinen Compiler zur Hand.
    Der Code soll in C# sein, so wie er aussieht läuft er aber auch mit C++.
    Wenn jemand das kompilieren könnte wäre ich ihm sehr verbunden, wenn die dabei entstehende Dll dann auch noch schnell ist, ist alles super :)

    Spoiler anzeigen
    Code
    //---------------------------------------------------------------------------
    AnsiString str_hex2dec(const AnsiString &hex)
        {
        char c;
        AnsiString dec="",s;
        int i,j,l,ll,cy,val;
        int  i0,i1,i2,i3,sig;
        sig=+1; l=hex.Length();
        if (l) { c=hex[l]; if (c=='h') l--; if (c=='H') l--; }
        i0=0; i1=l; i2=0; i3=l;
        for (i=1;i<=l;i++)      // scan for parts of number
            {
            char c=hex[i];
            if (c=='-') sig=-sig;
            if ((c=='.')||(c==',')) i1=i-1;
            if ((c>='0')&&(c<='9')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            if ((c>='A')&&(c<='F')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            if ((c>='a')&&(c<='f')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            }
    
    
        l=0; s=""; if (i0) for (i=i0;i<=i1;i++)
            {
            c=hex[i];
                 if ((c>='0')&&(c<='9')) c-='0';
            else if ((c>='A')&&(c<='F')) c-='A'-10;
            else if ((c>='a')&&(c<='f')) c-='A'-10;
            for (cy=c,j=1;j<=l;j++)
                {
                val=(s[j]<<4)+cy;
                s[j]=val%10;
                cy  =val/10;
                }
            while (cy>0)
                {
                l++;
                s+=char(cy%10);
                cy/=10;
                }
            }
        if (s!="")
            {
            for (j=1;j<=l;j++) { c=s[j]; if (c<10) c+='0'; else c+='A'-10; s[j]=c; }
            for (i=l,j=1;j<i;j++,i--) { c=s[i]; s[i]=s[j]; s[j]=c; }
            dec+=s;
            }
        if (dec=="") dec="0";
        if (sig<0) dec="-"+dec;
    
    
        if (i2)
            {
            dec+='.';
            s=hex.SubString(i2,i3-i2+1);
            l=s.Length();
            for (i=1;i<=l;i++)
                {
                c=s[i];
                     if ((c>='0')&&(c<='9')) c-='0';
                else if ((c>='A')&&(c<='F')) c-='A'-10;
                else if ((c>='a')&&(c<='f')) c-='A'-10;
                s[i]=c;
                }
            ll=((l*1234)>>10);  // num of decimals to compute
            for (cy=0,i=1;i<=ll;i++)
                {
                for (cy=0,j=l;j>=1;j--)
                    {
                    val=s[j];
                    val*=10;
                    val+=cy;
                    s[j]=val&15;
                    cy=val>>4;
                    }
                dec+=char(cy+'0');
                for (;;)
                    {
                    if (!l) break;;
                    if (s[l]) break;
                    l--;
                    }
                if (!l) break;;
                }
            }
    
    
        return dec;
        }
    //---------------------------------------------------------------------------
    AnsiString str_dec2hex(AnsiString dec)
        {
        AnsiString hex=""; BYTE a,b;
        int  i,j,i0,i1,i2,i3,l,sig;
        sig=+1; l=dec.Length();
        i0=0; i1=l; i2=0; i3=l;
        for (i=1;i<=l;i++)      // scan for parts of number
            {
            char c=dec[i];
            if (c=='-') sig=-sig;
            if ((c=='.')||(c==',')) i1=i-1;
            if ((c>='0')&&(c<='9')) { if (!i0) i0=i; if ((!i2)&&(i>i1)) i2=i; }
            }
        if (i0) for (;i1>=i0;i1=j-1)// process integer part /16
            {
            for (a=0,j=i0,i=i0;i<=i1;i++)
                {
                a*=10; a+=dec[i]-'0';
                if (a<16) { if (j>i0){ dec[j]='0'; j++; } continue; }
                b=a>>4; a=a&15;
                if (b>10) { dec[j]='1'; j++; b-=10; }
                dec[j]=b+'0'; j++;
                }
            if ((!a)&&(hex=="")) continue;
            if (a<10) a+='0'; else a+='A'-10;
            hex=AnsiString(char(a))+hex;
            }
        if (hex=="") hex="0";
    
    
        if ((i2)&&(i2<=i3))     // process fractional part *16
         for (hex+=".",j=i3-i2+2;j;j--)
            {
            for (a=0,b=0,i=i3;i>=i2;i--)
                {
                a=dec[i]-'0';
                b+=a<<4; dec[i]=(b%10)+'0'; b/=10;
                }
            if (b<10) b+='0'; else b+='A'-10;
            hex+=char(b);
            }
        if (sig<0) hex="-"+hex; hex+="h";
        return hex;
        }
    //---------------------------------------------------------------------------
    Alles anzeigen

    Edit: So wie da mit der for Schleife umgesprungen wird... der Urheber muss Spanier sein...
    @Make:
    Irgendwie läuft das für große Zahlen aber immernoch nicht.
    Die ganze Aufspalterei macht ja nur Sinn, wenn man damit beliebig große Zahlen verarbeiten kann.
    Leider finde ich den Fehler nicht :/

    lg
    M

  • Make-Grafik's Encryption Tool

    • Mars
    • 23. Januar 2014 um 21:32

    Du hast zu wenig Fantasie ;)
    Also die Abhandlung ist komplett als Binary Datentyp, damit es keine Probleme mit nicht anzeigbaren Zeichen, oder Chr(0) en gibt. (AutoIt spinnt da manchmal etwas, aber als Binarys kann man so ziemlich alles abhandeln).

    Die folgende Crypt Funktion kann daher nur mit Binarys benutzt werden. Um das Casten (StringToBinary und anderstherum muss sich der User kümmern, eine DAU Programmierung ist mir jetzt zu anstrengend).

    Im Beispiel wird ein String mit dem Passwort "0" Verschlüsselt.

    Spoiler anzeigen
    [autoit]

    #include <Crypt.au3>

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

    Global $sText = 'Hallo ich bin ein Passwort geschützter Text'; String !
    Global $sPW = '0' ; String !
    Global $bText = StringToBinary($sText)
    Global $bPW = StringToBinary($sPW)
    Global $bEncrypted = _XORCrypt($bText, $bPW) ; Ausgabe/$sText/$sPW - Hex
    Global $bDecrypted = _XORCrypt($bEncrypted, $bPW) ; Ausgabe/$sText/$sPW - Hex
    Global $sDecrypted = BinaryToString($bDecrypted) ; String

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

    ConsoleWrite('Text: ' & $sText & @CRLF & 'Text(bin): ' & $bText & @CRLF & 'Encrypt: ' & $bEncrypted & @CRLF & 'Decrypt: ' & $sDecrypted & @CRLF)

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

    Func _XORCrypt($sText, $sPW)
    Local $sHash = _StringHash($sPW, BinaryLen($sText)), $sRet = '0x'
    For $i = 3 To StringLen($sText) Step 2
    $sRet &= Hex(Int(BitXOR('0x' & StringMid($sText, $i, 2), '0x' & StringMid($sHash, $i, 2))), 2)
    Next
    Return Binary($sRet)
    EndFunc

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

    Func _StringHash($sStr, $iLen)
    _Crypt_Startup() ; Eine Runde MD5 gibt einen 16 Byte Hash
    Local $sRet = StringTrimLeft(_Crypt_HashData($sStr, $CALG_MD5), 2), $sRnd
    While StringLen($sRet) < $iLen * 2
    $sRet &= StringTrimLeft(_Crypt_HashData(BinaryToString('0x' & $sRet) & $sStr, $CALG_MD5), 2)
    WEnd ; Ab hier haben wir genug Zahlen. Jetzt müssen wir nur noch etwas durchmischen
    While $sRet
    $sRnd &= StringLeft($sRet, 1) & StringRight($sRet, 1)
    $sRet = StringTrimLeft(StringTrimRight($sRet, 1), 1)
    WEnd ; Nun nochmal, weil es so schön war, in 16Byte Schritten Hashen
    While $sRnd
    $sRet &= StringTrimLeft(_Crypt_HashData(BinaryToString('0x' & StringLeft($sRnd, 32)), $CALG_MD5), 2)
    $sRnd = StringTrimLeft($sRnd, 32)
    WEnd ; Fertig. Der entstandene String sollte relativ zufällig aussehen
    _Crypt_Shutdown()
    Return Binary('0x' & StringLeft($sRet, $iLen * 2))
    EndFunc

    [/autoit]

    Im Prinzip gaukelt man hier ein One Time Pad vor, indem man einen großen "zufälligen" String zum XORen benutzt. Von außen (nach der Verschlüsselung) sollte man das nicht mehr so leicht erkennen. Wenn man das Verfahren kennt kann man natürlich mittels BF ran. Und hier gilt die schon 1000x angesprochene Regel für die Laufzeit eines PW knackers.

  • Make-Grafik's Encryption Tool

    • Mars
    • 23. Januar 2014 um 14:58

    Hab eine kleine Funktion geschrieben, die aus einem kurzen PW einen pseudozufälligen String erzeugt.
    Verwendet wird folgendes:
    1. Solange Hashwerte erzeugen, bis die Ziellänge überschritten ist.
    2. Da nur der erste Hashwert Bezug zum PW besitzt, und alle anderen daraus abgeleitet sind, ist das Verfahren eventuell nicht so schön. Daher wird hier nochmal zeichenweise vermischt.
    3. Zu guter letzt wird der gemischte String in 16er Ketten nochmals gehasht. Der Hash ersetzt dann die Kette.

    Das was rauskommt ist nach einer kurzen Häufigkeitsanalyse nicht wirklich gleichverteilt, aber 100.000x besser als die Hintereinanderreihung des eigentlichen Passworts.
    Es sollte bedacht werden, dass der Output im Hex Format ist. (falls jemand die Funktion nutzen will)

    Spoiler anzeigen
    [autoit]


    #include <Crypt.au3>
    #include <Array.au3>

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

    ; 5KB langer Hash
    Global $sHash = _Hash('Passwort', 1024 * 5)
    ConsoleWrite($sHash & @CRLF)
    Global $a = _ArrayCountAbs($sHash)
    _ArrayDisplay($a)

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

    ; $sStr = Beliebiger String
    ; $iLen = Länge des Outputs in Byte
    Func _Hash($sStr, $iLen)
    _Crypt_Startup() ; Eine Runde MD5 gibt einen 16 Byte Hash
    Local $sRet = StringTrimLeft(_Crypt_HashData($sStr, $CALG_MD5), 2), $sRnd
    While StringLen($sRet) < $iLen * 2
    $sRet &= StringTrimLeft(_Crypt_HashData(BinaryToString('0x' & $sRet), $CALG_MD5), 2)
    WEnd ; Ab hier haben wir genug Zahlen. Jetzt müssen wir nur noch etwas durchmischen
    ;~ ConsoleWrite('Step 1: ' & $sRet & @CRLF)
    While $sRet
    $sRnd &= StringLeft($sRet, 1) & StringRight($sRet, 1)
    $sRet = StringTrimLeft(StringTrimRight($sRet, 1), 1)
    WEnd ; Nun nochmal, weil es so schön war, in 16Byte Schritten Hashen
    ;~ ConsoleWrite('Step 2: ' & $sRnd & @CRLF)
    While $sRnd
    $sRet &= StringTrimLeft(_Crypt_HashData(BinaryToString('0x' & StringLeft($sRnd, 32)), $CALG_MD5), 2)
    $sRnd = StringTrimLeft($sRnd, 32)
    WEnd ; Fertig. Der entstandene String sollte relativ zufällig aussehen
    ;~ ConsoleWrite('Step 3: ' & $sRet & @CRLF)
    _Crypt_Shutdown()
    Return StringLeft($sRet, $iLen * 2)
    EndFunc

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

    Func _ArrayCountAbs($a, $l = 1, $b = 0)
    If Not IsArray($a) Then Return _
    _ArrayCountAbs(_StringSplit($a, $l, $b))
    Local $u = UBound($a), $r[$u][2], _
    $c = __ArrayUnique($a)
    For $i = 0 To UBound($c) - 1 Step 1
    $r[$i][0] = $c[$i]
    For $e = 0 To $u - 1 Step 1
    If $a[$e] == $c[$i] Then $r[$i][1] += 1
    Next
    Next
    _ArraySort($r, 1, 0, 0, 1)
    ReDim $r[UBound($c)][2]
    Return $r
    EndFunc

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

    Func __ArrayUnique(Const ByRef $a)
    If UBound($a,0)>1 Then Return _ArrayUnique($a,1,0,1)
    Local $oD = ObjCreate('Scripting.Dictionary')
    $oD.CompareMode = 0
    For $i = 0 To UBound($a) - 1
    $oD.Item($a[$i])
    Next
    Return $oD.Keys()
    EndFunc

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

    Func _StringSplit($s, $l = 1, $b = 0)
    If $b Then Return _StringSplit(StringTrimLeft _
    (Binary($s), 2), $l * 2)
    If $l <= 1 Then Return StringSplit($s, '', 2)
    Local $c = Ceiling(StringLen($s) / $l), $a[$c]
    For $i = 0 To $c - 1 Step 1
    $a[$i] = StringMid($s, $i * $l + 1, $l)
    Next
    Return $a
    EndFunc

    [/autoit]
  • Make-Grafik's Encryption Tool

    • Mars
    • 23. Januar 2014 um 13:13

    Lesen bildet:
    - Das PW muss absolut zufällig sein, damit 100%ige Sicherheit erreicht wird.
    - Wenn man das PW immer hintereinander setzt kann man es extrem leicht herausbekommen
    - Man darf für 100%ige sicherheit das PW niemals für mehr als eine Nachricht verwenden. (einfach mal One Time Pad googeln)

    Wenn man den Hash des PW zum Verschlüsseln nutzt (und sich einen Algorithmus baut der aus dem PW einen Hash der Länge der Nachricht machen kann), so hat man eine nicht mehr erratbare Verschlüsselung. In diesem Fall muss Brute Force angewendet werden. (Annahme: Gehashte Daten sind optimal zufallsverteilt).
    Für Brute Force gilt immer die Regel (wie oben bereits erwähnt): Sicherheit in Bit = LängePW * log(ZeichenSatz) / Log(2)

    lg
    M

  • Make-Grafik's Encryption Tool

    • Mars
    • 22. Januar 2014 um 18:50

    Die Xor Verschlüsselung ist bei kurzen Passwörtern nur so sicher, wie das Passwort lang ist. Bei einem 5 Stelligen PW also 5*log(n)/log(2) Bit. (n = Anzahl zugelassener Zeichen)
    Nimmt man z.B. nur Zahlen hat man 5*log(10)/log(2) = 16,6 Bit. Das ist nicht sonderlich sicher.

    Ein Spezialfall dieser Methode ist das One Time Pad. Der Schlüssel muss sowohl vollkommen zufällig, als auch gleichlang wie die Eingabe sein. Dieses Verfahren ist nachweislich nicht entschlüsselbar.

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

    • Mars
    • 20. Januar 2014 um 18:23

    Make hat schon eine Funktion in Basic gefunden die scheinbar keine n² Komplexität besitzt.
    Es kann natürlich auch eine DLL sein.

    Das Problem ist dabei, dass man ja normalerweise immer die komplette Zahl durch 2 Teilen muss. Bei großen Strings braucht man dann die BugNum UDF (die ja ansich ziemlich flott ist), da man aber für jede 0 oder 1 eine Division durch 2 braucht ist das trotzdem schnarchlangsam...

    hier ist mal der Code von Make:

    Spoiler anzeigen
    Code
    Constructor bigint (ByRef a As String)
            Dim As Integer p, i, j, ch, blocks, sign
            If InStr(a, "-") <> 0 Then sign = -1
            '------------------------------------------------------------
            ' extract numerics from input string
            j = 0   '  in-place write pointer
            For i = 0 To Len(a) - 1
                ch = a[i]
                If (ch >= Asc("0")) And (ch <= Asc("9")) Then
                    a[j] = ch
                    j += 1
                End If
            Next i
            a = Left(a, j)  ' j is one ahead from string index = length of a
            '------------------------------------------------------------
            ' extend to next multiple of 9 digits
            i = Len(a)
            blocks = Int(0.99 + i / 9)  ' number of 9 digit blocks needed
            p = 9 * blocks
            a = String(p - i, "0") + a  ' pad to next multiple of 9 digits
            '------------------------------------------------------------
            ' decimal to binary conversion
            i = ( 8 + Len(a) * 3.32192809488) \ 8   ' bytes needed for binary
            blocks = 1 + (i \ 4)                    ' adjust to multiple of 4
            this.s = String(blocks * 4, Chr(0) ) ' binary destination string
            '------------------------------------------------------------
            Dim As UInteger<32> Ptr bp, bpz, bpcarry, bpdata
            bpz = Cast(UInteger<32> Ptr, StrPtr(this.s)) ' binary output string[0]
            Dim As ULongInt product, carry, multiplier = 1e9
            bpdata = Cast(UInteger<32> Ptr, @product) ' bottom half of product
            bpcarry = bpdata + 1                ' top half of product
            '------------------------------------------------------------
            blocks = 1  ' blocks will be advanced as required by carry
            For i = 1 To Len(a)-8 Step 9   ' msd to lsd in blocks of 9
                bp = bpz    ' point back to the start
                carry = ValULng(Mid(a, i, 9))  ' take the next 9 digit block
                For j = 1 To blocks
                    product = CLngInt(*bp) * multiplier + carry
                    *bp = CUInt<32>(*bpdata)
                    carry = CULngInt(*bpcarry)
                    bp += 1
                Next j
                ' advancing blocks only as needed doubles the speed of conversion
                If Carry Then
                    *bp = carry
                    blocks += 1 ' an exact count of the blocks used
                End If
            Next i
            this.s = Left(this.s, blocks * 4) ' keep only used blocks
            '-------------------------------------------------------------
            If this.s[Len(this.s)-1] And 128 Then this.s = this.s + bigint_0.s ' MSB must be 0
            If sign Then This = bigint_negate(This)
        End Constructor
    Alles anzeigen

    Und hier eine Version mit BigNum UDF

    Spoiler anzeigen
    [autoit]

    #include <BigNum.au3>
    #include <Array.au3>

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

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

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

    _DecToBin_Startup()

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

    Global $x = '123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890', $t
    $t = TimerInit()
    Global $b = _Big_DecToBin($x)
    $t = TimerDiff($t)

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

    ConsoleWrite('Time: ' & Round($t, 2) & ' ms' & @CRLF & $b & @CRLF)

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

    Func _Big_DecToBin($sDec)
    Local $iLen = StringLen($sDec), $aBlocks[Ceiling(Log(10)/Log(2)*$iLen/8)]
    Local $sTmp = $sDec, $i = 0, $sRet
    While Not ($sTmp = '0')
    $sRet = StringRight('00000000' & _DecToBin(_BigNum_Div256($sTmp)), 8) & $sRet
    $i += 1
    WEnd
    While StringLeft($sRet, 1) = '0'
    $sRet = StringTrimLeft($sRet, 1)
    WEnd
    Return $sRet
    EndFunc

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

    Func _BigNum_Div256(ByRef $sX) ; Input: sX, Output: Modulo, sX /= 256
    Local $sM = "0"
    Local $bRed = False
    Local $sRet = "", $sRem = StringLeft($sX, 3), $sTmp = "", $sTm2 = "", $iCnt, $iLen = 1
    $sX = StringTrimLeft($sX, 3)
    Do
    If __BigNum_DivComp($sRem, 256) = -1 Then
    $sTmp = StringLeft($sX, 1)
    $sRem &= $sTmp
    $sX = StringTrimLeft($sX, 1)
    If StringLen($sTmp) > 0 Then $iLen += 1
    EndIf
    $sTmp = 256
    $sTm2 = "0"
    If __BigNum_DivComp($sRem, 256) >= 0 Then
    For $iCnt = 1 To 9
    $sTm2 = $sTmp
    $sTmp = __BigNum_DivAdd($sTmp, 256)
    If __BigNum_DivComp($sRem, $sTmp) < 0 Then ExitLoop
    Next
    Else
    $iCnt = 0
    EndIf
    If StringLen($sX) = 0 Then $bRed = True
    $sM = $sRem
    $sRem = __BigNum_DivSub($sRem, $sTm2)
    If $iCnt > 0 Then $sM = $sRem
    $sRet &= StringFormat("%0" & String($iLen) & "u", $iCnt)
    $iTrm = 3 - StringLen($sRem)
    $sTmp = StringLeft($sX, $iTrm)
    $sX = StringTrimLeft($sX, $iTrm)
    $iLen = StringLen($sTmp)
    $sRem &= $sTmp
    Until $bRed
    $sX = StringRegExpReplace($sRet, "^0+([^0]|0$)", "\1", 1)
    Return StringRegExpReplace($sM, "^0+([^0]|0$)", "\1", 1)
    EndFunc ;==>__BigNum_Div_DivisorGreater14

    [/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]


    Edit: Er wird natürlich auch eine BigBin -> BigDec benötigt

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

    • Mars
    • 20. Januar 2014 um 01:44

    Läuft wirklich flott. Ein Ranking gibts Morgen, erstmal muss dieser Stringkram aus meinem Kopf.
    Irgendwie glaube ich, dass du dich damit auf Platz 1 Rangierst. Dann gibts nur noch Dll Overhead vs Array Overhead :D

    Zum Langen Dec String:
    Habe eine selbstverständlich unzufriedenstellende (aber extrem schnelle) Lösung gefunden.
    Der Dezimalstring wird einfach in 3er Ketten gespalten und dann umgewandelt.
    ddd -> 10 Bit (da 999 < 1024 geht das in jedem Fall).
    Allerdings werden dabei 0.34% + x der Bitlänge verbraten. (da die Werte 1000-1023 niemals genutzt werden).
    Jetzt stellt sich die Frage: Ist man mit einer falschen, aber schnellen Rechnung zufrieden ? (Die angehängten Nullen kann man durch eine Längenangabe wieder rausschmeißen)

    Skript
    [autoit]

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

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

    _DecToBin_Startup()

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

    Global $DEC = '234950770365524664314635516700700126668787223320782810776196842343923622379715841889813674902718039418167617401497873060561000272'

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

    Global $BIN = __MComp_DecToBin($DEC)
    Global $x = __MComp_BinToDec($BIN)

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

    ConsoleWrite('Original: ' & $DEC & @CRLF & 'Binär: ' & $BIN & @CRLF & 'Zurück: ' & $x & @CRLF & 'Verlust: ' & StringLen($BIN) - Int(StringLen($DEC)*Log(10)/Log(2)) & ' Bit (Anzahl unnötig verbrauchter Bits)' & @CRLF)

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

    ; nicht Optimal !
    ; Ersetzen von ddd -> 10 Bit (Verlust: 0.34%)
    ; Am Ende ggf bis zu 7 Bit Verlust !
    Func __MComp_DecToBin($sDec)
    While Not IsInt(StringLen($sDec)/3)
    $sDec &= 0
    WEnd
    Local $sRet
    For $i = 1 To StringLen($sDec) Step 3
    $sRet &= StringRight('0000000000' & _DecToBin(StringMid($sDec, $i, 3)), 10)
    Next
    Return $sRet
    EndFunc

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

    Func __MComp_BinToDec($sBin)
    Local $sRet
    For $i = 1 To StringLen($sBin) Step 10
    $sRet &= StringRight('000' & _BinToDec(StringMid($sBin, $i, 10)), 3)
    Next
    Return $sRet
    EndFunc

    [/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]
  • Suche (schnelle) Funktion zum Umrechnen ins Dual- oder Hexadezimalsystem

    • Mars
    • 19. Januar 2014 um 23:56

    Ich dachte an sowas:

    [autoit]

    Local $t = DllStructCreate('int64')
    DllStructSetData($t, 1, 1234567890123456789)
    Local $p = DllStructCreate('byte a[8]', DllStructGetPtr($t)), $s
    For $i = 9 To 1 Step -1
    $s &= Hex($p.a(($i)),2)
    Next
    ConsoleWrite($s & @CRLF)
    $s = StringRegExpReplace($s, "^0+([^0]|0$)", "\1", 1)
    ConsoleWrite(Int('0x' & $s) & @CRLF)

    [/autoit]


    Man kann per Struct den Kram schön ins Hexformat bringen (was ja dem Dualsystem nur noch ein Katzensprung entfernt ist).
    Man müsste nur die komplette Dezimalzahl da reinstecken können...

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

    • Mars
    • 19. Januar 2014 um 22:41

    Probiere ich auch grade.
    Bin an folgendem Gescheitert:

    Beispiel:
    Zahl = 10
    Binärdarstellung = 1010
    Zahl 11 -> 1011
    Zahl 12 -> 1100
    Die 2te Zahl kann bis auf die erste Stelle noch alle anderen Werte verändern, da hilft auch der Teilerrest der ersten nicht.

    auch doof ist, dass es keinen ggt gibt.
    z.B kann man sagen 4 Bin -> 1 Hex.
    Für Dezimalzahlen gilt das aber leider nicht. Es gibt keine 2^n Zahl die auf 0 endet, man kann den großen String also nicht in kleine Teile zerlegen und diese einzeln behandeln...

    Edit:
    Allerdings können die Ergebnisse der ersten Zahl die weiter hinten gelegenen nicht mehr beeinflussen. Dafür werden sie von den Überschlagen der vorherigen Zahlen beeinflusst...

    Edit2: http://www.php.net/manual/en/function.base-convert.php
    Mal schauen ob das was hilft. Da wird jedenfalls mit Strings hantiert.

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

    • Mars
    • 19. Januar 2014 um 22:08

    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

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

    • Mars
    • 19. Januar 2014 um 20:39

    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

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

    • Mars
    • 19. Januar 2014 um 14:40

    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

  • Arithmetisches Kodieren

    • Mars
    • 19. Januar 2014 um 12:27

    Der Trick scheint zu sein, dass der Dekodierer immer die gleichen Zustände durchläuft wie der Kodierer. Man kann also beliebig große Fehler machen, solange sie der Dekodierer ebenfalls macht.

    Zum Komprimieren, sowie zum Dekomprimieren ist die Zeichenliste mit den Wahrscheinlichkeiten nötig. Wenn ich diese Liste auf z.B. 8 Bit runde und mit ihr Kodiere, so reicht es auch dem Dekodierer aus eine 8 Bit Wahrscheinlichkeit zu kennen. Die Kompressionsqualität hängt von der Genauigkeit der Schranken und Wahrscheinlichkeiten ab. Hab aber bisher selbst beim Runden auf 3 Stellen keine Verlängerung des Output feststellen können.

    lg
    M

  • Arithmetisches Kodieren

    • Mars
    • 19. Januar 2014 um 00:22

    Moin,

    Wer bei mir eine lange Geschichte (Beginnt bei Adam und Eva) gewöhnt ist, der darf in den (verschachtelten) Archivierten Inhalt schauen und sich sattlesen :D

    Zu sagen bleibt:
    Das Skript wurde in den letzten Tagen mehrfach verändert, es benutzt jetzt nativ Hexadezimalzahlen (also wird keine Aufwendige Umrechnung mehr gebraucht) und ist allgemein aufgeräumter. Alle Änderungen stehen im Skript im oberen Abschnitt. So ganz einfach lässt es sich leider immernoch nicht verwenden, weil ich bisher keine "schöne" Methode gefunden habe den kodierten Daten unsere Wahrscheinlichkeitstabelle mitzugeben. (selbstverständlich lässt sich das sehr leicht machen, aber es soll ja auch möglichst wenig Platz verbrauchen, darüber denke ich aktuell noch nach :huh: ) Und es gilt wie üblich: Eine Entropiekodierung ist der LETZTE Schritt einer ernsthaften Kompression, nicht der Erste ;)

    Die Auswirkungen verschiedener Bitraten auf verschiedene Texte kann man in Zeile 79 und 80 ausprobieren.

    Arithmetische Kodierung
    [autoit]


    ;~ #include <Array.au3>

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

    ; |------------------------------------------------------------------------------|
    ; Skript : Entropiekodierung via Arithmetischer Kodierung
    ; Autor : Mars (AutoIt.de)
    ; AutoIt : Läuft mit [3.3.10.2] keine Gewähr für frühere oder spätere Versionen
    ; Version : 0.13
    ; Changes : 0.01 - Erzeugung von Tables
    ; 0.02 - Kodieren (dezimal)
    ; 0.03 - Dekodieren (dezimal)
    ; 0.04 - Anständige Formatierung (so halbwegs...)
    ; 0.10 - Kodieren im Hexadezimalsystem
    ; 0.11 - Rotierendes Alphabet
    ; 0.12 - Rewrite einiger Funktionen, Bugfixes, 2D-Tables eingeführt
    ; 0.13 - Dekodieren im Hexadezimalsystem
    ; Issues : 0.13 - Es treten in manchen Fällen "Missverständnisse" bei den letzten
    ; kodierten Zeichen eines Strings im Dekodierer auf. Um dieses Problem
    ; zu umgehen wurde 1Hexzeichen zusätzlich angehängt (obwohl das
    ; theoretisch unnötig sein müsste). Ob das Problem damit erfolgreich
    ; umgangen wurde kann zum jetzigen Zeitpunkt nicht gesagt werden.
    ; |------------------------------------------------------------------------------|

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

    ; |--------------------------------Funktionsweise--------------------------------|
    ; # Siehe Wikipedia
    ; - http://de.wikipedia.org/wiki/Arithmetisches_Kodieren
    ; |------------------------------------------------------------------------------|

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

    ; |----------------------------------Änderungen----------------------------------|
    ; # Funktioniert Hexadezimal
    ; - Keine Umrechnung von Dec in Hex nötig !
    ; - Diese Rechnung war für große Zahlen aufwändiger als befürchtet...
    ; # Rotierendes Alphabet
    ; - Das Intervall kann sich nicht mehr "festfressen"
    ; - z.B. 0.2000 und 0.1999, wenn letzteres immer weiter erhöht
    ; - wird erreicht die Signifikante Ziffer trotzdem nie 2
    ; # Einstellbare Bitrate
    ; - Die Wahrscheinlichkeit für jedes Zeichen muss exakt sein um das
    ; - bestmögliche Ergebnis zu erzielen. In der Realität verbraucht
    ; - die Wahrscheinlichkeitstabelle die den kodierten Daten hinzugefügt
    ; - werden muss einiges an Platz. Daher kann den Wahrscheinlichkeiten
    ; - eine Bitrate zugeteilt werden. Das Ergebnis wird somit besser.
    ; - Kleine Datenmengen profitieren von der kleinen Tabelle, und
    ; - für große Datenmengen reicht die Genauigkeit von 16 Bit aus um
    ; - ohne Kompressionsverluste zu arbeiten.
    ; |------------------------------------------------------------------------------|

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

    ; Gewöhnlicher Text (selbst verfasst, und daher frei von jeglichen Copyrights)
    Global $sText1 = _
    'Hallo, ich will komprimiert werden. Das gefällt ' & _
    'mir sehr gut. Sehr Schön, Ciao ! Sowas könnte ic' & _
    'h den ganzen lieben langen Tag machen. Da wird j' & _
    'a der Hund in der Pfanne Verrückt. Sowas lasse i' & _
    'ch nicht einfach durchgehen, ihr Banausen ! Da g' & _
    'eht mir die Hutschnur wenn ich sowas sehe, das i' & _
    'st ja nicht zum Aushalten ! Bei sowas könnte ich' & _
    ' mich grad vergessen. Das geht überhaupt nicht !' & _
    ' Wenn ich du wäre, würde ich mich was schämen :)'

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

    ; Einfach zu komprimierende Daten
    Global $sText2 = _
    '123456789012345678912345678123456712345612345123' & _
    '412312100000000000000000000000000000000000000000' & _
    '000000000000000000000000000000000000000000000000' & _
    '000000000000000000000000000000000000000000000000' & _
    'Das ist schön :)'

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

    ; Ein einziges sich wiederholendes Zeichen mit einem Fremdzeichen
    Global $sText3 = _
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' & _
    'aaaaaaaaaaaaoaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' & _
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' & _
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' & _
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' & _
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' & _
    'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'

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

    ; Zum Ausprobieren bitte hier herumspielen:
    Global $sText = $sText2
    Global $nBitRate = 7
    ; Zum Ausprobieren bitte hier herumspielen:

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

    Global $iAnz = 0
    Global $sComp = '', $sDecomp = ''
    ConsoleWrite(@CRLF & '-------------------------------------------------------------' & @CRLF)
    $iAnz = UBound(_MComp_StringCountChars($sText))
    ConsoleWrite('String -> (' & $iAnz & ')' & @CRLF & '> ' & $sText & @CRLF & 'Len: ' & StringLen($sText) & ' Byte' & @CRLF & 'Größe (gleichmäßig kodiert): ' & _MComp_StringGetInformationContent($sText) & ' Byte' & @CRLF & @CRLF)

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

    $sComp = _MComp_StringEncode($sText, $nBitRate)

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

    $iAnz = UBound(_MComp_StringCountChars($sComp))
    ConsoleWrite('Encode -> (' & $iAnz & ')' & @CRLF & '> ' & $sComp & @CRLF & 'Len: ' & StringLen($sComp) & ' Hex' & @CRLF & 'Größe (dynamisch kodiert): ' & _MComp_StringGetInformationContent($sComp) & ' Byte ( ' & Round(_MComp_StringGetInformationContent($sComp) / StringLen($sText), 4) * 100 & ' % )' & @CRLF & @CRLF)

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

    $sDecomp = _MComp_StringDecode($sComp, _MComp_StringCreateTable($sText, $nBitRate), StringLen($sText))

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

    $iAnz = UBound(_MComp_StringCountChars($sDecomp))
    ConsoleWrite('Decode -> (' & $iAnz & ')' & @CRLF & '> ' & $sDecomp & @CRLF & 'Len: ' & StringLen($sDecomp) & ' Byte' & @CRLF & 'Größe (gleichmäßig kodiert): ' & _MComp_StringGetInformationContent($sDecomp) & ' Byte' & @CRLF & @CRLF)

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

    If $sText == $sDecomp Then
    ConsoleWrite('+ Erfolg !' & @CRLF)
    Else
    ConsoleWrite('! ERROR !!!' & @CRLF)
    EndIf
    ConsoleWrite('-------------------------------------------------------------' & @CRLF)

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Aus einer Entropiekodierung ermittelter String
    ; | VORSICHT, der String der Encode Funktion reicht nicht zum dekodieren aus.
    ; | Es wird zusätzlich ein Table in gültiger Bitrate, sowie die Länge benötigt !
    ; |------------------------------------------------------------------------------|
    Func _MComp_StringDecode($sString, $aTable, $iLen)
    Local $aInterval[2] = [0, 0xFFFFFFF], $aIntNew, $sRet, $iTmp, $iHexLeft, $iHexRight, $iHexMid
    While $iLen
    $iTmp = Int('0x' & StringLeft($sString & '0000000', 7))
    $aIntNew = _MComp_IntervalCalcNew($aInterval, $aTable, $iLen > 1)
    For $e = 0 To UBound($aIntNew) - 1 Step 1
    If $iTmp < Int($aIntNew[$e][1]) Then ExitLoop
    Next
    ;~ _ArrayDisplay($aIntNew, _MComp_HexToString(Hex($aIntNew[$e][0], 2)))
    $sRet &= Hex($aIntNew[$e][0], 2)
    $iLen -= 1
    $aInterval[1] = Int($aIntNew[$e][1])
    If Not $e = 0 Then $aInterval[0] = Int($aIntNew[$e - 1][1])
    $iHexLeft = Hex(Int($aInterval[0]), 7)
    $iHexRight = Hex(Int($aInterval[1]), 7)
    $iHexMid = Hex(Int($iTmp), 7)
    ;~ ConsoleWrite($iHexLeft & '|' & $iHexMid & '|' & $iHexRight & @CRLF)
    While StringLeft($iHexLeft, 1) = StringLeft($iHexRight, 1) And StringLeft($iHexLeft, 1) = StringLeft($iHexMid, 1)
    $iTmp = StringLeft($iHexLeft, 1)
    $sString = StringTrimLeft($sString, 1)
    $aInterval[0] = ($aInterval[0] - ('0x' & $iTmp & StringLeft('0000000', StringLen($iHexLeft) - 1))) * 16
    $aInterval[1] = ($aInterval[1] - ('0x' & $iTmp & StringLeft('0000000', StringLen($iHexLeft) - 1))) * 16
    $iHexMid = StringLeft($sString, 7)
    $iHexLeft = Hex(Int($aInterval[0]), 7)
    $iHexRight = Hex(Int($aInterval[1]), 7)
    WEnd
    WEnd
    Return _MComp_HexToString($sRet)
    EndFunc ;==>_MComp_StringDecode

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

    ; |------------------------------------------------------------------------------|
    ; | Return: EntropieKodierung des Strings als Hexadezimalstring ohne führendes '0x'
    ; | Opt : Die Wahrscheinlichkeitsbitrate ist zwischen 1 und 16 frei wählbar
    ; | VORSICHT, die Rückgabe enthält ausschließlich den kodierten String, zur
    ; | Dekodierung wird weiterhin der gültige Table, sowie die Stringlänge benötogt
    ; |------------------------------------------------------------------------------|
    Func _MComp_StringEncode($sString, $iBitrate = 0)
    Local $aTable = _MComp_StringCreateTable($sString, $iBitrate), $sBin = _MComp_StringToHex($sString)
    Local $aInterval = [0, 0xFFFFFFF], $sRet, $iChar, $aIntNew, $iTmp, $iHexLeft, $iHexRight
    For $i = 1 To StringLen($sBin) Step 2
    $iChar = Int('0x' & StringMid($sBin, $i, 2))
    $aIntNew = _MComp_IntervalCalcNew($aInterval, $aTable)
    For $e = 0 To UBound($aIntNew) - 1 Step 1
    If $aIntNew[$e][0] = $iChar Then ExitLoop
    Next
    $aInterval[1] = Int($aIntNew[$e][1])
    If Not $e = 0 Then $aInterval[0] = Int($aIntNew[$e - 1][1])
    $iHexLeft = Hex(Int($aInterval[0]), 7)
    $iHexRight = Hex(Int($aInterval[1]), 7)
    ;~ ConsoleWrite($iHexLeft & '|' & 0 & '|' & $iHexRight & @CRLF)
    While StringLeft($iHexLeft, 1) = StringLeft($iHexRight, 1)
    $iTmp = StringLeft($iHexLeft, 1)
    $sRet &= $iTmp
    $aInterval[0] = ($aInterval[0] - ('0x' & $iTmp & StringLeft('0000000', StringLen($iHexLeft) - 1))) * 16
    $aInterval[1] = ($aInterval[1] - ('0x' & $iTmp & StringLeft('0000000', StringLen($iHexLeft) - 1))) * 16
    $iHexLeft = Hex(Int($aInterval[0]), 7)
    $iHexRight = Hex(Int($aInterval[1]), 7)
    WEnd
    Next
    $iHexLeft = Hex(Int($aInterval[0]), 7)
    $iHexRight = Hex(Int($aInterval[1]), 7)
    Return $sRet & Hex(Int(Round((Int('0x' & StringLeft($iHexLeft, 1)) + Int('0x' & StringLeft($iHexRight, 1))) / 2, 0)), 1)
    EndFunc ;==>_MComp_StringEncode

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

    ; |------------------------------------------------------------------------------|
    ; | Return: 1D-Table mit Wahrscheinlichkeiten zwischen 0 und 2^n-1
    ; | ByRef : 1D-Table mit Wahrscheinlichkeiten zwischen 0 und 1
    ; | Opt : Die Wahrscheinlichkeitsbitrate ist zwischen 1 und 16 frei wählbar
    ; |------------------------------------------------------------------------------|
    Func _MComp_TableCompress(ByRef $aTable, $iBitrate)
    If Not $iBitrate Or $iBitrate > 16 Then Return SetError(1, 0, $aTable)
    Local $iMax = _MComp_TableMax($aTable) / (2 ^ $iBitrate - 1), $iTmp, $iAnz
    For $i = 0 To UBound($aTable) - 1 Step 1
    $iTmp = $aTable[$i][1] / $iMax
    $aTable[$i][1] = ($iTmp < 1) ? 1 : Round($iTmp)
    $iAnz += $aTable[$i][1]
    Next
    Local $aRet = $aTable
    _MComp_TableDivide($aTable, $iAnz)
    Return $aRet
    EndFunc ;==>_MComp_TableCompress

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Aus Table und Intervall berechnetes neues Intervall
    ; | ByRef : Übergebener 2D-Table wird um eine Position nach oben rotiert
    ; | Opt : Bei Bedarf lässt sich die Table-Rotation ausschalten
    ; |------------------------------------------------------------------------------|
    Func _MComp_IntervalCalcNew($aInt, ByRef $aTable, $bRotate = True)
    Local $iSize = $aInt[1] - $aInt[0], $iUBound = UBound($aTable)
    Local $aIntNew[$iUBound][2], $iTmp = $aInt[0]
    For $i = 0 To $iUBound - 1 Step 1
    $aIntNew[$i][0] = $aTable[$i][0]
    $aIntNew[$i][1] = $iTmp + $aTable[$i][1] * $iSize
    $iTmp += $aTable[$i][1] * $iSize
    Next
    If $bRotate Then _MComp_TableRotate($aTable)
    Return $aIntNew
    EndFunc ;==>_MComp_IntervalCalcNew

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

    ; |------------------------------------------------------------------------------|
    ; | Return: 2D-Wahrscheinlichkeitstabelle für jedes Zeichen im Text
    ; | Opt : Die Wahrscheinlichkeitsbitrate ist zwischen 1 und 16 frei wählbar
    ; |------------------------------------------------------------------------------|
    Func _MComp_StringCreateTable($sText, $iBitrate = 0)
    Local $aTable = _MComp_StringCountChars($sText)
    _MComp_TableDivide($aTable, _MComp_TableSum($aTable))
    If $iBitrate > 0 Then _MComp_TableCompress($aTable, $iBitrate)
    Return $aTable
    EndFunc ;==>_MComp_StringCreateTable

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

    ; |------------------------------------------------------------------------------|
    ; | ByRef : Übergebenes 1D-Array wird in ein 2D-Array übersetzt
    ; |------------------------------------------------------------------------------|
    Func _MComp_ArrayMake2D(ByRef $aArray1D)
    If Not UBound($aArray1D, 0) = 1 Then Return SetError(1)
    Local $aArray2D[256][2], $iCnt = 0
    For $i = 0 To 255 Step 1
    If $aArray1D[$i] Then
    $aArray2D[$iCnt][0] = $i
    $aArray2D[$iCnt][1] = $aArray1D[$i]
    $iCnt += 1
    EndIf
    Next
    ReDim $aArray2D[$iCnt][2]
    $aArray1D = $aArray2D
    EndFunc ;==>_MComp_ArrayMake2D

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

    ; |------------------------------------------------------------------------------|
    ; | ByRef : Übergebenes 2D-Array wird um eine Position nach oben rotiert
    ; |------------------------------------------------------------------------------|
    Func _MComp_TableRotate(ByRef $aArray)
    If Not UBound($aArray, 0) = 2 Then Return SetError(1)
    Local $iTmp[2] = [$aArray[0][0], $aArray[0][1]], $iUBound = UBound($aArray)
    For $i = 0 To $iUBound - 2 Step 1
    $aArray[$i][0] = $aArray[$i + 1][0]
    $aArray[$i][1] = $aArray[$i + 1][1]
    Next
    $aArray[$iUBound - 1][0] = $iTmp[0]
    $aArray[$iUBound - 1][1] = $iTmp[1]
    EndFunc ;==>_MComp_TableRotate

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Array[256] mit der zum Index gehörenden Anzahl Zeichenfunde
    ; |------------------------------------------------------------------------------|
    Func _MComp_StringCountChars($sString)
    Local $aRet[256], $sBin = _MComp_StringToHex($sString)
    For $i = 1 To StringLen($sBin) Step 2
    $aRet['0x' & StringMid($sBin, $i, 2)] += 1
    Next
    _MComp_ArrayMake2D($aRet)
    Return $aRet
    EndFunc ;==>_MComp_StringCountChars

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Informationsgehalt eines Strings bei konstanter Bitrate/Zeichen
    ; | Opt : Die Genauigkeit in Dezimalstellen kann angepasst werden
    ; |------------------------------------------------------------------------------|
    Func _MComp_StringGetInformationContent($sString, $iDec = 2)
    Return Round(StringLen($sString) * Log(UBound( _
    _MComp_StringCreateTable($sString))) / Log(2) / 8, $iDec)
    EndFunc ;==>_MComp_StringGetInformationContent

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Hexadezimalrepräsentation eines ASC256-Strings ohne führendes '0x'
    ; |------------------------------------------------------------------------------|
    Func _MComp_StringToHex($sString)
    Return StringTrimLeft(StringToBinary($sString), 2)
    EndFunc ;==>_MComp_StringToHex

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

    ; |------------------------------------------------------------------------------|
    ; | Return: ASC265-String einer Hexadezimalrepräsentation ohne führendes '0x'
    ; |------------------------------------------------------------------------------|
    Func _MComp_HexToString($sHex)
    Return BinaryToString('0x' & $sHex)
    EndFunc ;==>_MComp_HexToString

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Summe aller Wahrscheinlichkeiten eines Tables
    ; |------------------------------------------------------------------------------|
    Func _MComp_TableSum($aArray)
    If Not UBound($aArray, 0) = 1 Then Return SetError(1)
    Local $iCnt = $aArray[0][1]
    For $i = 1 To UBound($aArray) - 1 Step 1
    $iCnt += $aArray[$i][1]
    Next
    Return $iCnt
    EndFunc ;==>_MComp_TableSum

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

    ; |------------------------------------------------------------------------------|
    ; | Return: Maximalwert der Wahrscheinlichkeiten eines Tables
    ; |------------------------------------------------------------------------------|
    Func _MComp_TableMax($aArray)
    Local $iMax = $aArray[0][1]
    For $i = 1 To UBound($aArray) - 1 Step 1
    If $aArray[$i][1] > $iMax Then $iMax = $aArray[$i][1]
    Next
    Return $iMax
    EndFunc ;==>_MComp_TableMax

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

    ; |------------------------------------------------------------------------------|
    ; | ByRef : Die Wahrscheinlichkeitswerte des Tables werden durch iNum dividiert
    ; |------------------------------------------------------------------------------|
    Func _MComp_TableDivide(ByRef $aArray, $iNum)
    For $i = 0 To UBound($aArray) - 1 Step 1
    $aArray[$i][1] /= $iNum
    Next
    EndFunc ;==>_MComp_TableDivide

    [/autoit]
    Archiviert: 23.05.2014

    Hab die Kodierung mit einigen Suboptimalitäten zum laufen bekommen.
    Es wird nun aus einem beliebigen String ein codierter Hexstring erzeugt der (im Idealfall) weniger Bytes beansprucht als der ursprüngliche String.

    ToDo:
    DecToBin, BinToDec, DecToHex, HexToDec - Suboptimal
    Table Einbindung IMMER mit 8Bit Kompression - wird später variabel und effizienter sein
    Das Tempo könnte auch noch steigen. Wäre jedenfalls nicht schlecht :)

    Skript
    [autoit]


    #include <Array.au3>

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

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

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

    _DecToBin_Startup()

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

    Global $sText = _
    'Hallo, ich will komprimiert werden. Das gefällt ' & _
    'mir sehr gut. Sehr Schön, Ciao ! Sowas könnte ic' & _
    'h den ganzen lieben langen Tag machen. Da wird j' & _
    'a der Hund in der Pfanne Verrückt. Sowas lasse i' & _
    'ch nicht einfach durchgehen, ihr Banausen ! Da g' & _
    'eht mir die Hutschnur wenn ich sowas sehe, das i' & _
    'st ja nicht zum Aushalten ! Bei sowas könnte ich' & _
    ' mich grad vergessen. Das geht überhaupt nicht ! '

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

    Global $sComp = _MComp_StringEncode($sText, 8)
    ConsoleWrite('Comp: ( ' & StringLen($sComp)/2 & ' Bytes ) ' & $sComp & @CRLF)

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

    Global $sDec = _MComp_StringDecode($sComp)

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

    ConsoleWrite('Dec: ( ' & StringLen($sDec) & ' Bytes ) ' & $sDec & @CRLF)
    If Not ($sDec == $sText) Then ConsoleWrite('! ERROR: Data corrupted !' & @CRLF & @CRLF)

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

    ; Nicht Optimal !
    Func _MComp_DecToHex($sDec)
    Local $sBin = __MComp_DecToBin($sDec), $iLen = Hex(Int(StringLen($sBin)),4), $sHex
    While Not IsInt(StringLen($sBin)/8)
    $sBin &= 0
    WEnd
    For $i = 1 To StringLen($sBin) Step 8
    ;~ ConsoleWrite(StringMid($sBin, $i, 8) & ' - ' & Hex(Int(_BinToDec(StringMid($sBin, $i, 8))),2) & @CRLF)
    $sHex &= Hex(Int(_BinToDec(StringMid($sBin, $i, 8))),2)
    Next
    ;~ ConsoleWrite('ssssssssssssssssssssssssssssssssssssssssss' & @CRLF)
    Return $iLen & $sHex
    EndFunc

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

    ; Nicht Optimal !
    Func _MComp_HexToDec($sHex)
    Local $iLen = Int('0x' & StringLeft($sHex, 4)), $sBin
    $sHex = StringTrimLeft($sHex, 4)
    For $i = 1 To StringLen($sHex) Step 2
    ;~ ConsoleWrite(StringRight('00000000' & _DecToBin(StringMid($sHex, $i, 2)), 8) & ' - ' & StringMid($sHex, $i, 2) & @CRLF)
    $sBin &= StringRight('00000000' & _DecToBin(Int('0x' & StringMid($sHex, $i, 2))), 8)
    Next
    ;~ Return $sBin
    Return __MComp_BinToDec(StringLeft($sBin, $iLen))
    EndFunc

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

    Func _MComp_TableToString($aTable, $nBit = 0)
    $nBit = 8 ;wird noch geändert !
    ; Aufbau:
    ; StartBit | ZielBit | Bit |Inhalt
    ; 1 | 4 | 4 | Rundungsstärke in Bit (1 -> 15)
    ; 5 | 12 | 8 | Anzahl Zeichen (1 -> 256)
    ; 13 | 15 | 4 | Charset (1 -> 15) ( bisher nur bis 7 befüllt )
    ; 16 | 23 | 8 | Hinzuzufügende Zeichen
    ; 24 | 31 | 8 | Abzuziehende Zeichen
    ; 32 | x | ... | Abzuziehende Zeichen je 8 Bit
    ; x+1 | y | ... | Hinzugefügte Zeichen je 8 Bit, Hinzugefügte Wahrscheinlichkeiten je x Bit
    ; Bsp: 39 Zeichen | Bitrate: 6 | Charset: Leer
    ; Header: 4+8+4+8+8 = 32Bit
    ; Abzüge: 0 = 0 Bit
    ; Zusätz: 39*8+39*6 = 546 Bit
    ; compData = 1695 Bit
    ; -> 284.125 Byte
    ; -> Kompression in Bezug auf 8 Bit/Char -> 74%

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

    ; Bisher:
    ; Anzahl|Char|Wert .... -> Char|Wert

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

    If $nBit Then $aTable = _MComp_TableCompress($aTable, $nBit)
    Local $iAnz
    Local $sRet
    For $i = 0 To 255 Step 1
    If $aTable[$i] Then
    $sRet &= Hex($i, 2) & Hex(Int($aTable[$i]), 2)
    $iAnz += 1
    EndIf
    Next
    Return Hex(Int($iAnz), 2) & $sRet
    EndFunc

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

    Func _MComp_StringToTable($sComp)
    Local $nBit = 8 ; wird noch geändert !
    Local $iLen = Int('0x' & StringLeft($sComp, 4))
    $sComp = StringTrimLeft($sComp, 4)
    Local $iAnz = Int('0x' & StringLeft($sComp, 2)), $iCnt
    Local $aTable[256], $aRet[3] = [$iLen, 0, 0]
    For $i = 3 To 3 + ($iAnz - 1) * 4 Step 4
    $aTable['0x' & StringMid($sComp, $i, 2)] = '0x' & StringMid($sComp, $i+2, 2)
    Next
    For $i = 0 To 255 Step 1
    $iCnt += $aTable[$i]
    Next
    For $i = 0 To 255 Step 1
    $aTable[$i] /= $iCnt
    Next
    $aRet[1] = $aTable
    $aRet[2] = StringTrimLeft($sComp, 2 + $iAnz * 4)
    Return $aRet
    EndFunc

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

    Func _MComp_StringDecode($sComp)
    Local $aDec = _MComp_StringToTable($sComp), $aTable = $aDec[1], _
    $iLen = $aDec[0], $aInterval = [0, 1], $aIntNew, $sRet, $iTMP
    $sComp = _MComp_HexToDec($aDec[2])
    While $iLen
    $iTMP = Number('0.' & StringLeft($sComp, 20))
    $aIntNew = _MComp_IntervalCreate($aInterval, $aTable)
    For $i = 0 To UBound($aIntNew) - 1 Step 1
    If $iTMP < $aIntNew[$i][1] Then ExitLoop
    Next
    $sRet &= Chr($aIntNew[$i][0])
    $iLen -= 1
    $aInterval[1] = $aIntNew[$i][1]
    If $i <> 0 Then $aInterval[0] = $aIntNew[$i-1][1]
    While StringLeft($sComp, 1) = StringLeft($aInterval[0] * 10, 1) And StringLeft($sComp, 1) = StringLeft($aInterval[1] * 10, 1)
    $iTMP = StringLeft($sComp, 1)
    $sComp = StringTrimLeft($sComp, 1)
    $aInterval[0] = $aInterval[0] * 10 - $iTMP
    $aInterval[1] = $aInterval[1] * 10 - $iTMP
    WEnd
    WEnd
    Return $sRet
    EndFunc

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

    Func _MComp_StringEncode($sText, $nBit = 0)
    Local $aTable = _MComp_StringCreateTable($sText, $nBit), $sTable _
    = _MComp_TableToString($aTable, $nBit), $aInterval = [0, 1], _
    $sBin = StringTrimLeft(StringToBinary($sText),2), $sRet, $sChar _
    , $aIntNew, $iTMP, $aTableBit = _MComp_TableCompress($aTable, $nBit)
    For $i = 1 To StringLen($sBin) Step 2
    $sChar = Int('0x' & StringMid($sBin, $i, 2))
    $aIntNew = _MComp_IntervalCreate($aInterval, $aTable)
    For $e = 0 To UBound($aIntNew) - 1 Step 1
    If $aIntNew[$e][0] = $sChar Then ExitLoop
    Next
    $aInterval[1] = $aIntNew[$e][1]
    If $e <> 0 Then $aInterval[0] = $aIntNew[$e-1][1]
    While StringLeft($aInterval[0] * 10, 1) = StringLeft($aInterval[1] * 10, 1)
    $iTMP = StringLeft($aInterval[0] * 10, 1)
    $sRet &= $iTMP
    $aInterval[0] = $aInterval[0] * 10 - $iTMP
    $aInterval[1] = $aInterval[1] * 10 - $iTMP
    WEnd
    Next
    Return Hex(Int(StringLen($sText)),4) & $sTable & '' & _MComp_DecToHex($sRet & Round(($aInterval[0] + $aInterval[1]) * 5, 0))
    EndFunc

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

    ; Komprimiert den Table mit einer Bitrate. Rückgabe ist
    ; der Table mit Werten zwischen 0 und 2^n-1. Der Table
    ; selbst wird noch durch die Summe aller Werte geteilt,
    ; damit er wieder eine Wahrscheinlichkeitstabelle ist.
    Func _MComp_TableCompress(ByRef $aTable, $nBit)
    If Not $nBit Then Return $aTable
    Local $iMax = $aTable[0], $iTMP, $iAnz
    For $i = 1 To UBound($aTable) - 1 Step 1
    If $aTable[$i] > $iMax Then $iMax = $aTable[$i]
    Next
    For $i = 1 To UBound($aTable) - 1 Step 1
    If $aTable[$i] Then
    $iTMP = $aTable[$i]/$iMax*(2^$nBit-1)
    If $iTMP < 0.5 Then
    $aTable[$i] = 1
    Else
    $aTable[$i] = Round($iTMP)
    EndIf
    $iAnz += $aTable[$i]
    EndIf
    Next
    Local $aRet = $aTable
    For $i = 1 To UBound($aTable) - 1 Step 1
    $aTable[$i] /= $iAnz
    Next
    Return $aRet
    EndFunc

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

    Func _MComp_IntervalCreate($aInterval, $aTable)
    Local $nSize = $aInterval[1] - $aInterval[0], $iAnz
    For $i = 0 To 255 Step 1
    If $aTable[$i] Then
    $aTable[$i] *= $nSize
    $iAnz += 1
    EndIf
    Next
    Local $aIntNew[$iAnz][2], $iTMP = $aInterval[0]
    $iAnz = 0
    For $i = 0 To 255 Step 1
    If $aTable[$i] Then
    $aIntNew[$iAnz][0] = $i
    $aIntNew[$iAnz][1] = $iTMP + $aTable[$i]
    $iTMP += $aTable[$i]
    $iAnz += 1
    EndIf
    Next
    Return $aIntNew
    EndFunc

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

    ; nicht Optimal !
    ; Ersetzen von ddd -> 10 Bit (Verlust: 0.34%)
    ; Am Ende ggf bis zu 7 Bit Verlust !
    Func __MComp_DecToBin($sDec)
    While Not IsInt(StringLen($sDec)/3)
    $sDec &= 0
    WEnd
    Local $sRet
    For $i = 1 To StringLen($sDec) Step 3
    $sRet &= StringRight('0000000000' & _DecToBin(StringMid($sDec, $i, 3)), 10)
    Next
    Return $sRet
    EndFunc

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

    Func __MComp_BinToDec($sBin)
    Local $sRet
    For $i = 1 To StringLen($sBin) Step 10
    $sRet &= StringRight('000' & _BinToDec(StringMid($sBin, $i, 10)), 3)
    Next
    Return $sRet
    EndFunc

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

    ; Erzeugt eine Wahrscheinlichkeitstabelle zu jedem Zeichen
    ; in einem String. Rückgabe ist ein Array[256] mit den
    ; Wahrscheinlichkeiten zu jedem Index.
    Func _MComp_StringCreateTable($sText, $nBit = 0)
    Local $aCount = _MComp_StringCount($sText), $iTMP
    For $i = 0 To 255 Step 1
    $iTMP += $aCount[$i]
    Next
    For $i = 0 To 255 Step 1
    $aCount[$i] /= $iTMP
    Next
    If $nBit Then _MComp_TableCompress($aCount, $nBit)
    Return $aCount
    EndFunc

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

    ; Zählt die Vorkommnisse der einzelnen 256 Zeichen in einem
    ; String und gibt diese als Array[256] zurück,
    Func _MComp_StringCount($sText)
    Local $aRet[256], $sBin = StringTrimLeft(StringToBinary($sText), 2)
    For $i = 1 To StringLen($sBin) Step 2
    $aRet['0x' & StringMid($sBin, $i, 2)] += 1
    Next
    Return $aRet
    EndFunc

    [/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]
    Alter Inhalt

    Moin,

    Da mir die Huffman Codierung bei einigen Tests nicht sonderlich gefallen hat, habe ich mich mal an der Arithmetischen Codierung versucht. Wie die Funktioniert steht auf Wikipedia: Hier

    In der jetzigen Ausführung wird beim Komprimieren ausschließlich die Zahl ausgegeben. Zum Dekomprimieren benötigt man weiterhin die Wahrscheinlichkeitstabelle, sowie die Stringlänge. Bevor ich mich dem widme möchte ich wissen, ob das Konzept überhaupt anständig funktioniert.

    Das Problem ist in dem Fall die Kommagenauigkeit. Diese wird zwar regelmäßig hochgesetzt, aber trotzdem habe ich einige Rundungsfehler bemerkt (die seltsamerweise keine Auswirkung auf das Ergebnis haben).

    &quot;Skript läuft mit der aktuellen Stable&quot;
    [autoit]


    #include <Array.au3>

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

    Global $sText = _
    'Hallo, ich will komprimiert werden. Das gefällt ' & _
    'mir sehr gut. Sehr Schön, Ciao ! Sowas könnte ic' & _
    'h den ganzen lieben langen Tag machen. Da wird j' & _
    'a der Hund in der Pfanne Verrückt. Sowas lasse i' & _
    'ch nicht einfach durchgehen, ihr Banausen ! Da g' & _
    'eht mir die Hutschnur wenn ich sowas sehe, das i' & _
    'st ja nicht zum Aushalten ! Bei sowas könnte ich' & _
    ' mich grad vergessen. Das geht überhaupt nicht !'

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

    Local $x = [0, 1], $iAnz = UBound(_MComp_IntervalCreate($x, _MComp_StringCreateTable($sText)))

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

    ConsoleWrite('String -> (' & $iAnz & ')' & @CRLF & '> ' & $sText & @CRLF & 'Len: ' & StringLen($sText) & @CRLF & 'Größe: ' & Round(StringLen($sText)*Log($iAnz)/Log(2)/8) & ' Byte' & @CRLF & @CRLF)

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

    Global $sComp = _MComp_StringEncode($sText)

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

    $x[0] = 0
    $x[1] = 1
    $iAnz = UBound(_MComp_IntervalCreate($x, _MComp_StringCreateTable($sComp)))

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

    ConsoleWrite('Coding -> (' & $iAnz & ')' & @CRLF & '> ' & $sComp & @CRLF & 'Len: ' & StringLen($sComp) & @CRLF & 'Größe: ' & Round(StringLen($sComp)*Log($iAnz)/Log(2)/8) & ' Byte' & @CRLF & @CRLF)

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

    Global $sDec = _MComp_StringDecode($sComp, _MComp_StringCreateTable($sText), StringLen($sText))

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

    ConsoleWrite('Decode ->' & @CRLF & '> ' & $sDec & @CRLF & @CRLF)
    If Not $sDec == $sText Then ConsoleWrite('! ERROR: Data corrupted !' & @CRLF)

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

    Func _MComp_StringDecode($sComp, $aTable, $iLen)
    Local $aInterval = [0, 1], $aIntNew, $sRet, $iTMP
    While $iLen
    $iTMP = Number('0.' & StringLeft($sComp, 20))
    $aIntNew = _MComp_IntervalCreate($aInterval, $aTable)
    For $i = 0 To UBound($aIntNew) - 1 Step 1
    ;~ ConsoleWrite('TMP: ' & $iTMP & ' - ' & 'nr: ' & $aIntNew[$i][1] & @CRLF)
    If $iTMP < $aIntNew[$i][1] Then ExitLoop
    Next
    ;~ ConsoleWrite('[' & $aInterval[0] & ' - ' & $aInterval[1] & ']' & @CRLF)
    $sRet &= Chr($aIntNew[$i][0])
    $iLen -= 1
    ;~ ConsoleWrite(BinaryToString('0x' & $aIntNew[$i][0]) & @CRLF)
    $aInterval[1] = $aIntNew[$i][1]
    If $i <> 0 Then $aInterval[0] = $aIntNew[$i-1][1]
    ;~ _ArrayDisplay($aInterval, $iTMP)
    While StringLeft($sComp, 1) = StringLeft($aInterval[0] * 10, 1) And StringLeft($sComp, 1) = StringLeft($aInterval[1] * 10, 1)
    $iTMP = StringLeft($sComp, 1)
    $sComp = StringTrimLeft($sComp, 1)
    $aInterval[0] = $aInterval[0] * 10 - $iTMP
    $aInterval[1] = $aInterval[1] * 10 - $iTMP
    WEnd
    WEnd
    Return $sRet
    EndFunc

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

    Func _MComp_StringEncode($sText)
    Local $aTable = _MComp_StringCreateTable($sText), _
    $aInterval = [0, 1], $sBin = StringTrimLeft( _
    StringToBinary($sText),2), $sRet, $sChar, $aIntNew, $iTMP
    For $i = 1 To StringLen($sBin) Step 2
    $sChar = Int('0x' & StringMid($sBin, $i, 2))
    $aIntNew = _MComp_IntervalCreate($aInterval, $aTable)
    For $e = 0 To UBound($aIntNew) - 1 Step 1
    If $aIntNew[$e][0] = $sChar Then ExitLoop
    Next
    $aInterval[1] = $aIntNew[$e][1]
    If $e <> 0 Then $aInterval[0] = $aIntNew[$e-1][1]
    While StringLeft($aInterval[0] * 10, 1) = StringLeft($aInterval[1] * 10, 1)
    $iTMP = StringLeft($aInterval[0] * 10, 1)
    $sRet &= $iTMP
    $aInterval[0] = $aInterval[0] * 10 - $iTMP
    $aInterval[1] = $aInterval[1] * 10 - $iTMP
    WEnd
    Next
    Return $sRet & Round(($aInterval[0] + $aInterval[1]) * 5, 0)
    EndFunc

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

    Func _MComp_IntervalCreate($aInterval, $aTable)
    Local $nSize = $aInterval[1] - $aInterval[0], $iAnz
    For $i = 0 To 255 Step 1
    If $aTable[$i] Then
    $aTable[$i] *= $nSize
    $iAnz += 1
    EndIf
    Next
    Local $aIntNew[$iAnz][2], $iTMP = $aInterval[0]
    $iAnz = 0
    For $i = 0 To 255 Step 1
    If $aTable[$i] Then
    $aIntNew[$iAnz][0] = $i
    $aIntNew[$iAnz][1] = $iTMP + $aTable[$i]
    $iTMP += $aTable[$i]
    $iAnz += 1
    EndIf
    Next
    Return $aIntNew
    EndFunc

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

    Func _MComp_StringCreateTable($sText)
    Local $aCount = _MComp_StringCount($sText), $iTMP
    For $i = 0 To 255 Step 1
    $iTMP += $aCount[$i]
    Next
    For $i = 0 To 255 Step 1
    $aCount[$i] /= $iTMP
    Next
    Return $aCount
    EndFunc

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

    Func _MComp_StringCount($sText)
    Local $aRet[256], $sBin = StringTrimLeft(StringToBinary($sText), 2)
    For $i = 1 To StringLen($sBin) Step 2
    $aRet['0x' & StringMid($sBin, $i, 2)] += 1
    Next
    Return $aRet
    EndFunc

    [/autoit]

    Zum Testen und Benutzen für alle die Lustig sind :)


    lg Mars

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

    • Mars
    • 8. Januar 2014 um 01:53

    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

  • Unterminated String

    • Mars
    • 4. Januar 2014 um 15:18

    Nur so nebenbei:
    Die Funktion von mir schiebt alle Dateien um 1 nach hinten und schreibt einen String in die Datei 1.
    Von Bildern war nicht die Rede. Bilder kann man sehr gut Chronologisch speichern indem du dir die TimeStamp nimmst für den Dateinamen.

    [autoit]

    @YEAR & @YDAY & @HOUR & @MIN & @SEC & @MSEC

    [/autoit]


    Dann heißen die Bilder z.B. 2014004151703271.jpg (Jahr 2014, Tag 004, Stunde 15, Minute 17, Sekunde 03.271)
    lg
    M

  • AutoIT Dateien umbenennen Counter

    • Mars
    • 3. Januar 2014 um 22:02

    Meine Interpretatinon der Fragestellung:
    Ein Ordner enthält keine, oder mehrere Dateien die linear per Index mit 1.txt -> n.txt beschriftet sind.
    Es wird eine Funktion benötigt die einen bestimmten Inhalt in die 1.txt packt und alle alten Dateien um 1 erhöht.

    Lösung:

    [autoit]

    For $i = 1 To 9 Step 1
    X('Ich wurde als ' & $i & 'tes geschrieben !')
    Next

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

    Func X($s, $i = 1, $x = 1) ; $s -> 1.txt | $i und $x NICHT benutzen !
    Return $x=1?FileExists($i&'.txt')?X($s,$i+1 _
    ,1):X($s,$i,0):$i>1?X($s,$i-1,FileMove($i-1 _
    &'.txt',$i&'.txt')*0):FileWrite('1.txt',$s)
    EndFunc

    [/autoit]

    Funktionsweise:
    1. Es wird die Anzahl Dateien ermittelt
    2. Es werden alle alten Dateien umbenannt
    3. Die neue Datei enthält den Inhalt der Variable $s und wird als 0.txt gespeichert.

    (Zum Test bitte einen Ordner erstellen, aktuelle Stable benutzen)

    Edit: Angepasst, dass die 1.txt als erste Datei genutzt wird.

    lg
    M

  • AutoIt Versions-Archiv und Diskussionsthread (3.3.8.1 bis 3.3.10.2, Stand 30.12.13)

    • Mars
    • 30. Dezember 2013 um 01:28

    Moin,
    Selbstverständlich ist das ändern von "Konstanten" grober Unfug, und das Einbauen von 100kb nur um einen einfachen Fehler zu beheben ebenfalls. Trotzdem finde ich, dass hier aktuell zu viel Wind gemacht wird. Eigentlich darf ich dazu kein Urteil fällen, da ich AutoIt (noch) nicht für irgendwelche Gewinnbringenden Angelegenheiten einsetze. Meine Skripte sind allesamt sowohl kompiliert, als auch als Code vorhanden. Idr wird einfach die kompilierte Version ausgeführt und alle freuen sich :) .

    Ich persönlich freue mich über die "Features" und die 15% mehr Tempo, Abwärtskompatibilität ist eben leider nicht immer gegeben. (ob das vermeidbar ist oder nicht liegt im Auge des Betrachters, manch einer begrüßt vllt die neue Bitmap Struct (mir persönlich ist das egal, da ich Konstanten aus Platzspargründen automatisch an den Skriptanfang einfügen lasse, will ja nicht gleich 2000 unnütze Variablen in meinem Skript haben))

    Das ist in anderen Sprachen vllt nicht so extrem, aber durchaus vorhanden. Wenn ich zu anderen Sprachen größere Beispiele suche laufen die auch meistens nicht ohne weiteres, da in diesem Fall die verschiedenen Compiler, Versionen, seltsame Includes und sonstige Kunstgriffe ausschlaggebend sind.

    Der beste Schutz ist eine kompilierte Version, nachteilig ist, dass man diese nicht ändern kann. Alles hat seine Vor- und Nachteile.
    Ich werde bei der Version 10 bleiben und schauen was sich so ergibt :)

    Edit: ein Lut in einer Programmiersprache ist allerdings "überlächerlich" (dafür fällt mir gar kein passendes Wort ein^^).

    lg
    M

Spenden

Jeder Euro hilft uns, Euch zu helfen.

Download

AutoIt Tutorial
AutoIt Buch
Onlinehilfe
AutoIt Entwickler
  1. Datenschutzerklärung
  2. Impressum
  3. Shoutbox-Archiv
Community-Software: WoltLab Suite™