Eigener Zufallsalgorhythmus - Fertig

  • Jemand hat gerade in der SB von Random gesprochen, da musste ich doch mal eine eigene Zufallsfunktion schreiben.

    Was macht se'? Sie erzeugt willkürliche Zahlen. Die Zufälligkeit (geiles Wort), Minimal, Maximal und obs eine Ganzzahl sein soll lässt sich einstellen.
    Als Basis für die Rechnung wird übrigens die Ungenauigkeit des "Sleep" Befehls benutzt :)

    Mit Beispiel.

    Spoiler anzeigen
    [autoit]

    ConsoleWrite(_random(2000, 10, 10000000, 1)&@CRLF)

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

    ; Funktion: _random($i)
    ; Beschreibung: Erzeugt eine Zufallszahl nach einer simplen Rechnung
    ; Paramter $i: Wie viele Iterationen soll die Rechnung haben (min. 5!)
    ; $min: Zufallszahl von MINIMAL bis maximal
    ; $max: Zufallszahl von minimal bis MAXIMAL
    ; $int: Wenn 1 dann wird eine ganze Zahl zurückgegeben
    ; Erfolg: Zufallszahl wird zurückgegeben
    ; Fehler: @error = 1 und Rückgabe von -1
    ; Autor: campweb

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

    Func _random($e, $min, $max, $int)
    SetError(0)
    If $e <= 5 Then
    SetError(1)
    Return -1
    Else
    $Zahl_Alt = natural()/2
    $Zahl = natural()
    $Iter = $e

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

    For $i = 1 to $Iter
    $1 = ($Zahl/$Zahl_Alt) * 23
    $2 = 10^8
    $3 = 1
    $Zahl = (Mod($1, ($2+$3)))
    If $i > $Iter-1 Then
    If $Zahl < $min Then
    Do
    $Zahl = $Zahl*4.123456789
    Until $Zahl > $min And $Zahl < $max
    If $int = 1 Then
    Return Int($Zahl)
    Else
    Return $Zahl
    EndIf
    ElseIf $Zahl > $max Then
    Do
    $Zahl = $Zahl/4.123456789
    Until $Zahl < $max And $Zahl > $min
    If $int = 1 Then
    Return Int($Zahl)
    Else
    Return $Zahl
    EndIf
    Else
    SetError(1)
    Return -1
    EndIf
    EndIf
    Next
    EndIf
    EndFunc

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

    Func natural()
    $1 = TimerInit()
    Sleep(1)
    $2 = TimerDiff($1)
    Return $2
    EndFunc

    [/autoit]

    MfG, campweb

    3 Mal editiert, zuletzt von campweb (29. Juni 2011 um 19:32)

  • Hmm... Naja ist nicht schlecht, aber ich fänds gut wenn man noch einstellen könnte dass nur ganze zahlen ausgegeben werden!
    DFPWare


    das kann man doch ganz leicht mit

    [autoit]

    int

    [/autoit]

    selbst machen..

    "Je mehr Käse, desto mehr Löcher; je mehr Löcher, desto weniger Käse. Ergo: Je mehr Käse, desto weniger Käse. 8| "
    "Programmers never die: they just GOSUB without RETURN"
    "I tried to change the world but I couldn't find the source code."

  • Hmm... Naja ist nicht schlecht, aber ich fänds gut wenn man noch einstellen könnte dass nur ganze zahlen ausgegeben werden!
    DFPWare


    Ist als Funktionsparameter ergänzt!

    MfG, campweb

  • Hast du auch mal die Qualität der "Zufälligkeit" überprüft?
    Ich habe mir mal mit folgenden Skript mit deiner Funktion 10.000 zufällige Werte zwischen 0 und 100 erstellt:

    [autoit]

    For $i = 1 To 10000
    ConsoleWrite _random(1000, 0, 100) & @CRLF
    Next

    [/autoit]


    Bei gutem Verhalten der Funktion sollte eine Gleichverteilung herauskommen.
    Das Ergebnis für deine Funktion:
    autoit.de/wcf/attachment/13647/
    Ich denke auf einen Chi²-Test kann man hier schnell verzichten da schon visuell erkennbar ist das das Verhalten nicht optimal ist.
    Zum Vergleich mal das Verhalten der in AutoIt eingebauten Funktion Random():
    autoit.de/wcf/attachment/13648/

  • Hallo?!

    Klar das das nicht perfekt ist! Ist ja nur ein ganz simples Skript...
    Die Iterartion verfälscht das Ergebnis, aber hauptsächlich ist dein Computer daran schuld, da die Sleep-Abweichung eigentlich immer in eine richtung abweicht, sicherlich könnte man auch z.B. das Rauschen der SOundkarte nehmen, aber es soll ja simpel sein.

    MfG, campweb

    • Offizieller Beitrag

    Hallo?!

    Klar das das nicht perfekt ist! Ist ja nur ein ganz simples Skript...


    Warum reagierst du so angepißt? AspirinJunkie hat völlig nüchtern deine Random-Funktion mit der aus AutoIt verglichen unter Berücksichtigung der Tatsache, dass eine Gleichverteilung Voraussetzung für ein gutes Funktionieren ist. Bei deiner ist dies nicht der Fall und somit ist sie zum eigentlichen Zweck nicht effektiv verwendbar.
    Vielleicht kannst du das ja als Anreiz sehen, deine Lösung dahingehend zu verbessern? ;)

    • Offizieller Beitrag

    Ein Zufallszahlen-Algorithmus sollte bei einer großen Anzahl an zufällig ausgewählten Zahlen eine möglichst gleichmäßige Häufigkeitsverteilung erreichen.
    Das heißt: wenn man die Funktion 10000 mal aufruft und jedes Mal eine Zahl zwischen 0 und 9 generieren lässt sollte am Ende jede Zahl ungefähr 1000 mal vorhanden sein.
    Wenn das nicht gegeben ist, dann bevorzugt die Funktion einen bestimmten Zahlenbereich, was für viele Anwendungsgebiete schlecht ist.

  • Um wirklich zufällige Zahlen zu erhalten muss für jede mögliche zu erhaltene Zahl die gleiche Wahrscheinlichkeit herrschen sie zu bekommen wie bei jeder anderen Zahl.

    Bestes Beispiel: Würfel.
    Jede Seite sollte bei einem richtigen Würfel die selbe Wahrscheinlichkeit besitzen gewürfelt zu werden.
    Wenn man nun z.B. 1000x würfelt sollte jede Zahl grob gleich oft vorgekommen sein wie die anderen Zahlen (Gleichverteilung).
    Wäre das nicht der Fall (z.B. die 5 ist doppelt so oft gefallen wie die anderen Zahlen) herrscht keine Gleichverteilung -> der Würfel ist entweder kaputt oder gezinkt.

    Hier ist das nicht anders.
    Die Funktion ist nichts weiter als eine Art Würfel mit halt allen Zahlen im festgelegten Bereich.
    Wenn die Funktion korrekt zufällig arbeitet sollte Gleichverteilung herrschen - das war die zu prüfende Frage.

    Ohne dich jetzt weiter verwirren zu wollen.
    Zufallszahlen müssen nicht gleichverteilt sein.
    Es können ganz andere Verteilungsarten vorherrschen.
    Im Fall des Würfels handelt es sich aber um eine Gleichverteilung.
    Eine andere sehr bekannte Verteilungsart welche z.B. Messfehler bei Messinstrumenten annehmen ist die Gaußsche Normalverteilung (zumindestens näherungsweise).

  • Ich habe mich mal daran versucht ein Skript zu machen, was diese Auswertungen macht.
    Ganz glücklich bin ich nicht, aber immerhin geht es einigermaßen...

    Damit konnte ich gleich meinen (Pseudo)Zufallsgenerator (den ich iwo im Netz gefunden habe. Ich weiß aber nicht mehr wo...^^) testen.

    Spoiler anzeigen
    [autoit]


    #include <Array.au3>
    #include <GDIPlus.au3>

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

    Global $GDI32_DLL = DllOpen('gdi32.dll')
    _GDIPlus_Startup()

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

    #cs
    _RandomAuswertung(Min, Max, Durchläufe, Absolut, Array anzeigen, Breite, Höhe)
    Absolut: Wenn False --> Es wird der Unterste Zufallswert als 0 benutzt
    Sonst --> Der Unterste Wert ist 0
    #ce

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

    If _RandomAuswertung(0, 100, 10000, False, False, 700, 500) = -1 Then
    ToolTip('Die Randomfunktion erfüllt die Anforderungen nicht.')
    Sleep(3000)
    EndIf

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

    _GDIPlus_Shutdown()
    DllClose($GDI32_DLL)

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

    Func _Random($Min, $Max)

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

    ;##### Der wird für Perlinberechnungen bei mir genutzt :P
    ;~ Local $Ret = 0
    ;~ Local Static $Nummer = @MSEC
    ;~ $Ret = _Zufall($Nummer) * ($Max-$Min) + $Min
    ;#####

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

    ;#####
    ;~ Local $Ret = StringRight(__random(1000, $Min, $Max, 0), 5)/99999 * ($Max-$Min) + $Min
    ;#####

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

    ;##### Der Hauseigene Apparat
    Local $Ret = Random($Min, $Max)
    ;#####

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

    ConsoleWrite($Ret & @CRLF)
    Return $Ret
    EndFunc ;==>_Random

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

    Func _Zufall(ByRef $Z) ; Eine Pseudo Zufallszahl wird generiert.
    $Z = Mod((7141 * $Z + 54773), 259200)
    Return $Z / 259200 ; Ein Kommawert zw 0 und 1
    EndFunc ;==>_Zufall2

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

    Func __random($e, $min, $max, $int)
    SetError(0)
    If $e <= 5 Then
    SetError(1)
    Return -1
    Else
    $Zahl_Alt = natural()/2
    $Zahl = natural()
    $Iter = $e

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

    For $i = 1 to $Iter
    $1 = ($Zahl/$Zahl_Alt) * 23
    $2 = 10^8
    $3 = 1
    $Zahl = (Mod($1, ($2+$3)))
    If $i > $Iter-1 Then
    If $Zahl < $min Then
    Do
    $Zahl = $Zahl*4.123456789
    Until $Zahl > $min And $Zahl < $max
    If $int = 1 Then
    Return Int($Zahl)
    Else
    Return $Zahl
    EndIf
    ElseIf $Zahl > $max Then
    Do
    $Zahl = $Zahl/4.123456789
    Until $Zahl < $max And $Zahl > $min
    If $int = 1 Then
    Return Int($Zahl)
    Else
    Return $Zahl
    EndIf
    Else
    SetError(1)
    Return -1
    EndIf
    EndIf
    Next
    EndIf
    EndFunc

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

    Func natural()
    $1 = TimerInit()
    Sleep(1)
    $2 = TimerDiff($1)
    Return $2
    EndFunc

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

    #Region Sonstiges

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

    Func _RandomAuswertung($Min, $Max, $i, $Absolut = True, $ArrayDisplay = False, $Breite = 600, $Hoehe = 400)
    Local $Anz = $Max - $Min
    Local $Array[$Anz + 1][3]
    Local $Random = 0
    For $o = 1 To $i Step 1
    $Random = Int(_Random($Min, $Max + 1)) ; Hier die eigene Randomfunktion einsetzen
    If $Random < $Min Or $Random > $Max Then Return -1
    $Array[$Random - $Min][0] = $Random
    $Array[$Random - $Min][1] += 1
    Next
    For $o = 0 To $Anz Step 1
    $Array[$o][2] = ($Array[$o][1] / $i)
    Next
    Local $MaximalWert, $MinimalWert
    __Max($Array, $Anz, $MaximalWert, $MinimalWert)
    If $Absolut Then $MinimalWert = 0
    Local $TeilDesMaxwertes = $MaximalWert / 15
    $MaximalWert += $TeilDesMaxwertes
    Local $TeilDesMinwertes = $MinimalWert / 15
    $MinimalWert -= $TeilDesMinwertes
    Local $Img = _CreateImage($Breite, $Hoehe)
    Local $Gfx = _GDIPlus_GraphicsCreateFromHDC(DllStructGetData($Img, 1, 1))
    _GDIPlus_GraphicsClear($Gfx, 0xFFFFFFFF)
    Local $hPen = _GDIPlus_PenCreate(0xFF000000, 1)
    Local $hFamily = _GDIPlus_FontFamilyCreate('Arial')
    Local $hFont = _GDIPlus_FontCreate($hFamily, 11)
    Local $tRect = _GDIPlus_RectFCreate(0, 5, 45, 15)
    Local $hBrush = _GDIPlus_BrushCreateSolid(0xFF000000)
    Local $hFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hFormat, 2)
    _GDIPlus_GraphicsDrawLine($Gfx, 0, $Hoehe, 50, $Hoehe - 50, $hPen)
    $Breite -= 60
    $Hoehe -= 60
    _GDIPlus_GraphicsDrawStringEx($Gfx, $MaximalWert, $hFont, $tRect, $hFormat, $hBrush)
    $tRect = _GDIPlus_RectFCreate(0, $Hoehe - 3, 45, 15)
    _GDIPlus_GraphicsDrawStringEx($Gfx, $MinimalWert, $hFont, $tRect, $hFormat, $hBrush)
    $tRect = _GDIPlus_RectFCreate(50, $Hoehe + 15, 45, 15)
    _GDIPlus_StringFormatSetAlign($hFormat, 0)
    _GDIPlus_GraphicsDrawStringEx($Gfx, $Min, $hFont, $tRect, $hFormat, $hBrush)
    $tRect = _GDIPlus_RectFCreate($Breite + 12, $Hoehe + 15, 45, 15)
    _GDIPlus_StringFormatSetAlign($hFormat, 2)
    _GDIPlus_GraphicsDrawStringEx($Gfx, $Max, $hFont, $tRect, $hFormat, $hBrush)
    _GDIPlus_PenSetWidth($hPen, 1)
    _GDIPlus_BrushSetSolidColor($hBrush, 0xFF00A000)
    Local $b = $Breite / ($Anz + 1)
    Local $h = 0
    For $i = 0 To $Anz Step 1
    $h = 10 + $Hoehe - (($Array[$i][2] - $MinimalWert) / ($MaximalWert - $MinimalWert) * $Hoehe)
    _GDIPlus_GraphicsFillRect($Gfx, 50 + $i * $b, $h, $b, $Hoehe - $h + 10, $hBrush)
    _GDIPlus_GraphicsDrawRect($Gfx, 50 + $i * $b, $h, $b, $Hoehe - $h + 10, $hPen)
    Next
    _GDIPlus_GraphicsDrawRect($Gfx, 50, 10, $Breite, $Hoehe, $hPen)
    If $ArrayDisplay Then _ArrayDisplay($Array)
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_BrushDispose($hBrush)
    _GDIPlus_FontFamilyDispose($hFamily)
    _GDIPlus_FontDispose($hFont)
    _GDIPlus_StringFormatDispose($hFormat)
    _SaveImage($Img)
    _GDIPlus_GraphicsDispose($Gfx)
    _DeleteImage($Img)
    EndFunc ;==>_RandomAuswertung

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

    Func __Max($A, $i, ByRef $b, ByRef $c)
    $b = 0
    $c = 100
    For $o = 0 To $i Step 1
    If $b < $A[$o][2] Then $b = $A[$o][2]
    If $c > $A[$o][2] Then $c = $A[$o][2]
    Next
    EndFunc ;==>__Max

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

    Func _CreateImage($b, $h)
    Local $ptr, $hDC, $hbmp
    $hDC = _CreateNewBmp32($b, $h, $ptr, $hbmp)
    Local $struct = DllStructCreate('int[5]')
    DllStructSetData($struct, 1, $hDC, 1)
    DllStructSetData($struct, 1, $b, 2)
    DllStructSetData($struct, 1, $h, 3)
    DllStructSetData($struct, 1, $ptr, 4)
    DllStructSetData($struct, 1, $hbmp, 5)
    Return $struct
    EndFunc ;==>_CreateImage

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

    Func _DeleteImage(ByRef $struct)
    _WinAPI_DeleteObject(DllStructGetData($struct, 1, 5))
    _WinAPI_DeleteDC(DllStructGetData($struct, 1, 1))
    $struct = 0
    EndFunc ;==>_DeleteImage

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

    Func _SaveImage($Img)
    Local $pfad = FileSaveDialog('BildSpeichern', @ScriptDir, '(*,.png)', Default, Hex(Random(256, 16 ^ 3, 1), 3) & '.png')
    If $pfad Then
    If Not StringRight($pfad, 4) = '.png' Then $pfad &= '.png'
    Local $bm = _GDIPlus_BitmapCreateFromHBITMAP(DllStructGetData($Img, 1, 5))
    _GDIPlus_ImageSaveToFile($bm, $pfad)
    _GDIPlus_BitmapDispose($bm)
    EndIf
    EndFunc ;==>_SaveImage

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

    ;Von Andy
    Func _CreateNewBmp32($iWidth, $iHeight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe DC und ptr und handle auf die Bitmapdaten
    Local $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    Local $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iWidth)
    DllStructSetData($tBMI, "Height", -$iHeight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    Local $adib = DllCall($GDI32_DLL, 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

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

    #EndRegion Sonstiges

    [/autoit]


    Seid nicht so hart :P (Seid mit d. Damit es nicht so hart klingt)
    Bin noch müde^^

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

    lg
    Mars(i)

  • Sehr schönes Testskript.
    Vor allem die direkte Ausgabe des Histogramms in AutoIt.
    Ich persönlich hatte meine Histogramme mit einem kleinen Python-Skript erstellt:

    Python-Histogramm Skriptchen
    Python
    from matplotlib import pyplot as PLT
    import numpy as NP
    
    
    ax1 = PLT.figure().add_subplot(111)
    n, bins, patches = ax1.hist(NP.ravel(NP.loadtxt(open('Random.txt'), dtype='float')), bins=100, normed=1, facecolor='green')
    PLT.show()


    Wenn man nun einen Schritt weiter gehen will und nicht nur visuell auswerten will sondern auch streng mathematisch dann würde man einen Chi²-Test auf Gleichverteilung über die Zufallszahlenmenge durchführen.
    Mal als Beispiel:

    Spoiler anzeigen
    [autoit]

    Global Const $N = 1e5
    Global Const $dIrrtumswahrscheinlichkeit = 0.005
    Global Const $dChiQuantil = 23.59 ; (Für df=9 und alpha = 0.005 aus Tabelle: http://psydok.sulb.uni-saarland.de/volltexte/2004…tml/chivert.htm)

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

    Global $Erwartungswert = $N / 10 ; Gibt die zu erwartende absolute Häufigkeit einer der 10 Zufallszahlen bei einer Gleichverteilung an

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

    Global $aHaeufigkeit[10]
    Global $dAbwSumme = 0

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

    ; Erzeuge die Stichprobe der Zufallszahlen und ermittle ihre absolute Häufigkeit
    For $i = 1 To $N
    $aHaeufigkeit[Random(0, 9, 1)] += 1
    Next

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

    ; Berechne die Summe aller normierten Abweichungen
    For $i = 0 To 9
    $dAbwSumme += (($aHaeufigkeit[$i] - $Erwartungswert) ^ 2) / $Erwartungswert
    Next

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

    If $dAbwSumme < $dChiQuantil Then
    ; Nullhypothese angenommen
    MsgBox(0, "", "Mit einer Irrtumswahrscheinlichkeit von " & 100 * $dIrrtumswahrscheinlichkeit & "% handelt es sich um eine Gleichverteilung.")
    Else
    ; Nullhypothese verworfen
    MsgBox(0, "", "Es konnte keine Gleichverteilung nachgewiesen werden.")
    EndIf

    [/autoit]