Warum erhalte ich dieses spezielle Farbmuster, wenn ich rand() verwende?

Lesezeit: 7 Minuten

Benutzeravatar von Little Pony
Kleines Pony

Ich habe versucht, eine Bilddatei wie folgt zu erstellen:

uint8_t raw_r[pixel_width][pixel_height];
uint8_t raw_g[pixel_width][pixel_height];
uint8_t raw_b[pixel_width][pixel_height];
uint8_t blue(uint32_t x, uint32_t y)
{
    return (rand()%2)? (x+y)%rand() : ((x*y%1024)%rand())%2 ? (x-y)%rand() : rand();
}
uint8_t green(uint32_t x, uint32_t y)
{
    return (rand()%2)? (x-y)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
}
uint8_t red(uint32_t x, uint32_t y)
{
    return (rand()%2)? (y-x)%rand() : ((x*y%1024)%rand())%2 ? (x+y)%rand() : rand();
}

for (y=0; y<pixel_height; ++y)
{
    for (x=0; x<pixel_width; ++x)
    {
        raw_b[x][y]=blue(x, y);
        raw_g[x][y]=green(x, y);
        raw_r[x][y]=red(x, y);
    }
}

Ich hatte erwartet, etwas Zufälliges zu bekommen (weißes Rauschen). Interessant ist aber die Ausgabe:

fLHGD

Kennen Sie den Grund dafür?


Bearbeiten

Jetzt ist klar, dass es nichts damit zu tun hat rand().

Versuchen Sie auch diesen Code:

for (x=0; x<pixel_width; ++x)
    for (y=0; y<pixel_height; ++y)
    {
        r[x][y] = (x+y);
        g[x][y] = (y-x);
        /* b[x][y] = rand()%2? x : y; */
    }

hLKRO

  • cos rand ist nicht rand – schöne Demo davon. Es ist 100% deterministisch

    – pm100

    21. September 2018 um 23:08 Uhr

  • stackoverflow.com/questions/822323/…

    – pm100

    21. September 2018 um 23:09 Uhr

  • @ pm100: Wie die Antwort von bames53 so gut erklärt, würden Sie das gleiche Muster erhalten, selbst wenn Sie einen perfekten Zufallszahlengenerator verwenden würden.

    – TonyK

    22. September 2018 um 14:04 Uhr

  • Entschuldigen Sie eine Frage: Da Sie die x- und y-Koordinaten verwenden, um die Pixelwerte zu berechnen, warum sollten Sie erwarten, dass diese Werte unabhängig von den Koordinaten sind? Wenn das Bild zu gleichmäßig zufällig aussieht, würden Sie das brauchen, oder?

    – Thomas Padron-McCarthy

    23. September 2018 um 7:15 Uhr


  • Gelernte Lektionen: Zufällige Dinge mit Zufallszahlen zu tun führt nicht zu zufälligen Ergebnissen 🙂

    – Hagen von Eitzen

    23. September 2018 um 20:03 Uhr

Benutzeravatar von bames53
Namen53

Ich wollte anfangs die gleiche Antwort wie alle anderen haben und dies den Problemen zuordnen rand(). Ich habe es mir jedoch besser überlegt und stattdessen die Verteilung analysiert, die Ihre Mathematik tatsächlich erzeugt.

TL;DR: Das Muster, das Sie sehen, hat nichts mit dem zugrunde liegenden Zufallszahlengenerator zu tun, sondern ist einfach darauf zurückzuführen, wie Ihr Programm die Zahlen manipuliert.

Ich bleibe bei deiner blauen Funktion, da sie alle ähnlich sind.

uint8_t blue(uint32_t x, uint32_t y) {
    return (rand() % 2)                  ? (x + y) % rand() :
           ((x * y % 1024) % rand()) % 2 ? (x - y) % rand() :
                                           rand();
}

Jeder Pixelwert wird aus einer von drei Funktionen ausgewählt: (x + y) % rand(), (x - y) % rand()und rand();

Schauen wir uns die Bilder an, die von jedem dieser allein erzeugt werden.

  • rand()

Das ist, was Sie erwarten würden, nur Rauschen. Nennen Sie dies “Bild C”

Geben Sie hier die Bildbeschreibung ein


  • (x + y) % rand()

Hier addieren Sie die Pixelkoordinaten und nehmen den Rest aus der Division durch eine Zufallszahl. Wenn das Bild 1024 x 1024 groß ist, liegt die Summe im Bereich [0-2046]. Die Zufallszahl, nach der Sie tauchen, liegt im Bereich [0,RAND_MAX], wobei RAND_MAX mindestens 32k und auf einigen Systemen 2 Milliarden beträgt. Mit anderen Worten, es besteht bestenfalls eine Chance von 1 zu 16, dass der Rest nicht gerecht ist (x + y). Diese Funktion erzeugt also größtenteils nur einen Gradienten mit zunehmendem Blau in Richtung + x + y.

Sie verwenden jedoch nur die niedrigsten 8 Bits, da Sie a zurückgeben uint8_tsodass Sie 256 Pixel breite Farbverlaufsstreifen haben.

Nennen Sie dies “Bild A”

Geben Sie hier die Bildbeschreibung ein


  • (x - y) % rand()

Hier machen Sie etwas Ähnliches, aber mit Subtraktion. Solange x größer als y ist, haben Sie etwas Ähnliches wie im vorherigen Bild. Aber wo y größer ist, ist das Ergebnis eine sehr große Zahl, weil x und y sind unsigned (negative Ergebnisse werden bis zum Anfang des Bereichs des unsigned-Typs umbrochen), und dann die the % rand() Tritt ein und Sie bekommen tatsächlich Geräusche.

Nennen Sie dies “Bild B”

