Ist Random doch nicht Random?

Für allgemeine Fragen zur Programmierung mit PureBasic.
Little John

Beitrag von Little John »

Gubbie247 hat geschrieben:das problem hier ist aber die geschwindigkeit. ich kann ja nicht für die koordinate (10395,432) 10827 mal einen RandomBefehl ausführen, deshalb suche ich ja eine Alternative.
Es kann aber keine Alternative sein, Befehle oder Funktionen der verwendeten Programmiersprache entgegen ihrer Zweckbestimmung zu benutzen bzw. zu suggerieren, dass diese nicht korrekt funktionieren.
Gubbie247 hat geschrieben:Besonders merkwürdig finde ich halt, dass offenbar der erste Randomwert mit dem Seedwert in zusammenhang steht, ich sehe da keinen Grund dafür? Deshalb ist es so schwierig.
Ich verstehe leider nicht, was Du meinst.

"Perlin Rauschen" kannte ich vorher nicht. Mit Google habe ich jetzt auf die Schnelle u.a. dies gefunden:
http://www.gup.uni-linz.ac.at/thesis/diploma/paul_heinzlreiter/html/node14.html hat geschrieben:Perlin Rauschen
Die Perlin Rauschfunktion kann man im ein-, zwei- oder dreidimensionalen Fall verwenden. Sie basiert auf einem Zufallszahlengenerator und setzt sich aus folgenden Schritten zusammen:

1. Berechnung einer Zufallszahlenfolge
2. Interpolation der Zufallszahlenfolge zu einer stetigen Funktion
3. Wiederholung der Schritte 1 und 2 für beliebig viele Funktionen, wobei die Amplitude jeder neuen Funktion im Vergleich zum Vorgänger halbiert wird, und die Frequenz verdoppelt
4. Aufsummieren der Funktionen
5. Glätten der Rauschfunktion falls notwendig
IMHO könnte das im ersten Ansatz in PureBASIC grob etwa so aussehen:

Code: Alles auswählen

AnzahlFunktionen = 6
LetzterWert = 100
Schrittweite = 12     ; gilt für die erste Funktion
Amplitude = 20        ; gilt für die erste Funktion

For i = 1 To AnzahlFunktionen
   RandomSeed(i)
   For k = 1 To LetzterWert Step Schrittweite
      r = Random(Amplitude)
      Debug r
   Next
   Schrittweite / 2
   Amplitude / 2
Next
Dieser Code ist (unter PB 4.10) nicht lauffähig, da hinter Step leider eine Konstante stehen muss. Diese Einschränkung dass dort keine Variable stehen kann ist ärgerlich. Man müsste hier also diese Logik mit einer While- oder Repeat-Schleife nachbilden.

Gruß, Little John
Benutzeravatar
Zaphod
Beiträge: 2875
Registriert: 29.08.2004 00:40

Beitrag von Zaphod »

Selbstverständlich stehen die Random Werte mit den Seedwerten in mathematischer Verbindung... so ein PC ist ja eine deterministische Maschine in der es keine echte Zufälligkeit geben kann, es sei denn mit nichtdeterministischer Zusatzhardware.
Gubbie247
Beiträge: 32
Registriert: 10.10.2004 13:23

Beitrag von Gubbie247 »

Vielen Dank für deine Antwort.
Ich denke, eine wichtige Tatsache ist nicht klar:
Am Ende steht eine Funktion wie perlin(x,y,z), die für die jeweils gleichen Werte das gleiche Ergebnis liefert.
Die perlin-Funktion habe ich auch schon fertig, es funktioniert alles, nur die Zufallswerte machen mir Sorgen.
RandomSeed liefert bei wiederholtem Aufruf der Randomfunktion die immer gleiche Folge, dasi st mir klar.
Meine Überlegung ist nun, nicht die ganze Folge entlang zu gehen, um einen Wert zu erhalten, sondern von dem Wert ausgehend (Seed) einen Wert zu bestimmen. Das Zackenmuster kommt nun durch die merkwürdige Funktionsweise von RandomSeed zustande, keine zufälligen ersten Randomwerte zu wählen, sondern Ansteigende.

Mein Code bis jetzt:

Code: Alles auswählen

InitSprite()
InitKeyboard()
InitMouse()

#bb=1280
#bh=800

OpenScreen(#bb,#bh,32,"")
Procedure.f Cosine_Interpolate(a.f, b.f, x.f)
ft.f = x * #PI
f.f = (1 - Cos(ft)) * 0.5
ProcedureReturn (a*(1-f) + b*f)
EndProcedure
Procedure.f ran(x,y)
  RandomSeed(y)
  RandomSeed(Random(10000)+x)
  ;For i = 0 To x
    l.f=-1+Random(2000)/1000
  ;Next
  ProcedureReturn l
EndProcedure
Procedure.f noise(x.f,y.f)
  rand1.f=ran(Int(x),Int(y))
  rand2.f=ran(Int(x)+1,Int(y))
  rand3.f=ran(Int(x),Int(y+1))
  rand4.f=ran(Int(x)+1,Int(y+1))
  
  ProcedureReturn Cosine_Interpolate(Cosine_Interpolate(rand1 ,rand2,x-Int(x)),Cosine_Interpolate(rand3 ,rand4,x-Int(x)),y-Int(y))
  
EndProcedure
Procedure.f perlin(x.f,y.f,order)
  res.f=0
 
  For i = 1 To order
    res + noise(x*Pow(2,i),y*Pow(2,i))/Pow(2,i)
  Next
  ProcedureReturn res;noise(x,y)/2 + noise(x*2,y*2)/4 + noise(x*4,y*4)/8
 EndProcedure


#Step=5
w=1
amp=100
CreateSprite(0,#bb,#bh)
CreateSprite(1,#bb,#bh)
StartDrawing(SpriteOutput(0))
For x = 1 To #bb-1 

;  Debug x
Next
StopDrawing()

Repeat
  
  ExamineKeyboard()
  ExamineMouse()
  ClearScreen(RGB(0,0,0))
  For i = 0 To 10
  DisplaySprite(0,-1,0)
  StartDrawing(ScreenOutput())
  For y = 1 To #bh/2-1
    farbe.f=(0.5+0.5*perlin(time*00.01,y*00.01,10))*255
    If farbe>y
      farbe-y
      Plot(#bb-1,#bh-y*w,RGB(farbe,farbe,farbe))
    EndIf
  Next
  time+1
 
  StopDrawing()
  GrabSprite(0,0,0,#bb,#bh)
Next
  ;DisplaySprite(1,0,0)
  FlipBuffers()
Until KeyboardPushed(1)
Benutzeravatar
#NULL
Beiträge: 2238
Registriert: 20.04.2006 09:50

Beitrag von #NULL »

vielleicht reicht dir ja schon ein bisschen pfuschen, nur damit sie säge verschwindet:

Code: Alles auswählen

Macro seed(_n_)
  RandomSeed(_n_) : RandomSeed(Random(99))
EndMacro
ansonsten mußt du dir halt selber ne rand() schreiben, oder sonst irgendwie eine anderen benutzen
my pb stuff..
Bild..jedenfalls war das mal so.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

@ #NULL: Das kann natürlich nicht funktionieren ;) denk mal nach...

Zum Thema: Würde es denn funktionieren, wenn Du beim allerersten Mal einen zufälligen Seed nimmst? Weil dann kannst Du doch einfach ElapsedMilliseconds() benutzen um einen tatsächlich zufälligen Seed zu erhalten. Von dort aus könntest Du auch wieder Deine festen Werte benutzen, also immer +1, dann hast Du wenigstens bei jedem Programmstart eine andere Folge, aber intern sind wieder alle abhängig voneinander. Keine Ahnung, ob Dir das hilft...
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Little John

Beitrag von Little John »

Wenn Du ganz oben (meinetwegen in die 4. Zeile) schreibst

Code: Alles auswählen

RandomSeed(77)
und innerhalb von Procedure.f ran(x,y) die erste Zeile deaktivierst, sieht das Rauschen dann so aus wie es soll?

Gruß, Little John
Gubbie247
Beiträge: 32
Registriert: 10.10.2004 13:23

Beitrag von Gubbie247 »

Little John hat geschrieben:Wenn Du ganz oben (meinetwegen in die 4. Zeile) schreibst

Code: Alles auswählen

RandomSeed(77)
und innerhalb von Procedure.f ran(x,y) die erste Zeile deaktivierst, sieht das Rauschen dann so aus wie es soll?

Gruß, Little John
nein
Zaphod hat geschrieben:Selbstverständlich stehen die Random Werte mit den Seedwerten in mathematischer Verbindung... so ein PC ist ja eine deterministische Maschine in der es keine echte Zufälligkeit geben kann, es sei denn mit nichtdeterministischer Zusatzhardware.
in EINEM ja, aber es muss ja nicht sowas aehnliches sein, wie proportional und modulo zusammen (Yackenmuster halt, ich kenne die richtigen Begriffe nicht).
Benutzeravatar
Zaphod
Beiträge: 2875
Registriert: 29.08.2004 00:40

Beitrag von Zaphod »

Wenn du RandomSeed und Random so nutzt wie es gedacht ist, ist das ja auch nicht so ;)

Was versprichst du dir eigentlich davon in jedem Durchlauf Randomseed auszuführen? Glaubst du das ist schneller so?
Gubbie247
Beiträge: 32
Registriert: 10.10.2004 13:23

Beitrag von Gubbie247 »

Zaphod hat geschrieben:Wenn du RandomSeed und Random so nutzt wie es gedacht ist, ist das ja auch nicht so ;)

Was versprichst du dir eigentlich davon in jedem Durchlauf Randomseed auszuführen? Glaubst du das ist schneller so?
es geht, wie schon weiter oben gesagt, darum, für eine BESTIMMTE KOORDINATE einen Wert zu erhalten, der immer der selbe sein soll. Mir ist keine andere Möglichkeit eingefallen, ich verwende die RandomSeedfunktion so, wie ich sie verstanden habe.
Benutzeravatar
ZeHa
Beiträge: 4760
Registriert: 15.09.2004 23:57
Wohnort: Friedrichshafen
Kontaktdaten:

Beitrag von ZeHa »

Das heißt, Du willst einfach nur 'ne Kurve, die krass aussieht, aber reproduzierbar ist?

Dann müßte es doch folgendermaßen funktionieren:

Code: Alles auswählen

RandomSeed(666)

Dim y(100)

For x = 0 to 100
    y(x) = Random(10)
Next x
Jetzt kannst Du in Zeile 1 jedesmal einen anderen Wert einsetzen, und bekommst auch jedesmal die passende Kurve. Die Kurve für 666 sieht aber immer gleich aus, und die Kurve für 667 sieht auch immer gleich aus. Ist es das, was Du brauchst?
Bild     Bild

ZeHa hat bisher kein Danke erhalten.
Klicke hier, wenn Du wissen möchtest, woran ihm das vorbeigeht.
Antworten