Moin,
das folgende ist eine mini UDF um Integerzahlen zusammenzupacken. Die Rechnung ist analog zur Umrechnung zwischen "Uhrzeit und Sekunden", sodass genau dieser Spezialfall auch als Beispiel im Code enthalten ist. Eine Einschränkung ist leider, dass AutoIt intern maximal uint63 unterstützt (also eigentlich int64). Mit einer BigInt-UDF (die es ja gibt, ich wollte aber keine Abhängigkeiten hier) könnte man also "sehr viel mehr" Zahlen zusammenfassen.
Mein persönlicher Anwendungsfall ist (mal wieder) irgendwo einzelne Bits beim Speichern von Daten mit bekannten Intervallen herauszuholen. Ob es dafür andere (sinnvolle) Anwendungsfälle gibt weiß ich leider nicht.
Falls Fehler auftauchen, bitte hier melden. Ich habe die Sache nur kurz getestet und bin froh korrigiert zu werden.
__PI_Test()
Func __PI_Test()
; Uhrzeit Beispiel (Hier spart man keine Bits. Schade)
Local $structure = [[0,23],[0,59],[0,59]]
Local $values = [1, 30, 15]
; Uhrzeit Beispiel mit Tag und Millisekunden (1 Bit gespart)
;~ Local $structure = [[1,365],[0,23],[0,59],[0,59],[0,999]]
;~ Local $values = [234, 1, 30, 15, 789]
; Anderes Beispiel (2 Bit gespart)
;~ Local $structure = [[0, 3], [7, 16], [1000, 1500], [55, 88], [0, 2], [0, 1]]
;~ Local $values = [3, 16, 1500, 88, 1, 1]
; Klassenarbeitsergebnisse von 24 Personen (9 Bit gespart, ist aber auch absichtlich ein Extremfall)
;~ Local $structure = [[1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6], [1, 6]]
;~ Local $values = [1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
Local $packed = _PI_Create($structure)
_PI_SetValue($packed, $values) ; Set all values (can set single ones too via ($packed, $i, $iValue)
Local $iInt = _PI_GetInt($packed) ; Das ist der resultierende uint
_PI_Debug($packed) ; Nochmal reinschauen
ConsoleWrite(@CRLF)
Local $otherPacked = _PI_Create($structure)
_PI_SetInt($otherPacked, $iInt) ; Alle einzelnen Zahlen aus dem uint laden.
_PI_Debug($otherPacked)
Local $values = _PI_GetValue($otherPacked)
For $i = 0 To UBound($values) - 1 Step 1
ConsoleWrite(($i = 0 ? 'Values as array: [' : '') & $values[$i] & ($i < UBound($values) - 1 ? ', ' : ']' & @CRLF))
Next
EndFunc
; e.g. $structure = [[0, 3], [7, 16], [1000, 1500], [55, 88]]
; -> 4 Integers
; -> 1st can be 0, 1, 2 or 3. Ränder inklusive!
Func _PI_Create($aStructure)
Local $x[], $_[]
For $i = 0 To UBound($aStructure) - 1 Step 1
$x[$i] = $_
$x[$i][0] = $aStructure[$i][0]
$x[$i][1] = $aStructure[$i][1]
$x[$i][2] = 0 ; Default = min value
Next
Return $x
EndFunc
; Output the contents + bonus info
Func _PI_Debug($x)
Local $iSumBits = 0, $iSumBitsNaive = 0, $iValue, $iRange, $iMaxIntLen = 0, $sPadding = ' '
For $i = 0 To UBound($x) - 1 Step 1
$iValue = $x[$i][0] + $x[$i][2]
If StringLen($x[$i][0]) > $iMaxIntLen Then $iMaxIntLen = StringLen($x[$i][0])
If StringLen($x[$i][1]) > $iMaxIntLen Then $iMaxIntLen = StringLen($x[$i][1])
If StringLen($iValue) > $iMaxIntLen Then $iMaxIntLen = StringLen($iValue)
Next
ConsoleWrite('Debug packed integers in $x[' & UBound($x) & '][2]' & @CRLF)
For $i = 0 To UBound($x) - 1 Step 1
$iValue = $x[$i][0] + $x[$i][2]
$iRange = $x[$i][1] - $x[$i][0] + 1
ConsoleWrite('[' & StringRight($sPadding & $x[$i][0], $iMaxIntLen) & ', ' & StringRight($sPadding & $x[$i][1], $iMaxIntLen) & '] (Bit: ' & StringFormat('%5.2f', (Log($iRange) / Log(2))) & _
') -> $x[' & $i & '][2] = ' & StringRight($sPadding & $iValue, $iMaxIntLen) & ' (raw: ' & StringRight($sPadding & $x[$i][2], $iMaxIntLen) & ')' & @CRLF)
$iSumBits += Log($iRange) / Log(2)
$iSumBitsNaive += Ceiling(Log($iRange) / Log(2))
Next
ConsoleWrite('Overall bits needed: ' & StringFormat('%.2f', $iSumBits) & ' (' & Ceiling($iSumBits) & ' instead of '&$iSumBitsNaive&') for Integer ' & _PI_GetInt($x) & @CRLF)
EndFunc
; set a value with _PI_SetValue($x, $i, $iValue), where $i is the index and $iValue is the value
; set all values with _PI_SetValue($x, $i), where $i = Array of values [1, 2, 3, ...]
Func _PI_SetValue(ByRef $x, $i, $iValue = 0)
If IsArray($i) Then
If UBound($i) <> UBound($x) Then Return SetError(1, 0, 0 * ConsoleWrite('Num Values ('&UBound($i)&') does not match the size of $x (' & UBound($x) & ')' & @CRLF))
For $j = 0 To UBound($i) - 1 Step 1
_PI_SetValue($x, $j, $i[$j])
Next
Return
EndIf
If $iValue < $x[$i][0] Or $iValue > $x[$i][1] Then Return SetError(1, 0, 0 * ConsoleWrite('Value "'&$iValue&'" is outside the allowed range [' & $x[$i][0] & ', ' & $x[$i][1] & ']' & @CRLF))
If Not IsInt($iValue) Then SetError(2, 0, 0 * ConsoleWrite('Value "'&$iValue&'" is no integer but "'&VarGetType($iValue)&'"' & @CRLF))
$x[$i][2] = $iValue - $x[$i][0]
EndFunc
; get a value with _PI_GetValue($x, $i), where $i is the index
; get all values with _PI_GetValue($x)
Func _PI_GetValue(ByRef $x, $i = -1)
If $i = -1 Then
Local $aRet[UBound($x)]
For $j = 0 To UBound($x) - 1 Step 1
$aRet[$j] = _PI_GetValue($x, $j)
Next
Return $aRet
EndIf
Return $x[$i][0] + $x[$i][2]
EndFunc
; get the uint value
Func _PI_GetInt(ByRef $x)
Local $iInt = 0, $mul = 1
For $i = UBound($x) - 1 To 0 Step -1
$iInt += $x[$i][2] * $mul
$mul *= $x[$i][1] - $x[$i][0] + 1
Next
Return $iInt
EndFunc
; set the uint value. This automatically sets all internal values
Func _PI_SetInt(ByRef $x, $iInt)
Local $prefixMul[], $mul = 1
For $i = UBound($x) - 1 To 1 Step -1
$mul *= $x[$i][1] - $x[$i][0] + 1
$prefixMul[$i - 1] = $mul
Next
For $i = 0 To UBound($prefixMul) - 1 Step 1
$x[$i][2] = Int($iInt / $prefixMul[$i])
$iInt -= $x[$i][2] * $prefixMul[$i]
Next
$x[$i][2] = $iInt
EndFunc
Alles anzeigen
lg
M