Gleitkommazahlen (float) aus Binärdaten extrahieren

  • Hallo,

    ich habe in AutoIT das Problem eine 32 bit-Float richtig zu extrahieren wie es die PHP-Funktion unpack("f", ...) tut.

    PHP
    $bin = pack("f", 312.77105712891);
    $float = unpack("f",$bin); //312.77105712891


    Die Funktionen von AutoIT hab ich schon alle nach verschiedenen Möglichkeiten probiert, aber das erwünschte Ergebnis kam nie. :(

    Kennt einer von euch den Weg "unpack("f",..)" oder ähnliche Funktionen in AutoIT zu benutzen?

    Danke für die Antworten. :)

    Edit:

    [autoit]


    #include <WinAPI.au3>

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

    Func HexToFloat($hex)
    Return _WinAPI_IntToFloat(Int("0x" & StringMid($hex, 7, 2) & StringMid($hex, 5, 2) & StringMid($hex, 3, 2) & StringMid($hex, 1, 2)))
    EndFunc

    [/autoit]

    3 Mal editiert, zuletzt von A.I7 (24. Dezember 2009 um 04:37)

  • Meinst du vielleicht das hier? oder was macht pack, unpack?

    [autoit]

    Dim $str = "312.77105712891"
    Dim $number = Number($str)

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

    MsgBox(0, $str, $number)

    [/autoit]
  • [autoit]

    #include <Array.au3>
    Global $BIN
    _pack($BIN,"3.14124124")
    _Pack($BIN,"41.4537585")

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

    $array = _unpack($BIN)
    _ArrayDisplay($array)

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

    Func _pack(ByRef $bBinary, $sText, $sDelim="|")
    $bBinary &= StringToBinary($sText)&$sDelim
    EndFunc

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

    Func _unpack($bBinary,$sDelim="|")
    $aRet = StringSplit($bBinary,"|")
    For $i = 1 to $aRet[0]
    $aRet[$i] = BinaryToString($aRet[$i])
    Next
    ReDim $aRet[$aRet[0]]
    $aRet[0] -= 1
    Return $aRet
    EndFunc

    [/autoit]
  • Danke, aber wenn es so einfach wäre, hätte ich es längst. ;)
    OK, dann erzähl ich alles. Ich erstelle gerade eine AutoIt Query Library für Source Server. (http://developer.valvesoftware.com/wiki/Server_Queries)

    Ich hab schon alle Funktionen fertig, nur ein Datentyp ist mir ein Dorn im Auge:
    Bei der Spielerzeit kommt ein float-Wert zurück. Ich hab ihn zwar versucht mit StringFormat() zu dekodieren, aber es kommt nur 0.0000 raus.

    Hier die ganze Funktion:

    Spoiler anzeigen
    [autoit]


    Func SrcPlayers()
    Local $r, $pNum;, $hour, $min, $sec
    ; Get data
    $r = _SrcRequest("55" & _SrcChallenge())
    If StringLeft($r, 2) <> "44" Then
    ErrorVal("Player query failed (invalid header).")
    SetError(51)
    Return False
    Else
    $r = StringTrimLeft($r, 2)
    EndIf
    ; Player number -- byte
    $pNum = Dec(StringLeft($r, 2))
    $r = StringTrimLeft($r, 2)
    Local $pData[$pNum + 1][5]
    For $j = 0 To $pNum
    ; Index -- byte
    $pData[$j][1] = Dec(StringLeft($r, 2))
    $r = StringTrimLeft($r, 2)
    ; Name -- string
    $pData[$j][2] = _SrcStrRead($r)
    $r = StringTrimLeft($r, StringLen($pData[$j][2])*2 + 2)
    ; Kills -- long (int)
    $pData[$j][3] = String(Dec(StringMid($r, 7, 2) & StringMid($r, 5, 2) & StringMid($r, 3, 2) & StringMid($r, 1, 2)))
    $r = StringTrimLeft($r, 8)
    ; Time -- float
    ;TODO: HextoFloat or something
    $pData[$j][4] = Binary("0x" & StringLeft($r, 8))
    ;No way... yet
    $r = StringTrimLeft($r, 8)
    Next
    Return $pData
    EndFunc ;==>SrcPlayers

    [/autoit]

    $r ist immer ein langer String aus HEX-Werten.
    Also wie bekomme ich eine vernünftige Kommazahl da raus?

    Edit: Nach vielen verzweifelten Stunden bin ich nun tatsächlich selber draufgekommen. :wacko:
    Seltsam.. naja, dann werde ich mal nichts vorenthalten.

    [autoit]


    #include <WinAPI.au3>

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

    Func HexToFloat($hex)
    Return _WinAPI_IntToFloat(Int("0x" & StringMid($hex, 7, 2) & StringMid($hex, 5, 2) & StringMid($hex, 3, 2) & StringMid($hex, 1, 2)))
    EndFunc

    [/autoit]

    4 Mal editiert, zuletzt von A.I7 (24. Dezember 2009 um 04:37)

  • So geht es auch ;)

    Spoiler anzeigen
    [autoit]

    Func _BinaryToFloat($sBin, $fDouble=False)
    ;Author: Prog@ndy
    If Not IsBinary($sBin) Then
    Switch StringIsXDigit($sBin)
    Case True
    $sBin = Binary('0x' & $sBin)
    Case False
    $sBin = Binary($sBin)
    EndSwitch
    EndIf
    Switch $fDouble
    Case True
    Local $tBin = DllStructCreate("byte[8]")
    DllStructSetData($tBin, 1, $sBin)
    Return DllStructGetData(DllStructCreate('double', DllStructGetPtr($tBin)),1)
    Case Else
    Local $tBin = DllStructCreate("byte[4]")
    DllStructSetData($tBin, 1, $sBin)
    Return DllStructGetData(DllStructCreate('float', DllStructGetPtr($tBin)),1)
    EndSwitch
    EndFunc

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

    $bin = Binary(312.77105712891) ; Binärdaten von Double
    MsgBox(0, '', _BinaryToFloat($bin, True)) ; AutoIt-Intern wird doubel verwendet, also $fDouble auf true

    [/autoit]