Random-Number-Generator

    • Offizieller Beitrag

    Ich habe mal eine UDF erstellt mit der man Zufallszahlen generieren kann.

    Eigenschaften:
    - Die Zufallszahlen sind einmalig, kommen also nur ein Mal vor
    - Ausgabe aufsteigend sortiert ausgeben lassen
    - Zahlenbereich auswählbar
    - Anzahl der Zufallszahlen auswählbar
    - Ganz- oder Kommazahlen möglich

    Version 1.4.0.0 ( 23.06.08 )

    Edit 1.3.0.0 :
    Jetzt kann man auch riesige Zahlenbereiche angeben, wie z.B. 10.000 Zufallszahlen aus dem Bereich 100.000.000...999.999.999, aufsteigend sortiert ausgeben. Auf meinem Rechner braucht das Script dafür nur rund 4 sek. Man bedenke: es gibt dabei keine doppelten Zahlen!

    Edit 1.4.0.0 :
    - Parameterübergabe an die Original Random()-Funktion angepasst (siehe Kommentare in der UDF)
    - Auswahlmöglichkeit (Ganz- oder Kommazahlen)

    Mein besonderer Dank gilt hierbei: BugFix, der mit seiner Erklärung zu dem Dictionary-Objekt zu diesen Erfolg beigetragen hat.
    BugFix : Ich benutze das Objekt zwar 'nur' um die doppelten auszuschliessen, aber mit anderen Mitteln würde das ewig dauern.


    Das ist die UDF:

    Spoiler anzeigen
    [autoit]


    #include-once

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

    ;===============================================================================
    ; Funktion Name: _RanNumGen()
    ; AutoIt-Version: 3.2.10.0
    ; Language: German
    ; Version: 1.4.0.0
    ; Date: 23. Jun. 2008
    ; Author: Thomas Stephan <oscar at elektronik-kurs dot de>
    ;
    ; Beschreibung:
    ; Diese Funktion generiert Zufallszahlen aus einem angegebenen Zahlenbereich.
    ; Die ausgegebenen Zufallszahlen sind einmalig, kommen also nicht doppelt vor.
    ; Sortierung erfolgt mit einer Quicksort-Version
    ;
    ; Funktionsaufruf: _RanNumGen ( [$min], [$max], [$int], [$num], [, $sort] )
    ; [$min] und [$max] = Anfang (Default = 0) und Ende (Default = 1) des Zahlenbereichs
    ; [$int] = Ganzzahl (True) oder Kommazahl (False = Default)
    ; [$num] = Anzahl der auszugebenen Zufallszahlen
    ; Wenn $num nicht angegeben ist, dann nur eine Zahl generieren
    ; [$sort] = 'True', Ausgabe wird aufsteigend sortiert (wird ignoriert bei $num = 1)
    ; [$sort] = 'False' oder nicht angegeben, dann unsortiert
    ;
    ; Rückgabe:
    ; Wenn keine Fehler aufgetreten sind, wird ein 0-basiertes Array mit den
    ; Zufallszahlen zurückgegeben.
    ;
    ; Bei einem Fehler ist der Rückgabewert = 0 und @error =
    ; 1 = Wenn $num (Anzahl der Zufallszahlen) Null oder negativ
    ; 2 = Wenn $max kleiner als $min
    ; 3 = Wenn $num (Anzahl der Zufallszahlen) größer als
    ; der Zahlenbereich ($min bis $max)
    ; 4 = Dictionary-Objekt konnte nicht erstellt werden
    ;===============================================================================
    Func _RanNumGen($min = 0, $max = 1, $int = False, $num = 1, $sort = False)
    If $num < 1 Then Return SetError(1, 0, 0)
    If $max < $min Then Return SetError(2, 0, 0)
    If $num > $max - $min + 1 Then Return SetError(3, 0, 0)
    $oDictionary = ObjCreate('Scripting.Dictionary')
    If Not IsObj($oDictionary) Then Return SetError(4, 0, 0)
    SRandom(@AutoItPID + @SEC + @MIN + @HOUR + @YDAY + @YEAR)
    Local $out[$num], $ran, $i
    For $i = 0 To $num-1
    Do
    $ran = Random($min, $max, $int)
    Until Not $oDictionary.Exists($ran)
    $oDictionary.Add($ran, '')
    $out[$i] = $ran
    Next
    $oDictionary.RemoveAll
    If $sort And ($num > 1) Then _Quicksort($out, 0, $num-1)
    Return $out
    EndFunc

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

    Func _Quicksort(ByRef $aArray, $left, $right)
    If $left < $right Then
    Local $pivot = _SplitSwap($aArray, $left, $right)
    _Quicksort($aArray, $left, $pivot-1)
    _Quicksort($aArray, $pivot+1, $right)
    EndIf
    EndFunc

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

    Func _SplitSwap(ByRef $aArray, $left, $right)
    Local $i = $left, $j = $right-1, $pivot = $aArray[$right], $h
    Do
    While $aArray[$i] <= $pivot And $i < $right
    $i += 1
    WEnd
    While $pivot <= $aArray[$j] And $j > $left
    $j -= 1
    WEnd
    If $i < $j Then
    $h = $aArray[$i]
    $aArray[$i] = $aArray[$j]
    $aArray[$j] = $h
    EndIf
    Until $i >= $j
    $aArray[$right] = $aArray[$i]
    $aArray[$i] = $pivot
    Return $i
    EndFunc

    [/autoit]

    Und das ist ein Beispielscript:

    Spoiler anzeigen
    [autoit]


    #include <Array.au3> ; wird hier nur für die Anzeige benötigt
    #include "RanNumGen.au3" ; wenn die UDF im Script-Verzeichnis liegt
    ; #include <RanNumGen.au3> ; wenn die UDF im Include-Verzeichnis (C:\Programme\AutoIt3\Include) liegt.

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

    ; <Anfang> Beispielaufruf mit Ausgabe
    ; ------------------------------------------------------------------------------
    ; Beispiel 1 = 1.000 Kommazahlen aus dem Bereich 1.000.000.000...2.147.483.647 (2^31-1 ist das Maximum), aufsteigend sortiert ausgeben
    Global $zahlen = _RanNumGen(1000000000, 2147483647, 0, 1000, True)
    If IsArray($zahlen) Then _ArrayDisplay($zahlen)

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

    ; Beispiel 2 = 6 Ganzzahlen aus dem Bereich 1...49, aufsteigend sortiert ausgeben
    Global $zahlen = _RanNumGen(1, 49, 1, 6, True)
    If IsArray($zahlen) Then _ArrayDisplay($zahlen)
    ; ------------------------------------------------------------------------------
    ; <Ende> Beispielaufruf

    [/autoit]

    Vielleicht kann es ja noch jemand gebrauchen. :)

    • Offizieller Beitrag

    Ja, zum Lottozahlen ziehen ist das auch geeignet. :)

    Ich wollte aber ein universelles Script haben und da gab es viele Probleme.

    Will man z.B. 9000 Zahlen aus einem Bereich von 1...10000, dann gibt es mit der 'Random()-Hinterhervergleichen'-Methode das Problem, dass sehr viele doppelte auftauchen und man die Schleife entsprechend oft wiederholen muss. Hier ist die Methode vorher ein Array mit Zahlen füllen und dann Random und Zahl rauslöschen sehr viel schneller. Dafür hat diese Methode den Nachteil bei einem großen Zahlenbereich, denn man muss in dem Fall ein sehr großes Array generieren, was entsprechend lange dauert.
    Das obige Script benutzt zum Vergleich, ob es die Zahl bereits gibt, das Dicionary-Objekt, was sehr viel schneller geht. :)

    Die obere Grenze des Zahlenbereichs liegt übrigens bei: 2^31-1 = 2147483647.

    • Offizieller Beitrag

    Welches Script hast du denn augeführt ? Das Beispiel hat gar keine 39 Zeilen .