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

  • _GDIPlus_ImageCalcDif

    • Mars
    • 5. November 2025 um 19:42
    Zitat von Reinhard

    mir ist ein bisschen unbehaglich dabei, hier vom ursprünglichen Thema abzuschweifen.

    Ach das passt schon :D
    Im Endeffekt geht es ja um eine sehr ähnliche (bzw. fast die selbe) Sache, von daher ist das hier thematisch eigentlich ganz gut aufgehoben. Wäre nur praktisch das was am Ende herauskommt ggf. nochmal kurz in einem eigenen Post zu erklären. Den verlinke ich (oder auch UEZ, wir sind ja PUs, da kann man überall editieren) dann im Startpost entsprechend damit er sichtbarer wird, falls andere Leute das auch gebrauchen können.

    lg
    M

  • _GDIPlus_ImageCalcDif

    • Mars
    • 3. November 2025 um 18:28

    Hier ist noch ein Anhang mit der EasyASM.au3 zusammen, damit man im ASM herumfummeln kann, falls erforderlich.
    (Den 2x Startup & Shutdown bitte ignorieren, das hatte ich mal automatisch in die EasyASM.au3 eingebaut. Genauso wie anderer Kram wie z.B. _ASM_Call(...) wo ich das Interface geändert habe sodass nur noch ein einziger pointer verwendet wird und cdecl verwendet wird statt stdcall. Also bitte bei DllCallAdress bleiben)

    Dateien

    ImageDiffMod_Mars.zip 958,05 kB – 14 Downloads
  • _GDIPlus_ImageCalcDif

    • Mars
    • 3. November 2025 um 18:10

    Ich habs jetzt auch nochmal bei mir angeschaut (mit deiner modifizierten Test.au3) -> Ergebnisse sind meines Erachtens nach richtig.

    Ansonsten kann ich nur empfehlen ein bisschen selbst zu debuggen. Da der Code vorher funktioniert hat kann es maximal ein "Minifehler" irgendwo sein. Also zumindest eingrenzen was schiefgeht. Weil wenn ich es nicht reproduzieren kann muss ich im Dunkeln stochern...

    Bitte probiere es mal komplett ohne ASM aus mit dem nativen AutoIt-Code aus Post #12. Reinhard
    Falls das Ergebnis dann deinen Erwartungen entspricht liegt es am ASM Teil, falls nicht, dann nicht.

  • _GDIPlus_ImageCalcDif

    • Mars
    • 2. November 2025 um 19:30
    Zitat von Schnuffel

    ich vermute dahinter: 3.3.18.0 (September 07, 2025) (Release)

    ScriptBreaking change:

    Added #3891: DllCall() performance optimisation.

    Bleibt die Frage warum eine Performance Optimierung "script breaking" ist. Im changelog steht auch nicht "script breaking", außer ich übersehe da etwas...

  • _GDIPlus_ImageCalcDif

    • Mars
    • 2. November 2025 um 19:03

    Da wurde in der 3.3.18.0 wieder irgendwas im Hintergrund an der Calling Convention geändert (nice... Ich dachte immer Konventionen wären da um sie nicht zu ändern. Das sind bestimmt diese Optimierungen :D). Sowas ähnliches ist schonmal passiert (vor >10 Jahren) wo plötzlich sämtlicher ASM Code nicht mehr gelaufen ist...

    Naja, jedenfalls kann man offensichtlich nicht mehr
    DllCallAddress('none', $pOP_ImageCalcDif, 'ptr', $v1.PTR, 'ptr', $v2.PTR, 'ptr', DllStructGetPtr($vDIFF))
    schreiben, weil "none" als Returnwert wohl irgendwo hintenrum undefined behavior verursacht.

    Der "wahre" fix ist also folgendes:
    DllCallAddress('int', $pOP_ImageCalcDif, 'ptr', $v1.PTR, 'ptr', $v2.PTR, 'ptr', DllStructGetPtr($vDIFF))
    wobei man eax einfach ignoriert, weil man den Returnwert ja nicht braucht.

    Tja, da gibts wohl keine Funktionen mit "void" Returnwert mehr. Kamma nix machen.
    Ich lad das mal als "fix" hoch und schreibe 3.3.18.0+ als Version dran. In der Annahme, dass nicht nochmal irgendwas an Stellen gedreht wird an denen man niemals nie nicht überhaupt gar nicht drehen sollte.

    lg
    Mars

  • _GDIPlus_ImageCalcDif

    • Mars
    • 2. November 2025 um 18:03

    Moin,

    bei mir bekomme ich folgendes, wenn ich die mitgelieferten Daten verwende:
    Die verglichenen Bilder haben eine Differenz von 145.62 Farbtönen pro Pixel.
    Die verglichenen Bildstellen haben eine Differenz von 37.67 Farbtönen pro Pixel.

    wenn ich 2 identische Bilder reinstecke (also z.B. 1.png durch eine Kopie von 2.png ersetze) bekomme ich:
    Die verglichenen Bilder haben eine Differenz von 0 Farbtönen pro Pixel.
    Die verglichenen Bildstellen haben eine Differenz von 62.63 Farbtönen pro Pixel.

    Was genau der Erwartung entspricht. AutoIt 3.3.16.1, 32Bit

    Ich vermute, dass du die 64Bit Version verwendest und der ASM Code ist für 32Bit zusammengesetzt worden

    Edit zur Version von Schnuffel:
    Die (u)Int32 Zahlen einfach so voneinander abzuziehen und nicht in ARGB zu zerlegen ist sehr mutig :D

    Edit2: Könnt ihr die betreffenden Beispielbilder hochladen? Ich kann das Problem bei mir nicht reproduzieren...

    Edit3: OOOOOOH. Tatsächlich. Mit AutoIt 3.3.18.0 (habe mal eben geupdated) sind die Ergebnisse komplett für die Tonne...

    Identische Bilder ergeben bei mir:
    Die verglichenen Bilder haben eine Differenz von 21.05 Farbtönen pro Pixel.
    Die verglichenen Bildstellen haben eine Differenz von 1 Farbtönen pro Pixel.
    Noch schlimmer ist, dass es nicht deterministisch ist was vermuten lässt dass irgendwo nicht initialisierter oder out of bounds speicher gelesen wird.

    Edit 4: Hier ist ein "Fix" der aber nicht das eigentliche Problem löst. Analog zu Schnuffel kann man es auch problemlos ohne ASM machen. Dann wird es aber ziemlich langsam...

    AutoIt
    Func __I2D_BufferCalcDif($v1, $v2) ; Rocket Science
    	Local $iPX = $v1.WIDTH * $v1.HEIGHT
    ;~ 	Local $vDIFF = DllStructCreate('int')
    ;~ 	DllStructSetData($vDIFF, 1, $iPX)
    
    	; --------------------
    	Local $nDif = 0
    	For $i = 0 To $iPX - 1 Step 1
    		Local $p1 = DllStructCreate('byte b; byte g; byte r; byte a', $v1.PTR + $i * 4)
    		Local $p2 = DllStructCreate('byte b; byte g; byte r; byte a', $v2.PTR + $i * 4)
    		$nDif += Abs($p1.r - $p2.r) + Abs($p1.g - $p2.g) + Abs($p1.b - $p2.b)
    	Next
    	$nDif /= $iPX
    	Return ($nDif > 765 Or $nDif < 0) ? SetError(1) : $nDif
    	; --------------------
    
    ;~ 	DllCallAddress('none', $pOP_ImageCalcDif, 'ptr', $v1.PTR, 'ptr', $v2.PTR, 'ptr', DllStructGetPtr($vDIFF))
    ;~ 	If @error Then ConsoleWrite('__I2D_BufferCalcDif' & @error)
    ;~ 	_ASM_Call($iOP_ImageCalcDif, $v1.PTR, $v2.PTR, DllStructGetPtr($vDIFF))
    ;~ 	Local $nDif = DllStructGetData($vDIFF, 1) / $iPX
    ;~ 	Return ($nDif > 765 Or $nDif < 0) ? SetError(1) : $nDif
    EndFunc
    Alles anzeigen


    lg
    Mars

  • QOI.au3

    • Mars
    • 3. August 2025 um 16:05

    Moin,

    anbei ist eine 1:1 Übersetzung der C++ Implementierung von https://github.com/phoboslab/qoi/blob/master/qoi.h

    Falls ich dabei keine Abschreibefehler gemacht habe (unwahrscheinlich, aber möglich ^^) wäre das hier eine "standard" Implementierung vom QOI Dateiformat für Bilder mit Transparenz.

    Für eine anschauliche Erklärung von QOI kann ich das hier empfehlen: youtube dot com/watch?v=EFUYNoFRHQI (nicht vom Titel verwirren lassen, QOI wird hier auch behandelt)

    PS: Code ist nicht optimiert, war auch nicht das Ziel ;)

    AutoIt: QOI.au3
    #include-once
    
    ; QOI AutoIt reference implementation by Mars
    ; https://github.com/phoboslab/qoi/blob/master/qoi.h
    
    Global Const $QOI_SRGB       = 0x00
    Global Const $QOI_LINEAR     = 0x01
    Global Const $QOI_OP_INDEX   = 0x00 ; 00xxxxxx
    Global Const $QOI_OP_DIFF    = 0x40 ; 01xxxxxx
    Global Const $QOI_OP_LUMA    = 0x80 ; 10xxxxxx
    Global Const $QOI_OP_RUN     = 0xc0 ; 11xxxxxx
    Global Const $QOI_OP_RGB     = 0xfe ; 11111110
    Global Const $QOI_OP_RGBA    = 0xff ; 11111111
    Global Const $QOI_MASK_2     = 0xC0 ; 11000000
    Global Const $QOI_PIXELS_MAX = 400000000 ; max file size = 2GB
    Global Const $QOI_MAGIC = BitShift(Asc('q'), -24) + BitShift(Asc('o'), -16) + BitShift(Asc('i'), -8) + Asc('f') ; 'qoif' = 1903128945 (LE)
    Global Const $QOI_HEADER_SIZE = 14
    Global Const $QOI_PADDING = [0, 0, 0, 0, 0, 0, 0, 1]
    Global Const $QOI_CH_RGB = 3
    Global Const $QOI_CH_ARGB = 4
    
    ; Helper because AutoIt has no direct byte access otherwise
    Global $__QOI_RGBA = __QOI_Pixel()
    Global $__QOI_UI32  = __QOI_i32At($__QOI_RGBA)
    
    ; Internal byte order is fixed at 3, 0, 1, 2
    Global $__QOI_ExtARGBByteOrder = [3, 0, 1, 2]
    Func _QOI_ExtARGBByteOrder($a = 3, $r = 0, $g = 1, $b = 2)
    	Local $_ = [$a, $r, $g, $b]
    	$__QOI_ExtARGBByteOrder = $_
    EndFunc
    
    ; Get strings for error-codes
    Func _QOI_Error($i)
    	Switch $i
    		Case 0
    			Return 'Ok'
    		Case 1
    			Return '_QOI_Encode/_QOI_Decode: $vData is no DllStruct'
    		Case 2
    			Return '_QOI_Encode/_QOI_Decode: $vHeader is no DllStruct'
    		Case 3
    			Return '_QOI_Encode/_QOI_Decode: $vLen is no DllStruct'
    		Case 4
    			Return '_QOI_Encode/_QOI_Decode: Invalid header'
    		Case 5
    			Return '_QOI_Decode: Invalid size in $vLen'
    		Case 6
    			Return '_QOI_Decode: Invalid magic number in $vData'
    		Case 10 To 20
    			Return '_QOI_Encode: Alloc failed: DllStructCreate @error = ' & ($i - 10)
    		Case 100
    			Return '_QOI_Encode: Unknown error'
    		Case 101
    			Return '_QOI_Write: Cannot open File in binary write mode'
    	EndSwitch
    	Return 'Unknown error code: ' & $i
    EndFunc
    
    ; All these must be specified when writing files
    Func _QOI_Header($ui32_width = 0, $ui32_height = 0, $ui8_channels = 0, $ui8_colorspace = 0)
    	Local $vHeader = DllStructCreate('uint width;uint height; byte channels; byte colorspace')
    	$vHeader.width = $ui32_width
    	$vHeader.height = $ui32_height
    	$vHeader.channels = $ui8_channels
    	$vHeader.colorspace = $ui8_colorspace
    	Return $vHeader
    EndFunc
    
    Func _QOI_Encode($vData, $vHeader, $vLen)
    	; Ist direkt aus C++ übersetzt und nicht für AutoIt optimiert!
    
    	If Not IsDllStruct($vData) Then Return SetError(1, 0, 0)
    	If Not IsDllStruct($vHeader) Then Return SetError(2, 0, 0)
    	If Not IsDllStruct($vLen) Then Return SetError(3, 0, 0)
    
    	If $vHeader.width = 0 Or $vHeader.height = 0 Or _
    		$vHeader.channels < 3 Or $vHeader.channels > 4 Or _
    		$vHeader.colorspace > 1 Or _
    		$vHeader.height >= Int($QOI_PIXELS_MAX / $vHeader.width) _
    	Then Return SetError(4, 0, 0) ; Invalid header
    
    	Local Const $iMaxSize = $vHeader.width * $vHeader.height * ($vHeader.channels + 1) + $QOI_HEADER_SIZE + UBound($QOI_PADDING)
    
    	Local $vBytes = DllStructCreate('byte[' & $iMaxSize & ']')
    	If @error Then Return SetError(@error + 10, 0, 0) ; Alloc failed
    	Local Const $pBytes = DllStructGetPtr($vBytes)
    	Local $p = 0 ; Pointer & Index
    
    	__QOI_write_ui32($pBytes, $p, $QOI_MAGIC)
    	__QOI_write_ui32($pBytes, $p, $vHeader.width)
    	__QOI_write_ui32($pBytes, $p, $vHeader.height)
    	__QOI_write_ui8($pBytes, $p, $vHeader.channels)
    	__QOI_write_ui8($pBytes, $p, $vHeader.colorspace)
    
    	Local Const $pPixels = DllStructGetPtr($vData)
    	Local $avIndex[64], $aiIndex[64]
    	For $i = 0 To UBound($avIndex) - 1 Step 1
    		$avIndex[$i] = __QOI_Pixel()
    		$aiIndex[$i] = __QOI_i32At($avIndex[$i])
    	Next
    	Local $iRun = 0, $iIndexPos = 0
    	Local $vPx = __QOI_PixelVal(0, 0, 0, 255)
    	Local $iPx = __QOI_i32At($vPx)
    	Local $vPxPrev = __QOI_PixelVal(0, 0, 0, 255)
    	Local $iPxPrev = __QOI_i32At($vPxPrev)
    	Local Const $iPxLen = $vHeader.width * $vHeader.height * $vHeader.channels
    	Local Const $iPxEnd = $iPxLen - $vHeader.channels
    	Local Const $iChannels = $vHeader.channels
    	Local $vr = 0, $vg = 0, $vb = 0, $vgr = 0, $vgb = 0
    
    	For $iPxPos = 0 To $iPxLen - 1 Step $iChannels
    		$vPx.r = __QOI_peek_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[1])
    		$vPx.g = __QOI_peek_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[2])
    		$vPx.b = __QOI_peek_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[3])
    		If $iChannels = 4 Then $vPx.a = __QOI_peek_ui8($pPixels, $iPxPos +  + $__QOI_ExtARGBByteOrder[0])
    		If $iPx.v == $iPxPrev.v Then
    			$iRun += 1
    			If $iRun = 62 Or $iPxPos = $iPxEnd Then
    				__QOI_write_ui8($pBytes, $p, BitOR($QOI_OP_RUN, $iRun - 1))
    				$iRun = 0
    			EndIf
    		Else
    			If $iRun > 0 Then
    				__QOI_write_ui8($pBytes, $p, BitOR($QOI_OP_RUN, $iRun - 1))
    				$iRun = 0
    			EndIf
    			$iIndexPos = BitAND(__QOI_hash_ui32($vPx), 64 - 1)
    			If $aiIndex[$iIndexPos].v = $iPx.v Then
    				__QOI_write_ui8($pBytes, $p, BitOR($QOI_OP_INDEX, $iIndexPos))
    			Else
    				$aiIndex[$iIndexPos].v = $iPx.v
    
    				If $vPx.a = $vPxPrev.a Then
    					$vr = $vPx.r - $vPxPrev.r
    					$vg = $vPx.g - $vPxPrev.g
    					$vb = $vPx.b - $vPxPrev.b
    					$vgr = $vr - $vg
    					$vgb = $vb - $vg
    					If $vr > -3 And $vr < 2 And $vg > -3 And $vg < 2 And $vb > -3 And $vb < 2 Then
    						__QOI_write_ui8($pBytes, $p, BitOR($QOI_OP_DIFF, BitShift($vr + 2, -4), BitShift($vg + 2, -2), $vb + 2))
    					ElseIf $vgr > -9 And $vgr < 8 And $vg > -33 And $vg < 32 And $vgb > -9 And $vgb < 8 Then
    						__QOI_write_ui8($pBytes, $p, BitOR($QOI_OP_LUMA, $vg + 32))
    						__QOI_write_ui8($pBytes, $p, BitOR(BitShift($vgr + 8, -4), $vgb + 8))
    					Else
    						__QOI_write_ui8($pBytes, $p, $QOI_OP_RGB)
    						__QOI_write_ui8($pBytes, $p, $vPx.r)
    						__QOI_write_ui8($pBytes, $p, $vPx.g)
    						__QOI_write_ui8($pBytes, $p, $vPx.b)
    					EndIf
    				Else
    					__QOI_write_ui8($pBytes, $p, $QOI_OP_RGBA)
    					__QOI_write_ui8($pBytes, $p, $vPx.r)
    					__QOI_write_ui8($pBytes, $p, $vPx.g)
    					__QOI_write_ui8($pBytes, $p, $vPx.b)
    					__QOI_write_ui8($pBytes, $p, $vPx.a)
    				EndIf
    			EndIf
    		EndIf
    		$iPxPrev.v = $iPx.v
    	Next
    
    	For $i = 0 To UBound($QOI_PADDING) - 1 Step 1
    		__QOI_write_ui8($pBytes, $p, $QOI_PADDING[$i])
    	Next
    
    	DllStructSetData($vLen, 1, $p)
    	Return $vBytes
    
    EndFunc
    
    Func _QOI_Write($sFileName, $vData, $vHeader)
    	Local $vLen = DllStructCreate('uint')
    	Local $vEncoded = _QOI_Encode($vData, $vHeader, $vLen)
    	If @error Then Return SetError(@error, 0, 1)
    	If DllStructGetData($vLen, 1) = 0 Then Return SetError(100, 0, 0)
    	Local Const $FO_OVERWRITE = 2
    	Local Const $FO_BINARY = 16
    	Local $hFile = FileOpen($sFileName, $FO_BINARY + $FO_OVERWRITE)
    	If $hFile = -1 Then Return SetError(101, 0, 0)
    	Local $vFile = DllStructCreate('byte[' & DllStructGetData($vLen, 1) & ']', DllStructGetPtr($vEncoded))
    	FileWrite($hFile, DllStructGetData($vFile, 1))
    	FileClose($hFile)
    	Return DllStructGetData($vLen, 1)
    EndFunc
    
    Func _QOI_Decode($vData, $vHeader, $vLen)
    
    	If Not IsDllStruct($vData) Then Return SetError(1, 0, 0)
    	If Not IsDllStruct($vHeader) Then Return SetError(2, 0, 0)
    	If Not IsDllStruct($vLen) Then Return SetError(3, 0, 0)
    
    	Local $iSize = DllStructGetData($vLen, 1)
    	If $iSize < $QOI_HEADER_SIZE + UBound($QOI_PADDING) Then Return SetError(5, 0, 0)
    
    	Local Const $pBytes = DllStructGetPtr($vData)
    	Local $p = 0 ; Pointer & Index
    	Local $iChannels = $vHeader.channels ; Output channels (can be different from input e.g. when reading a RGB qoi into 32bit ARGB aligned mem or vice versa)
    
    	Local Const $iMagic = __QOI_read_ui32($pBytes, $p)
    	If $iMagic <> $QOI_MAGIC Then Return SetError(6, 0, 0)
    	$vHeader.width = __QOI_read_ui32($pBytes, $p)
    	$vHeader.height = __QOI_read_ui32($pBytes, $p)
    	$vHeader.channels = __QOI_read_ui8($pBytes, $p)
    	$vHeader.colorspace = __QOI_read_ui8($pBytes, $p)
    
    	If $vHeader.width = 0 Or $vHeader.height = 0 Or _
    		$vHeader.channels < 3 Or $vHeader.channels > 4 Or _
    		$vHeader.colorspace > 1 Or _
    		$vHeader.height >= Int($QOI_PIXELS_MAX / $vHeader.width) _
    	Then Return SetError(4, 0, 0) ; Invalid header
    
    	If $iChannels = 0 Then $iChannels = $vHeader.channels
    
    	Local Const $iPxLen = $vHeader.width * $vHeader.height * $iChannels
    	Local $vPixels = DllStructCreate('byte[' & $iPxLen & ']')
    	If @error Then Return SetError(@error + 10, 0, 0) ; Alloc failed
    	Local Const $pPixels = DllStructGetPtr($vPixels)
    
    	Local $avIndex[64], $aiIndex[64]
    	For $i = 0 To UBound($avIndex) - 1 Step 1
    		$avIndex[$i] = __QOI_Pixel()
    		$aiIndex[$i] = __QOI_i32At($avIndex[$i])
    	Next
    	Local $vPx = __QOI_PixelVal(0, 0, 0, 255)
    	Local $iPx = __QOI_i32At($vPx)
    	Local $iChunksLen = $iSize - UBound($QOI_PADDING)
    	Local $iRun = 0, $iB1 = 0, $iIndexPos = 0, $iB2 = 0, $vg = 0
    
    	For $iPxPos = 0 To $iPxLen - 1 Step $iChannels
    		If $iRun > 0 Then
    			$iRun -= 1
    		ElseIf $p < $iChunksLen Then
    			$iB1 = __QOI_read_ui8($pBytes, $p)
    			If $iB1 = $QOI_OP_RGB Then
    				$vPx.r = __QOI_read_ui8($pBytes, $p)
    				$vPx.g = __QOI_read_ui8($pBytes, $p)
    				$vPx.b = __QOI_read_ui8($pBytes, $p)
    			ElseIf $iB1 = $QOI_OP_RGBA Then
    				$vPx.r = __QOI_read_ui8($pBytes, $p)
    				$vPx.g = __QOI_read_ui8($pBytes, $p)
    				$vPx.b = __QOI_read_ui8($pBytes, $p)
    				$vPx.a = __QOI_read_ui8($pBytes, $p)
    			ElseIf BitAND($iB1, $QOI_MASK_2) = $QOI_OP_INDEX Then
    				$iIndexPos = $iB1 ; Kein BitAnd 63 erforderlich, da Mask == 0b00111111
    				$iPx.v = $aiIndex[$iIndexPos].v
    			ElseIf BitAND($iB1, $QOI_MASK_2) = $QOI_OP_DIFF Then
    				$vPx.r += BitAND(BitShift($iB1, 4), 0x03) - 2
    				$vPx.g += BitAND(BitShift($iB1, 2), 0x03) - 2
    				$vPx.b += BitAND($iB1, 0x03) - 2
    			ElseIf BitAND($iB1, $QOI_MASK_2) = $QOI_OP_LUMA Then
    				$iB2 = __QOI_read_ui8($pBytes, $p)
    				$vg = BitAND($iB1, 0x3F) - 32
    				$vPx.r += $vg - 8 + BitAND(BitShift($iB2, 4), 0x0F)
    				$vPx.g += $vg
    				$vPx.b += $vg - 8 + BitAND($iB2, 0x0F)
    			ElseIf BitAND($iB1, $QOI_MASK_2) = $QOI_OP_RUN Then
    				$iRun = BitAND($iB1, 0x3F)
    			EndIf
    			$iIndexPos = BitAND(__QOI_hash_ui32($vPx), 64 - 1)
    			$aiIndex[$iIndexPos].v = $iPx.v
    		EndIf
    		__QOI_put_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[1], $vPx.r)
    		__QOI_put_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[2], $vPx.g)
    		__QOI_put_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[3], $vPx.b)
    		If $iChannels = 4 Then __QOI_put_ui8($pPixels, $iPxPos + $__QOI_ExtARGBByteOrder[0], $vPx.a)
    	Next
    
    	Return $vPixels
    
    EndFunc
    
    Func _QOI_Read($sFileName, ByRef $vData, $vHeader)
    	Local Const $FO_BINARY = 16
    	Local $hFile = FileOpen($sFileName, $FO_BINARY)
    	If $hFile = -1 Then Return SetError(101, 0, 0)
    	Local $vLen = DllStructCreate('uint')
    	DllStructSetData($vLen, 1, FileGetSize($sFileName))
    	Local $vBytes = DllStructCreate('byte[' & DllStructGetData($vLen, 1) & ']')
    	DllStructSetData($vBytes, 1, FileRead($hFile))
    	FileClose($hFile)
    	$vData = _QOI_Decode($vBytes, $vHeader, $vLen)
    EndFunc
    
    #region INTERNAL
    
    Func __QOI_write_ui8($pBytes, ByRef $iPos, $ui8_value)
    	Local $v = DllStructCreate('byte v', $pBytes + $iPos)
    	$v.v = BitAND($ui8_value, 0x000000FF)
    	$iPos += 1
    EndFunc
    
    Func __QOI_put_ui8($pBytes, $iPos, $ui8_value)
    	Local $v = DllStructCreate('byte v', $pBytes + $iPos)
    	$v.v = BitAND($ui8_value, 0x000000FF)
    EndFunc
    
    Func __QOI_read_ui8($pBytes, ByRef $iPos)
    	Local $v = DllStructCreate('byte v', $pBytes + $iPos)
    	$iPos += 1
    	Return $v.v
    EndFunc
    
    Func __QOI_peek_ui8($pBytes, $iPos)
    	Local $v = DllStructCreate('byte v', $pBytes + $iPos)
    	Return $v.v
    EndFunc
    
    Func __QOI_write_ui32($pBytes, ByRef $iPos, $i32_value)
    	; Ist direkt aus C++ übersetzt und nicht für AutoIt optimiert!
    	; Da nacheinander geschrieben wird ist das endian safe (ist es bei AutoIt sowieso, da Windows only)
    	Local $v = DllStructCreate('byte v', $pBytes + $iPos)
    	$v.v = BitShift(BitAND($i32_value, 0xFF000000), 24)
    	$iPos += 1
    	$v = DllStructCreate('byte v', $pBytes + $iPos)
    	$v.v = BitShift(BitAND($i32_value, 0x00FF0000), 16)
    	$iPos += 1
    	$v = DllStructCreate('byte v', $pBytes + $iPos)
    	$v.v = BitShift(BitAND($i32_value, 0x0000FF00), 8)
    	$iPos += 1
    	$v = DllStructCreate('byte v', $pBytes + $iPos)
    	$v.v = BitAND($i32_value, 0x000000FF)
    	$iPos += 1
    EndFunc
    
    Func __QOI_read_ui32($pBytes, ByRef $iPos)
    	; Ist direkt aus C++ übersetzt und nicht für AutoIt optimiert!
    	; Da nacheinander gelesen wird ist das endian safe (ist es bei AutoIt sowieso, da Windows only)
    	Local $v = DllStructCreate('byte v', $pBytes + $iPos)
    	Local $a = $v.v
    	$iPos += 1
    	$v = DllStructCreate('byte v', $pBytes + $iPos)
    	Local $b = $v.v
    	$iPos += 1
    	$v = DllStructCreate('byte v', $pBytes + $iPos)
    	Local $c = $v.v
    	$iPos += 1
    	$v = DllStructCreate('byte v', $pBytes + $iPos)
    	Local $d = $v.v
    	$iPos += 1
    	Return BitOR(BitShift($a, -24), BitShift($b, -16), BitShift($c, -8), $d)
    EndFunc
    
    Func __QOI_Pixel()
    	Return DllStructCreate('byte r; byte g; byte b; byte a')
    EndFunc
    
    Func __QOI_PixelVal($r, $g, $b, $a)
    	Local $vPx = DllStructCreate('byte r; byte g; byte b; byte a')
    	$vPx.r = $r
    	$vPx.g = $g
    	$vPx.b = $b
    	$vPx.a = $a
    	Return $vPx
    EndFunc
    
    Func __QOI_i32At($vStruct)
    	Return DllStructCreate('uint v', DllStructGetPtr($vStruct))
    EndFunc
    
    Func __QOI_hash_ui32($vPx)
    	Return $vPx.r * 3 + $vPx.g * 5 + $vPx.b * 7 +$vPx.a * 11
    EndFunc
    
    #EndRegion INTERNAL
    Alles anzeigen

    Minimalbeispiel gibts im Anhang.

    Falls Fehler vorhanden sind, gerne hier posten bzw. Leute mit PU/Mod Rechten können für fixes auch einfach meinen Beitrag editieren 8)

    Spoiler anzeigen

    Edit: Habe mir noch ein paar Gedanken gemacht:

    Problem 1: QOI nutzt keine vertikale Ähnlichkeit von Pixeln aus.
    Potenzielle Lösung 1: Sortierte Quadtree Koordinaten (eine schnelle Methode wären z.B. Morton-Codes) statt Pixel mit x y Koordinaten.
    Erwartete Verbesserung: 5% - 30%

    Problem 2: QOI encodete Bilder sind nicht redundanzfrei und nicht musterfrei
    Potenzielle Lösung 2: Nachgeschaltetes (mini) LZSS + Nachgeschalteter (mini) Entropieencoder (mit "mini" meine ich Varianten die keine Zusatzdaten speichern, also keinen Header haben)
    Erwartete Verbesserung: 5% - 30%

    Wenn man beides macht schätze ich, dass man png in Bezug zur Kompressionsrate locker besiegen kann. (das wäre dann ohnehin sehr ähnlich zu png, wobei man darauf hofft, dass QOI hier im ersten Schritt besser performed als die Filter von png)

    lg

    M

    Dateien

    QOI_und_Minimalbeispiel.zip 235,23 kB – 86 Downloads
  • ArrayDisplayInternals - temp fix

    • Mars
    • 14. Juli 2025 um 23:14

    Vielleicht bin ich auch einfach der einzige der das Problem andauernd hat :D

    Ich verwende _ArrayDisplay oft in großen Schleifen zum debuggen und zum Beenden drücke ich dann auf das Tray-Icon (sonst müsste ich unmengen Array-Displays ansehen, oder eine alternative exit-Methode einbauen und dazu bin ich wohl zu faul :))

  • AutoIt-Hackathon #3 "alte Zeiten"

    • Mars
    • 11. Mai 2025 um 21:06
    AutoIt
    ; ================================= entferne alle Leer- und Kommentarzeilen und poste diesen Code-Block im Thread ==================================
    Func _IntegerToRoman($sInteger)
    	Local $Return
    	Local Static $M[], $K
    	If Not UBound($M) Then
    		$M[1] = 'I'
    		$M[5] = 'V'
    		$M[10] = 'X'
    		$M[50] = 'L'
    		$M[100] = 'C'
    		$M[500] = 'D'
    		$M[1000] = 'M'
    		$K = MapKeys($M)
    	EndIf
    	For $r = UBound($K) - 1 To 0 Step -1
    		While $sInteger >= $K[$r]
    			$Return &= $M[$K[$r]]
    			$sInteger -= $K[$r]
    		WEnd
    	Next
    	$Return = StringReplace($Return, 'IIII', 'IV')
    	$Return = StringReplace($Return, 'VIV' , 'IX')
    	$Return = StringReplace($Return, 'XXXX', 'XL')
    	$Return = StringReplace($Return, 'LXL' , 'XC')
    	$Return = StringReplace($Return, 'CCCC', 'CD')
    	$Return = StringReplace($Return, 'DCD' , 'CM')
    	Return $Return
    EndFunc   ;==>_IntegerToRoman
    Func _RomanToInteger($sRoman)
    	Local $Return
    	Local Static $M[], $K
    	If Not UBound($M) Then
    		$M['I'] = 1
    		$M['V'] = 5
    		$M['X'] = 10
    		$M['L'] = 50
    		$M['C'] = 100
    		$M['D'] = 500
    		$M['M'] = 1000
    		$K = MapKeys($M)
    	EndIf
    	$sRoman = StringReplace($sRoman, 'CM', 'DCD', 0, 1)
    	$sRoman = StringReplace($sRoman, 'CD', 'CCCC', 0, 1)
    	$sRoman = StringReplace($sRoman, 'XC', 'LXL', 0, 1)
    	$sRoman = StringReplace($sRoman, 'XL', 'XXXX', 0, 1)
    	$sRoman = StringReplace($sRoman, 'IX', 'VIV', 0, 1)
    	$sRoman = StringReplace($sRoman, 'IV', 'IIII', 0, 1)
    	For $c In StringSplit($sRoman, '', 2)
    		$Return += $M[$c]
    	Next
    	Return $Return
    EndFunc   ;==>_RomanToInteger
    
    ; Bonus-Aufgabe für Ambitionierte ;-)
    Func _DateToRoman($sDate) ;Input date in the format "YYYY/MM/DD[ HH:MM:SS]", Output in same date-format with roman sign
    	;If Not StringInStr($sDate, ' ', 0, 1) Then Return '' ; Das hier ist ein Joke. Natürlich muss diese Zeile weg :)
    	Local $Return, $aDate = StringSplit(StringReplace(StringReplace($sDate, ' ', ':', 0, 1), '/', ':', 0, 1), ':', 2)
    	For $i = 0 To UBound($aDate) - 1 Step 1
    		$Return &= _IntegerToRoman($aDate[$i]) & ($i < UBound($aDate) - 1 ? ($i < 2 ? '/' : $i = 2 ? ' ' : ':') : '')
    	Next
    	Return $Return
    EndFunc   ;==>_DateToRoman
    ; ================================= entferne alle Leer- und Kommentarzeilen und poste diesen Code-Block im Thread ==================================
    Alles anzeigen
  • AutoIt Hackathon #1 Mitarbeiter-ID abgeschlossen

    • Mars
    • 30. März 2025 um 21:44

    Das passiert, wenn man <Array.au3> nach _Check() included.

  • AutoIt Hackathon #1 Mitarbeiter-ID abgeschlossen

    • Mars
    • 30. März 2025 um 21:22

    Hinweis: Das ist die Lösung für die heruntergeladene Datei (die nur 14 Zeichen erfordert).

    AutoIt
    Func _CreateID($aUserdata)
    	Local $Return
    	$Return = StringLeft($aUserdata[2] & '99999', 5)
    	$Return &= StringLeft(StringRight(StringSplit($aUserdata[3], '.', 2)[2], 2), 1)
    	$Return &= StringRight('0' & StringSplit($aUserdata[3], '.', 2)[1] + 50 * ($aUserdata[4] = 'W'), 2)
    	$Return &= StringSplit($aUserdata[3], '.', 2)[0]
    	$Return &= StringRight(StringSplit($aUserdata[3], '.', 2)[2], 1)
    	$Return &= StringLeft($aUserdata[0], 1) & ($aUserdata[1] ? StringLeft($aUserdata[1], 1) : '9')
    	Local $q = 0, $a = StringSplit($Return, '', 2)
    	For $i = 0 To UBound($a) - 1 Step 1
    		$a[$i] = Asc($a[$i])
    	Next
    	While UBound($a) > 1
    		For $i = 0 To UBound($a) - 1 Step 1
    			$q += $a[$i]
    		Next
    		$a = StringSplit($q, '', 2)
    		$q = 0
    	WEnd
    	$Return &= $a[0]
    	Return $Return
    EndFunc
    Alles anzeigen
  • PackedIntegers (miniudf)

    • Mars
    • 2. März 2025 um 14:59

    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.

    AutoIt: PackedIntegers.au3
    __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

  • Code Kata - Christmas Tree

    • Mars
    • 19. Dezember 2024 um 17:39
    Zitat von chesstiger

    Wer online testen möchte: https://gc.de/gc/brainfuck/

    Hat mich jetzt knappe 3 Stunden gekostet, das zu entwerfen. ^^

    Das erste Element auf dem Stack ist nebenbei die gesamte Baumhöhe. Heißt kurz gesagt, für jedes + was man der Baumspitze hinzufügt, wird der generierte Baum eine Ebene höher.

    Hat er nicht gemacht.... Das ist ja der Wahnsinn :D

  • Code Kata - Christmas Tree

    • Mars
    • 17. Dezember 2024 um 14:53

    Die Idee mit der Animation ist gar nicht mal so schlecht. Hoffentlich vergesse ich das nicht bis nächstes Jahr ^^

  • Code Kata - Christmas Tree

    • Mars
    • 16. Dezember 2024 um 22:31

    Neues Jahr, neuer Weihnachtsbaum!

    (Entspricht nicht den Vorgaben, aber ich wollte einfach Basteln)

    AutoIt
    P(15)
    
    Func P($h, $_ = Default)
    	If $_ <> Default Then
    		If $_ > 0 Then
    			Local $1 = $h = '.' ? '' : $h, $a = ['.', '.', ' ', '*', 'O'], $o = False
    			For $i = 0 To $_ - 2 Step 1
    				$h &= $1 ? $1 : $a[Random(0, UBound($a)-1-(StringInStr($h, 'O', 0, 1)?1:0), 1)]
    			Next
    			Return $h
    		Else
    			Return ''
    		EndIf
    	EndIf
    	Local $w = Int($h / 2) * 2 + 1, $r = 1, $s = '', $l = False, $k, $p
    	For $y = 0 To $h - 1 Step 1
    		$s &= ($y = 0 ? (P(' ', Int($w / 2 + 1)) & '*') : ($y < $h - 1) ? (P(' ', Int(($w - $r)/2) - 0) & '/' & P('.', $r) & '\') : ((($p/2 < $r/2 ? ' ' : '') & P('^', $p/2) & '[_]' & P('^', $p/2)))) & @CRLF
    		If Not ($y < $h - 1 And $y > 0) Then ContinueLoop
    		$p = $r
    		$k = ($h - $y - 2) > (($w - $r) / 2) And Not $l
    		$l = $k ? Random() > 0.5 : False
    		$r += $k ? (Not ($l And $y > 2) ? ((Random() > 0.5 ? 2 : ($r < $w / 2 ? 2 : ($y > 3 ? -2 : 2)))) : 0) : 2
    		$r = $r - 2 * ($r > $w)
    	Next
    	ConsoleWrite($s & @CRLF)
    EndFunc
    Alles anzeigen

    lg

    M

  • Persönliche Weiterbildung bzgl. IT, Programmierung und Co.

    • Mars
    • 23. Oktober 2024 um 19:28

    1. Meine Weiterbildung erfolgt meistens privat durch "irgendwelche Sachen die ich sehe" und durch "herumbasteln". Das macht sich natürlich auf dem Papier nicht gut, daher bekomme ich alle Halbjahr irgendeine Weiterbildung gesponsort (ist immer Themenbezogen).

    Trends sind mir persönlich vollkommen egal, ich mache was ich für richtig halte. Da ich aktuell am C++ lernen bin (bzw. es seit ~5 Jahren aktiv nutze, aber man lernt ja nie aus), will ich das erst "perfektionieren" bevor irgendwas anderes um die Ecke kommt. Sowas wie z.B. Rust gefällt mir überhaupt nicht, da es sich anfühlt als würde man mit angezogener Handbremse programmieren. Den "Mit Rust konnte ich meine alten Projekte 3x so schnell neu implementieren" Bias halte ich ebenfalls für lächerlich. Ja, wenn ich ein altes Projekt erneut programmiere, dann bin ich 3x so schnell, selbst wenn ich die Sprache nicht wechsele. Aber gut, das ist Ansichtssache. Jeder soll machen was er für richtig hält.

    2. Ich habe noch keine dollen Papers geschrieben, bin aber gerade dabei. Das scheint wohl gern gesehen zu sein, und da ich soweiso eine Quatschtüte bin ist das kein Problem auch mal ein paar "ordentliche" Sachen zu schreiben. Insgesamt halte ich aber das publizieren für gnadenlos überbewertet. Ja, es ist wichtig neuen Kram für die Welt zugänglich aufzuschreiben, sodass sich das Wissen verbreiten kann. Finde den Fehler im vorherigen Satz. "Für die Welt zugänglich", war der Fehler, da alles was ich "ordentlich" schreibe hinter einer Paywall landen wird (außer auf den sieben Weltmeeren, die ich in diesem Bezug tatsächlich empfehlen kann).
    Wenn es nach mir ginge, gäbe es ein weltweites community moderiertes "Wissenschafts Wikipedia" bei dem eben nur Profs bzw. "Leute aus der Forschung an einer Bildungs/Forschungseinrichtung" Schreibrechte, aber jeder auf der ganzen Welt Leserechte besitzt. Möchte man etwas veröffentlichen muss man sich an jemanden vom Fach wenden. Damit wird direkt 90% Unfug (der sich auch in aktuellen Veröffentlichungen wiederfindet) herausgefiltert. Außerdem kann man "in diesem Wiki" eine Analyse machen ob das eigene Thema dort schon vorhanden ist. (Such mal 50 Journals/Konferenzen weltweit über die letzten 50 Jahre nach etwas durch was du erfunden/gefunden hast. Viel Spaß. Die Wahrscheinlichkeit ist 95%, dass du es nicht findest, selbst wenn es schonmal irgendwo aufgetaucht ist. Vielleicht falsche Keywords? Vielleicht falsche Sprache? etc.). Falls ja (Thema existiert bereits), dann bekommt man schreibrechte für den dazugehörigen Artikel für eventuelle Ergänzungen, falls nein (Thema ist neu bzw. transformativ), dann bekommt man einen eigenen Artikel. Ein super Nebeneffekt sind "Verlinkungen" die es zwar auch jetzt schon gibt [Mar24], mit der unfassbar altertümlichen Methode ([...] verweist auf einen Text der im Anhang steht, den ich googeln muss um das dazugehörige Paper zu finden was ich dann lesen muss um herauszufinden welche Stelle überhaupt zitiert wurde) bin ich aber auf Kriegsfuß. Wie schön wäre es, wenn ich [Mar24] anklicke und in einer Sekunde bin ich im richtigen Artikel in der richtigen Zeile um nachzulesen wo etwas herkommt... Das wird es leider niemals geben, zumindest nicht mehr in meiner Lebenszeit.

    Aber gut, damit kann niemand Geld verdienen, und Wissen wäre ein Grundrecht. So eine Welt haben wir halt nicht.

    Over and Out :D

    M

  • Select Cas in einem Intervall

    • Mars
    • 18. September 2024 um 12:21

    Es bringt halt leider auch Granaten wie das Folgende:

    Halbe Seite Text

    Dauert also noch etwas bis wir ersetzt werden :D

    (Bei der Frage habe ich implizit gehofft, dass mein Thread aus dem PU-Bereich gelesen wurde. Da ist ein Beispiel wie man die Pointer von (Globalen) AutoIt-Variablen durch ein paar Tricks herausbekommen kann)

    lg

    M

  • Select Cas in einem Intervall

    • Mars
    • 18. September 2024 um 11:49

    Einfach aus Jux habe ich die Frage mal in die KI gefüttert, und siehe da, der Code ist technisch gesehen korrigiert worden.

    Irgendwann werden wir als Supporter überflüssig, es ist nur noch eine Frage der Zeit :)

    Edit: Habe noch nachgefragt, ob man an dem Code noch etwas ändern könnte, und tatsächlich, das zweimalige Verwenden von "left" wurde als potenzieller Fehler markiert.

    lg

    M

  • Ungefähre Funktionswerte Puffern

    • Mars
    • 1. Juli 2024 um 22:31

    Moin,

    wer kennt es nicht. Man hat eine Funktion die irgendetwas stochastisch berechnet (Monte-Carlo) und relativ lange braucht.

    Diese Funktion möchte man aber im Idealfall "oft" aufrufen (ggf. in einer anderen Funktion, die ebenfalls stochastisch arbeitet, usw usw). Im Endeffekt resultiert das in Abermillionen von Funktionsaufrufen, die sehr schnell sehr viel Zeit in Anspruch nehmen.

    Aber es gibt Abhilfe: Ein sich selbst füllender Puffer der Funktionswerte an einigen Stützstellen speichert und dann linear interpoliert (mit Unsicherheitsangabe).

    Vermutlich habe ich darin noch ein Paar Bugs versteckt, aber für meine bisherigen Anwendungsfälle hat es funktioniert, daher gibts jetzt ne "mini-UDF". Wie bei allen Methoden ist es wichtig "sinnvolle" Parameter zu wählen, ansonsten läuft sich der Algorithmus tot (mit Failsave -> MaxIter) oder produziert vollkommen falsche Ergebnisse (z.B. wenn man nur 10 Stützstellen verwendet, obwohl man eigentlich mindestens 100 braucht, oder wenn man eine Genauigkeit von 0.01 haben möchte, obwohl die Funktionswerte die Größenordnung 100 und eine große Streuung haben). Was die Ungenauigkeitsangabe im Returnwert angeht möchte ich meine Hand nicht ins Feuer legen. Da sich der Mittelwert ja mit jedem neuen Sample ändert und die vorherigen Varianzen nicht angepasst werden können (man will ja nicht "alles" speichern) ist dieser Wert nur "ungefähr richtig".

    Die Verwendung ist glaube ich intuitiv ersichtlich wenn man das Beispiel anschaut. FFB heißt "FuzzyFunctionBuffer"

    AutoIt
    Global Const $__FFB_MIN_SAMPLES = 17
    
    ; Beispielfunktion mit langer Rechenzeit die "nicht genau" arbeitet:
    ; Stochastisches abschätzen vom Volumen einer Kugel mir Radius $r
    Func myFunc($r)
    	Local Const $k = 1000
    	Local $n = 0, $r2 = $r ^ 2
    	For $i = 0 To $k - 1 Step 1
    		$n += Random(-$r, $r) ^ 2 + Random(-$r, $r) ^ 2 + Random(-$r, $r) ^ 2 < $r2
    	Next
    	Return $n / $k * (2 * $r) ^ 3
    EndFunc   ;==>myFunc
    
    ; Naiver Ansatz:
    ; Einfach Mittelwert bilden über N Versuche (hier mit N = 100)
    ; Probleme:
    ; - Wie genau ist das denn jetzt?
    ; - Wenn ich die Funktionswerte mehrfach brauche muss ich mich selbst um das Puffern kümmern.
    ; - Wenn ich "ähnliche" Funktionswerte brauche muss die Funktion komplett neu ausgewertet werden.
    Local $t = TimerInit()
    For $i = 80 To 90 Step 1
    	Local $v = 0
    	For $j = 0 To 99 Step 1
    		$v += myFunc($i / 100)
    	Next
    	$v /= 100
    	ConsoleWrite('r = ' & StringFormat('% 5.3f', $i / 100) & ' -> Vol = ' & StringFormat('% 6.4f', $v) & ' err = ' & StringFormat('% 6.4f', $v-4/3*(($i/100)^3)*3.141592654) & @CRLF)
    Next
    ConsoleWrite('Time: ' & TimerDiff($t) & @CRLF)
    ConsoleWrite(@CRLF)
    
    ;~ ; Ansatz mit Lookup-Table & linearer Interpolation
    Local $FFB = _FFB_Create1D(myFunc, 0, 5, 100)
    Local $t = TimerInit()
    For $i = 80 To 90 Step 1
    	Local $v = _FFB_Call1D($FFB, $i / 100, 0.01)
    	ConsoleWrite('r = ' & StringFormat('% 5.3f', $i / 100) & ' -> Vol = ' & StringFormat('% 6.4f +- % 6.4f', $v[0], $v[1]) & ' err = ' & StringFormat('% 6.4f', $v[0] - 4 / 3 * (($i / 100) ^ 3) * 3.141592654) & @CRLF)
    Next
    ConsoleWrite('Time: ' & TimerDiff($t) & @CRLF)
    ConsoleWrite(@CRLF)
    
    ; Der Trick ist jetzt, dass der LUT jetzt aufgebaut ist. Braucht man die Funktionswerte erneut ist das relativ schnell
    ; Auch für Funktionswerte die nicht "exakt" da liegen wo man schonmal gesampled hat. Je mehr sich der LUT füllt, desto schneller wird er.
    Local $t = TimerInit()
    For $i = 80 To 90 Step 1
    	Local $x = $i / 100 + Random(-0.05, 0.05)
    	Local $v = _FFB_Call1D($FFB, $x, 0.01)
    	ConsoleWrite('r = ' & StringFormat('% 5.3f', $x) & ' -> Vol = ' & StringFormat('% 6.4f +- % 6.4f', $v[0], $v[1]) & ' err = ' & StringFormat('% 6.4f', $v[0] - 4 / 3 * ($x ^ 3) * 3.141592654) & @CRLF)
    Next
    ConsoleWrite('Time: ' & TimerDiff($t) & @CRLF)
    ConsoleWrite(@CRLF)
    
    Func _FFB_Call1D(ByRef $FFB, $x, $nAccuracy = 0.01, $iIterMax = 100)
    	Local $iSteps = UBound($FFB) - 1
    	Local $k = ($x - $FFB[$iSteps][1]) / $FFB[$iSteps][2] * ($iSteps - 1)
    	Local $i = Int($k), $ix = ($i / ($iSteps - 1) * $FFB[$iSteps][2] + $FFB[$iSteps][1]) ; Unterer Slot
    	Local $j = $i + 1, $jx = ($j / ($iSteps - 1) * $FFB[$iSteps][2] + $FFB[$iSteps][1]) ; Oberer Slot
    	Local $alpha = $k - $i ; $alpha = Prozentsatz vom darüberliegenden Slot
    	Local $f = $FFB[$iSteps][0], $v = 0, $t = 0
    
    	If $i >= 0 And $i < $iSteps Then
    		If $FFB[$i][2] < $__FFB_MIN_SAMPLES Then
    			Local $p[]
    			For $_ = 0 To $__FFB_MIN_SAMPLES - 1 Step 1
    				$p[$_] = $f($ix)
    				$FFB[$i][0] += $p[$_]
    			Next
    			$FFB[$i][0] /= $__FFB_MIN_SAMPLES
    			For $_ = 0 To $__FFB_MIN_SAMPLES - 1 Step 1
    				$FFB[$i][1] += ($p[$_] - $FFB[$i][0]) ^ 2
    			Next
    			$FFB[$i][2] = $__FFB_MIN_SAMPLES
    		EndIf
    		$t = 0
    		While Sqrt($FFB[$i][1]) / ($FFB[$i][2] - 1) > $nAccuracy
    			$v = $f($ix)
    			$FFB[$i][0] = ($FFB[$i][0] * $FFB[$i][2] + $v) / ($FFB[$i][2] + 1)
    			$FFB[$i][1] += ($v - $FFB[$i][0]) ^ 2
    			$FFB[$i][2] += 1
    			$t += 1
    			If $t >= $iIterMax Then ExitLoop
    		WEnd
    	EndIf
    
    	If $j >= 0 And $j < $iSteps Then
    		If $FFB[$j][2] < $__FFB_MIN_SAMPLES Then
    			Local $p[]
    			For $_ = 0 To $__FFB_MIN_SAMPLES - 1 Step 1
    				$p[$_] = $f($jx)
    				$FFB[$j][0] += $p[$_]
    			Next
    			$FFB[$j][0] /= $__FFB_MIN_SAMPLES
    			For $_ = 0 To $__FFB_MIN_SAMPLES - 1 Step 1
    				$FFB[$j][1] += ($p[$_] - $FFB[$j][0]) ^ 2
    			Next
    			$FFB[$j][2] = $__FFB_MIN_SAMPLES
    		EndIf
    		$t = 0
    		While Sqrt($FFB[$j][1]) / ($FFB[$j][2] - 1) > $nAccuracy
    			$v = $f($jx)
    			$FFB[$j][0] = ($FFB[$j][0] * $FFB[$j][2] + $v) / ($FFB[$j][2] + 1)
    			$FFB[$j][1] += ($v - $FFB[$j][0]) ^ 2
    			$FFB[$j][2] += 1
    			$t += 1
    			If $t >= $iIterMax Then ExitLoop
    		WEnd
    	EndIf
    
    	Local $Ret[]
    	If Abs($alpha) < 1E-3 Then
    		$Ret[0] = $FFB[$i][0]
    		$Ret[1] = Sqrt($FFB[$i][1] / ($FFB[$i][2] - 1))
    	ElseIf Abs($alpha - 1) < 1E-3 Then
    		$Ret[0] = $FFB[$j][0]
    		$Ret[1] = Sqrt($FFB[$j][1] / ($FFB[$j][2] - 1))
    	Else
    		$Ret[0] = $FFB[$i][0] * (1 - $alpha) + $FFB[$j][0] * $alpha
    		$Ret[1] = (Sqrt($FFB[$i][1]) / ($FFB[$i][2] - 1)) * (1 - $alpha) + (Sqrt($FFB[$j][1]) / ($FFB[$j][2] - 1)) * $alpha
    	EndIf
    
    	Return $Ret ; [0] = Wert, [1] = Unsicherheit
    
    EndFunc   ;==>_FFB_Call1D
    
    Func _FFB_Create1D($xFunc, $fMinInclusive = 0, $fMaxInclusive = 1, $iSteps = 100)
    	Local $_[$iSteps + 1][3]
    	$_[$iSteps][0] = $xFunc
    	$_[$iSteps][1] = $fMinInclusive
    	$_[$iSteps][2] = $fMaxInclusive - $fMinInclusive
    	; [0] = Mittelwert
    	; [1] = VarianzSumme
    	; [2] = NumSamples
    	Return $_
    EndFunc   ;==>_FFB_Create1D
    Alles anzeigen


    Edit: Hier noch eine Überarbeitung mit quadratischer Interpolation (so kann man den LUT etwas kleiner wählen, oder man möchte eine sehr weiche Kurve. Die gab es bei der linearen Version nicht).

    AutoIt
    #include <Array.au3>
    
    Global Const $__FFB_MIN_SAMPLES = 17
    Global Const $__FFB_NUM_MAXITER = 100
    
    ; Anwendungsfall: Funktionswerte entstören
    Func myFunc($r)
    	Return Sin($r) + Random() / 3 ; sin ist im Bereich -1 bis 1, mit 1/3 plusminus rauschen ist das schon ziemlich viel.
    EndFunc   ;==>myFunc
    
    Local $FFB = _FFB_Create1D(myFunc, -10, 10, 100) ; Hat 100 Slots zwischen -10 und 10
    For $i In __FFB_Range('[', -3.141, 3.141, ']', 200) ; Die 200 Samples brauchen nur ca. 33 Slots. Durch die quadratische Interpolation kommt trotzdem eine gute Kurve heraus.
    	Local $v = _FFB_Call1D($FFB, $i[1], 0.0005, 1e9, 100000) ; Wenn man es wirklich ganz genau haben will. (0.0005 Sigma, da will man schon 3 richtige Nachkommastellen haben)
    	ConsoleWrite(StringFormat('% 5.3f', $i[1]) & ', ' & StringFormat('% 6.4f', $v[0])  & @CRLF)
    Next
    _ArrayDisplay($FFB) ; Nachschauen was im LUT eigentlich drin steht.
    
    Func _FFB_Train1D(ByRef $FFB, $nAbsAccuracy = 1e9, $nRelAccuracy = 1e9)
    	Local $iSteps = UBound($FFB) - 1
    	Local $fMin = $FFB[$iSteps][1]
    	Local $fMax = $FFB[$iSteps][2] + $FFB[$iSteps][1]
    	Local $bTargetMet = True, $v = 0
    	Do
    		$bTargetMet = True
    		For $i In __FFB_Range('[', $fMin, $fMax, ']', $iSteps)
    			$v = _FFB_Call1D($FFB, $i[1], $nAbsAccuracy, $nRelAccuracy)
    			If $v[1] > $nAbsAccuracy Then $bTargetMet = False
    			If $v[0] > 1E-9 And $v[1] / $v[0] > $nRelAccuracy Then $bTargetMet = False
    		Next
    	Until $bTargetMet
    EndFunc   ;==>_FFB_Train1D
    
    Func _FFB_Call1D(ByRef $FFB, $x, $nAbsAccuracy = 1e9, $nRelAccuracy = 1e9, $iIterMax = $__FFB_NUM_MAXITER, $bQuadraticInterpolation = True)
    	Local $iSteps = UBound($FFB) - 1, $s5 = $iSteps - 5, $s5d = $s5 / $FFB[$iSteps][2]
    	Local $k = ($x - $FFB[$iSteps][1]) * $s5d + 2, $ik = Int($k) ; Slots: [ik-1, ik, ik+1, ik+2] <- diese 4 sind immer vorhanden.
    	Local $alpha = $k - $ik ; $alpha = Prozentsatz vom darüberliegenden Slot
    	Local $f = $FFB[$iSteps][0], $v = 0, $t = 0
    	For $i = $ik - 1 To $ik + 2 Step 1 ; from -1 to 2 -> Für 4 Slots.
    		Local $ix = ($i - 2) / $s5d + $FFB[$iSteps][1]
    		If $FFB[$i][2] < $__FFB_MIN_SAMPLES Then
    			Local $p[]
    			For $_ = 0 To $__FFB_MIN_SAMPLES - 1 Step 1
    				$p[$_] = $f($ix)
    				$FFB[$i][0] += $p[$_]
    			Next
    			$FFB[$i][0] /= $__FFB_MIN_SAMPLES
    			For $_ = 0 To $__FFB_MIN_SAMPLES - 1 Step 1
    				$FFB[$i][1] += ($p[$_] - $FFB[$i][0]) ^ 2
    			Next
    			$FFB[$i][2] = $__FFB_MIN_SAMPLES
    		EndIf
    		$t = 0
    		While Sqrt($FFB[$i][1]) / ($FFB[$i][2] - 1) > $nAbsAccuracy Or ($FFB[$i][0] > 1E-9 And Sqrt($FFB[$i][1]) / ($FFB[$i][2] - 1) / $FFB[$i][0] > $nRelAccuracy)
    			$v = $f($ix)
    			$FFB[$i][0] = ($FFB[$i][0] * $FFB[$i][2] + $v) / ($FFB[$i][2] + 1)
    			$FFB[$i][1] += ($v - $FFB[$i][0]) ^ 2
    			$FFB[$i][2] += 1
    			$t += 1
    			If $t >= $iIterMax Then ExitLoop
    		WEnd
    	Next
    	Local $Ret[]
    	If $bQuadraticInterpolation Then
    		Local $ixa = ($ik - 3) / $s5d + $FFB[$iSteps][1], $ixb = ($ik - 2) / $s5d + $FFB[$iSteps][1], $ixc = ($ik - 1) / $s5d + $FFB[$iSteps][1], $ixd = $ik / $s5d + $FFB[$iSteps][1]
    		Local $P3L = __FFB_Func3P($ixa, $FFB[$ik - 1][0], $ixb, $FFB[$ik - 0][0], $ixc, $FFB[$ik + 1][0])
    		Local $P3H = __FFB_Func3P($ixb, $FFB[$ik - 0][0], $ixc, $FFB[$ik + 1][0], $ixd, $FFB[$ik + 2][0])
    		$Ret[0] = ($P3L[0] * $x^2 + $P3L[1] * $x + $P3L[2]) * (1 - $alpha) + ($P3H[0] * $x^2 + $P3H[1] * $x + $P3H[2]) * $alpha
    	Else
    		$Ret[0] = $FFB[$ik][0] * (1 - $alpha) + $FFB[$ik + 1][0] * $alpha
    	EndIf
    	$Ret[1] = (Sqrt($FFB[$ik][1]) / ($FFB[$ik][2] - 1)) * (1 - $alpha) + (Sqrt($FFB[$ik + 1][1]) / ($FFB[$ik + 1][2] - 1)) * $alpha
    	Return $Ret ; [0] = Wert, [1] = Unsicherheit
    EndFunc   ;==>_FFB_Call1D
    
    Func _FFB_Create1D($xFunc, $fMinInclusive = 0, $fMaxInclusive = 1, $iSteps = 100, $nBorderEpsilon = 1E-6)
    	$fMinInclusive -= $nBorderEpsilon
    	$fMaxInclusive += $nBorderEpsilon
    	Local $_[$iSteps + 1][3]
    	$_[$iSteps][0] = $xFunc
    	$_[$iSteps][1] = $fMinInclusive
    	$_[$iSteps][2] = $fMaxInclusive - $fMinInclusive
    	; [i][0] = Mittelwert
    	; [i][1] = VarianzSumme
    	; [i][2] = NumSamples
    	Return $_
    EndFunc   ;==>_FFB_Create1D
    
    Func __FFB_Range($sLeft = '[', $fMin = 0, $fMax = 1, $sRight = ']', $iSteps = 10)
    	Local $a[$iSteps], $_[2], $l = $sLeft = '[' ? 0 : 1, $s = ($fMax - $fMin) / ($iSteps - 1 + ($sRight = ']' ? 0 : 1) + $l)
    	For $i = 0 To $iSteps - 1 Step 1
    		$_[0] = $i
    		$_[1] = ($i + $l) * $s + $fMin
    		$a[$i] = $_
    	Next
    	Return $a
    EndFunc   ;==>__FFB_Range
    
    Func __FFB_Func2P($x0, $y0, $x1, $y1)
    	Local $_[] ; f(x) = ax + b
    	$_[0] = ($y1 - $y0) / ($x1 - $x0)
    	$_[1] = $y0 - $_[0] * $x0
    	Return $_
    EndFunc
    
    Func __FFB_Func3P($x0, $y0, $x1, $y1, $x2, $y2)
    	Local $_[] ; f(x) = ax² + bx + c
    	$_[0] = ($x2 * ($y1 - $y0) + $x1 * ($y0 - $y2) + $x0 * ($y2 - $y1)) / (($x0 - $x1) * ($x0 - $x2) * ($x1 - $x2)) ; a
    	$_[1] = (($y1 - $y0) + $_[0] * ($x0 ^ 2 - $x1 ^ 2)) / ($x1 - $x0) ; b
    	$_[2] = $y0 - $_[0] * $x0 ^ 2 - $_[1] * $x0 ; c
    	Return $_
    EndFunc
    Alles anzeigen


    lg

    M

  • RAM-Typ auslesen

    • Mars
    • 25. Juni 2024 um 17:12
    Zitat von water

    In der deutschen Übersetzung fälschlich "Blitz"

    Jedes Mal, wenn ich auf der MS Seite etwas nachschlage und diese furchtbaren deutschen Übersetzungen (teilweise von Naturkonstanten wie "BLACKNESS" beim BitBlt) sehe, klicke ich "diese Seite war nicht hilfreich" an und schreibe in den Kommentar rein, dass sämtliche Wörter die mit Programmcode zu tun haben bitte nicht übersetzt werden sollen. Ich hab schon Tabellen mit Enums gesehen die man von Start bis Ende in die Tonne treten konnte weil fast alle Bezeichnungen falsch waren X/

    Ist denen aber egal. Wenn ich nicht 90% der Namen von Sachen die ich dort suche schonmal gehört hätte wäre ich echt sauer, aus genanntem Grund bin ich nur "genervt" von sowas...

    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™