Geben Sie hier die Bildbeschreibung ein

Jedes Pixel in Ihrem endgültigen Bild wird mithilfe von Funktionen aus einem dieser drei Bilder entnommen rand() % 2 und ((x * y % 1024) % rand()) % 2. Die erste davon kann so gelesen werden, dass Sie mit einer Wahrscheinlichkeit von 50 % auswählen (Ignorieren von Problemen mit rand() und seine niederwertigen Bits.)

Hier ist eine Nahaufnahme, wo rand() % 2 wahr ist (weiße Pixel), also wird Bild A ausgewählt.

Geben Sie hier die Bildbeschreibung ein

Die zweite Funktion ((x * y % 1024) % rand()) % 2 hat wieder das Problem wo rand() ist normalerweise größer als das, was Sie dividieren, (x * y % 1024)was höchstens 1023 ist. Dann (x*y%1024)%2 erzeugt nicht gleich oft 0 und 1. Jede ungerade Zahl multipliziert mit einer beliebigen geraden Zahl ist gerade. Jede gerade Zahl multipliziert mit einer beliebigen geraden Zahl ist auch gerade. Nur eine ungerade Zahl multipliziert mit einer ungeraden Zahl ist ungerade, und so %2 bei Werten, die drei Viertel der Zeit gerade sind, wird in drei Vierteln der Zeit 0 ergeben.

Hier ist eine Nahaufnahme, wo ((x * y % 1024) % rand()) % 2 wahr ist, sodass Bild B ausgewählt werden konnte. Es wählt genau dort aus, wo beide Koordinaten ungerade sind.

Geben Sie hier die Bildbeschreibung ein

Und hier ist eine Nahaufnahme, wo Bild C ausgewählt werden könnte:

Geben Sie hier die Bildbeschreibung ein

Wenn Sie die Bedingungen hier schließlich kombinieren, wird Bild B ausgewählt:

Geben Sie hier die Bildbeschreibung ein

Und wo Bild C ausgewählt ist:

Geben Sie hier die Bildbeschreibung ein

Die resultierende Kombination kann gelesen werden als:

Verwenden Sie mit 50% Wahrscheinlichkeit das Pixel von Bild A. Wählen Sie für den Rest der Zeit zwischen Bild B und Bild C, B, wo beide Koordinaten ungerade sind, C, wo eine gerade ist.

Da Sie schließlich dasselbe für drei verschiedene Farben tun, aber mit unterschiedlichen Ausrichtungen, sind die Muster in jeder Farbe unterschiedlich ausgerichtet und erzeugen die sich kreuzenden Streifen oder Gittermuster, die Sie sehen.

Benutzeravatar von templatetypedef
Vorlagentypdef

Viele der Berechnungen, die Sie in Ihrem Code durchführen, führen nicht zu wirklich zufälligen Werten. Diese scharfen Linien, die Sie sehen, entsprechen Stellen, an denen die relativen Werte Ihrer x- und y-Koordinaten miteinander handeln, und wenn das passiert, verwenden Sie grundlegend unterschiedliche Formeln. Rechenleistung zum Beispiel (x + y) % rand() geben Ihnen in der Regel den Wert zurück x + yseit rand() wird (normalerweise) eine viel, viel größere Zahl als zurückgeben x + y gegeben das RAND_MAX ist normalerweise eine ziemlich große Zahl. In diesem Sinne sollten Sie nicht erwarten, weißes Rauschen zurückzubekommen, da der Algorithmus, den Sie zum Generieren von Dingen verwenden, davon abweicht, weißes Rauschen zu erzeugen. Wenn Sie weißes Rauschen wünschen, stellen Sie einfach jedes Pixel auf ein rand(). Wenn Sie ein schönes Muster wie das oben gezeigte möchten, aber hier und da ein wenig Zufälligkeit hinzugefügt haben, verwenden Sie den Code, den Sie geschrieben haben.

Darüber hinaus, wie @pm100 in den Kommentaren angemerkt hat, die rand -Funktion gibt keine echten Zufallszahlen zurück, sondern verwendet stattdessen eine Pseudozufallsfunktion, um ihre Werte zu erzeugen. Die Standardimplementierung von rand verwendet auf vielen Systemen eine Art Pseudozufallszahlengenerator namens a linearer Kongruenzgenerator das erzeugt Zahlen, die in kurzen Bursts zufällig erscheinen können, die aber in der Praxis entschieden nicht zufällig sind. Hier ist zum Beispiel eine Animation aus Wikipedia, die zeigt, wie zufällige Punkte im Raum, die mit einem linearen Kongruenzgenerator ausgewählt wurden, letztendlich in eine feste Anzahl von Hyperebenen fallen:

Das Bild

Wenn Sie die x-, y- und z-Koordinaten durch die R-, G- und B-Koordinaten ersetzen, sieht dies so aus bemerkenswert ähnlich der Ausgabe, die von Ihrem Programm erzeugt wird. Ich vermute, dass dies hier wahrscheinlich nicht der Kernpunkt ist, da der andere oben genannte Aspekt wahrscheinlich viel ausgeprägter sein wird.

Wenn Sie nach qualitativ hochwertigeren Zufallszahlen suchen, müssen Sie eine qualitativ hochwertigere Zufallsquelle verwenden. In C könnten Sie in Betracht ziehen, Bytes von zu lesen /dev/urandom/ (auf einem Linux-ähnlichen System), was ziemlich gleichmäßig zufällige Werte liefert. C++ hat jetzt in seinen Standardbibliotheken eine Reihe guter Primitive zur Generierung von Zufallszahlen, falls Ihnen diese zur Verfügung stehen.

1425030cookie-checkWarum erhalte ich dieses spezielle Farbmuster, wenn ich rand() verwende?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy