Hallo Jimmy,
da ich mit der Funktion RandomIn() hinsichtlich der Doppelungen auch nicht sehr zufrieden war,
verwende ich eine eigene Klasse zur Generierung von Zufallszahlen, bei der man einen Faktor
festlegen kann, der Doppelungen begrenzt.
Code: Alles auswählen
#include "common.ch"
Procedure Main
LOCAL i
LOCAL iMax := 1000
LOCAL nZahl
LOCAL nPosi
LOCAL aTreff := {}
LOCAL oRandom
SET ALTER TO _LOGFILE.TXT
SET ALTER ON
oRandom := xRandom():New( iMax, 900 ) // innerhalb der ersten 900 generierten Zufallszahlen keine Doppelungen zulassen
FOR i := 1 TO iMax
nZahl := oRandom:NextValue()
nPosi := ASCAN(aTreff,{|x| x[1] = nZahl } )
IF nPosi > 0
aTreff[nPosi,2] := aTreff[nPosi,2] +1
ELSE
AADD(aTreff,{nZahl,1} )
ENDIF
NEXT
? iMax := LEN(aTreff)
? "********"
aTreff := ASort(aTreff,,, {|aX,aY| aX[2] < aY[2]} )
FOR i := 1 TO iMax
? aTreff[i,1],aTreff[i,2]
NEXT
SET ALTER OFF
SET ALTER TO
RETURN
//////////////////////////////////////////////////////////////////////////////////////////////////
// xRandom-Klasse
//
// - Klasse zur Generierung von Zufallszahlen
// - xLimit: (default: 100); entweder eine pos. Ganzzahl zw. 1..n (0 als Zufallszahl ist aus-
// geschlossen) oder ein Array mit Min- und Max-Angabe (0 und negative Zahlen sind mgl.);
// Bsp. f. xLimit: { 0, 70 }; { -10, 10 }; { 500, 1000 }
// - nDoubleLimit: Erzeugung doppelter Zufallszahlen bis zur Hoehe von nDoubleLimit verhindern
// (default: 0 = Doppelungen zulassen); wenn nDoubleLimit = 100, wird innherhalb der ersten
// 100 Zufallszahlen keine Doppelung zugelassen, von 101. bis 200. Zufallszahl wird wieder
// keine Doppelung zugelassen und von 201. bis 300. keine Doppelung usw.
//
// - Bsp.: oRandom := xRandom():New( 500, 100 ) // Zufallszahlen zw. 1 u. 500 erzeugen;
// // aller 100 Zufallszahlen darf es keine Doppelung geben
// nValue := oRandom:NextValue() // Zufallszahl erzeugen
//
/////////////////////////////////////////////////////////////////////////////////////////////////
CLASS xRandom
PROTECTED:
VAR nRandom
VAR nShiftValue
EXPORTED:
VAR Value, Values
VAR Limit
VAR DoubleLimit
METHOD Init, NextValue
ENDCLASS
METHOD xRandom:Init( xLimit, nDoubleLimit )
DEFAULT xLimit TO 100 // Limit standardmaessig auf 100 setzen
DEFAULT nDoubleLimit TO 0 // Doppelungen per default zulassen
::DoubleLimit := nDoubleLimit
if Valtype( xLimit ) == "A" // xLimit ist ein Array mit Von-Bis-Wertepaar
::Limit := ( xLimit[2] - xLimit[1] + 1 ) // Limit zw. 1..n aus den Von-Bis-Werten errechnen
::nShiftValue := ( xLimit[1] - 1 ) // um wie viel muss das Ergebnis bei der Ausgabe verschoben werden
ELSE // xLimit ist eine pos. Ganzzahl zw. 1..n
::Limit := xLimit
::nShiftValue := 0
endif
// wenn ::DoubleLimit groesser als 95% von ::Limit ist, wird ::DoubleLimit auf 95% des ::Limit
// herabgesetzt, da es andernfalls zu Stack Overflow Errors kommen kann
if ( ::DoubleLimit * 100 / ::Limit ) > 95
::DoubleLimit := ( ::Limit * 95 / 100 )
endif
::Values := {}
// Ausgangswert
::nRandom := Seconds()
::nRandom := ( ::nRandom - Int( ::nRandom ) )
RETURN Self
METHOD xRandom:NextValue( lShiftValue )
DEFAULT lShiftValue TO .T.
::nRandom := Log( ::nRandom + Sqrt( 2 ) ) * Exp( 3 )
::nRandom := Val( Str( ::nRandom - Int( ::nRandom ), 17, 15 ) )
::Value := Int( ::Limit * ::nRandom ) + 1 // +1 <-- keine 0 zulassen
if ::DoubleLimit > 0
if Len( ::Values ) == ::DoubleLimit
::Values := {}
endif
if AScan( ::Values, ::Value ) > 0
::Value := ::NextValue( .F. ) // bei rekursivem Aufruf kein Verschieben des Wertebereiches zulassen (.F.)
ELSE
AAdd( ::Values, ::Value )
endif
endif
::Value += iif( lShiftValue, ::nShiftValue, 0 )
RETURN ::Value