Zufallszahlen
-
@DirkB Hab bei der Übergabe an die Funktion 2 mal "mal1" gehabt... aiaiai
Danke für die schnellen Antworten und sorry, dass ich das C-Forum gemisst habe.
Lg
Rene
-
Am besten mal lernen, wie man den Debugger bedient. Das spart eine Menge Zeit.
-
Hallo Swordfish!
Zum besseren Verständnis sieh dir mal folgende code-Sequenz an:
int initrandom = 0; //generiert Zufallszahlen von 1 bis 32767; int getrand(int min, int max) { int zuza, range, zuza3, rewer; // bis 32767 //srand (time (NULL)); if (initrandom == 0) { srand (time (NULL)); initrandom = 1; } max++; zuza = rand(); printf("urzuza: %d\n", zuza); range = (max - min); // + 1); zuza3 = zuza % range; rewer = zuza3 + min; return rewer; srand (time (NULL)); }
Wenn man innerhalb der Laufzeit eines Programms jedes mal srand() startet erhält
man immer die selben Werte. Um das zu verhindern dient die globale Variable
"initrandom", welche vor dem Start auf NULL gesetzt wird. Ruft man dann die Funktion
getrand() auf, wird automatisch geprüft, ob srand() schon gestartet wurde.
Innerhalb von getrand() wird die Funktion rand() aufgerufen.
Diese erzeugt eine Zufallszahl zwischen 0 und RAND_MAX.Diese Konstante ist in den headern<cstdlib> (stdlib.h)
definiert.Bei UNIX-Systemen und deren Derivaten(Linux, BSD) kann RAND_MAX durchaus andere Werte
annehmen als bei Windows-Systemen. Ganz zu schweigen vom Compiler.
Man kann sich auch folgende Zeile reinbasteln um deren Größe zu erhalten:printf("RAND_MAX: %d\n", RAND_MAX);
Auf meinem Linux-System(64Bit, SUSE-Linux Tumbleweed, Kernel 4.19.11-1
mit GCC 8.2.1 und codeblocks 17.12 rev. 11256)
ist die Größe der Konstante 2147483647Wie man aus dem Beispiel ersehen kann, beinhaltet die Variable "range"(englisch für Spannweite)
die Spannweite zwischen der kleinsten gewünschten Zufallszahl(min) und der größten (max).
Danach wird der Divisionsrest von der mit rand() erzeugten Zufallszahl und der
Spannweite errechnet. Logisch das dieser Divisionsrest niemals größer sein kann
als die Spannweite (=max - min). Theoretisch kann dieser Divisionsrest auch Null sein.
Deshalb wird anschließend der gewünschte Minimalwert dazu addiert.
In deinem Fall ist bei mal1 und mal2 die Spannweite 10 und der gewünschte Minimalwert 1.
Bei der Funktion getrand() müsstest du also als ersten Parameter 1 und beim zweiten 11 angeben.
Man könnte auch ein Array allokieren und dieses mit Zufallszahlen füllen und später
eine Häufigkeitsanalyse vornehmen.Dazu sollte man sich folgend Aussage vor Augen halten:
"Anyone who consider arithmetic means of producing random number is,
of course, in a state of sin" - John Von NeumannSiehe zur Person:
https://de.wikipedia.org/wiki/John_von_NeumannWer sich dafür interessiert, wie so ein Source-Code für diese Funktionen aussieht, für den habe ich
aus einer uralten CD mal folgendes Beispiel ausgegraben:/************************************************************************ This random number generator originally appeared in "Toward a Universal Random Number Generator" by George Marsaglia and Arif Zaman. Florida State University Report: FSU-SCRI-87-50 (1987) It was later modified by F. James and published in "A Review of Pseudo- random Number Generators" Converted from FORTRAN to C by Phil Linttell, James F. Hickling Management Consultants Ltd, Aug. 14, 1989. THIS IS THE BEST KNOWN RANDOM NUMBER GENERATOR AVAILABLE. (However, a newly discovered technique can yield a period of 10^600. But that is still in the development stage.) It passes ALL of the tests for random number generators and has a period of 2^144, is completely portable (gives bit identical results on all machines with at least 24-bit mantissas in the floating point representation). The algorithm is a combination of a Fibonacci sequence (with lags of 97 and 33, and operation "subtraction plus one, modulo one") and an "arithmetic sequence" (using subtraction). On a Vax 11/780, this random number generator can produce a number in 13 microseconds. ************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <math.h> #include <time.h> #define TRUE 1 #define FALSE 0 float u[97], c, cd, cm; int i97, j97, test; int rmarin(int ij, int kl); int ranmar(float rvec[], int len); void sow( int *seed1, int *seed2 ); int main() { float temp[100]; int i; int ij, kl, len; /*These are the seeds needed to produce the test case results*/ sow( &ij, &kl); //ij = 1802; //kl = 9373; /*Do the initialization*/ if (1 == rmarin(ij,kl)) return 1; /*Generate 20000 random numbers*/ len = 100; for ( i=0; i<=199 ; i++) if (1 == ranmar(temp, len)) return 1; /*If the random number generator is working properly, the next six random numbers should be: 6533892.0 14220222.0 7275067.0 6172232.0 8354498.0 10633180.0 */ len = 6; if (1 == ranmar(temp, len)) return 1; for ( i=0; i<=5; i++) printf("%12.1f\n",4096.0*4096.0*temp[i]); return 0; } /************************************************************************ This is the initialization routine for the random number generator RANMAR() NOTE: The seed variables can have values between: 0 <= IJ <= 31328 0 <= KL <= 30081 The random number sequences created by these two seeds are of sufficient length to complete an entire calculation with. For example, if several different groups are working on different parts of the same calculation, each group could be assigned its own IJ seed. This would leave each group with 30000 choices for the second seed. That is to say, this random number generator can create 900 million different subsequences -- with each subsequence having a length of approximately 10^30. Use IJ = 1802 & KL = 9373 to test the random number generator. The subroutine RANMAR should be used to generate 20000 random numbers. Then display the next six random numbers generated multiplied by 4096*4096 If the random number generator is working properly, the random numbers should be: 6533892.0 14220222.0 7275067.0 6172232.0 8354498.0 10633180.0 ************************************************************************/ int rmarin(int ij, int kl) { float s, t; int i, j, k, l, m; int ii, jj; /* Change FALSE to TRUE in the next statement to test the random routine.*/ test = TRUE; if ( ( ij < 0 || ij > 31328 ) || ( kl < 0 || kl > 30081 ) ) { printf ("RMARIN: The first random number seed must have a " "value between 0 and 31328\n"); printf (" The second random number seed must have a " "value between 0 and 30081"); return 1; } i = fmod(ij/177.0, 177.0) + 2; j = fmod(ij , 177.0) + 2; k = fmod(kl/169.0, 178.0) + 1; l = fmod(kl , 169.0); for ( ii=0; ii<=96; ii++ ) { s = 0.0; t = 0.5; for ( jj=0; jj<=23; jj++ ) { m = fmod( fmod(i*j,179.0)*k , 179.0 ); i = j; j = k; k = m; l = fmod( 53.0*l+1.0 , 169.0 ); if ( fmod(l*m,64.0) >= 32) s = s + t; t = 0.5 * t; } u[ii] = s; } c = 362436.0 / 16777216.0; cd = 7654321.0 / 16777216.0; cm = 16777213.0 / 16777216.0; i97 = 96; j97 = 32; test = TRUE; return 0; } int ranmar(float rvec[], int len) { float uni; int ivec; if ( !test ) { printf ("RANMAR: Call the initialization routine (RMARIN) " "before calling RANMAR.\n"); return 1; } for ( ivec=0; ivec < len; ivec++) { uni = u[i97] - u[j97]; if ( uni < 0.0 ) uni = uni + 1.0; u[i97] = uni; i97--; if ( i97 < 0 ) i97 = 96; j97--; if ( j97 < 0 ) j97 = 96; c = c - cd; if ( c < 0.0 ) c = c + cm; uni = uni - c; if ( uni < 0.0 ) uni = uni + 1.0; rvec[ivec] = uni; } return 0; } /* I use the following procedure in TC to generate seeds: The sow() procedure calculates two seeds for use with the random number generator from the system clock. I decided how to do this myself, and I am sure that there must be better ways to select seeds; hopefully, however, this is good enough. The first seed is calculated from the values for second, minute, hour, and year-day; weighted with the second most significant and year-day least significant. The second seed weights the values in reverse. */ void sow( int *seed1, int *seed2 ) { struct tm *tm_now; float s_sig, s_insig, maxs_sig, maxs_insig; long secs_now; int s, m, h, d, s1, s2; time(&secs_now); tm_now = localtime(&secs_now); s = tm_now->tm_sec + 1; m = tm_now->tm_min + 1; h = tm_now->tm_hour + 1; d = tm_now->tm_yday + 1; maxs_sig = 60.0 + 60.0/60.0 + 24.0/60.0/60.0 + 366.0/24.0/60.0/60.0; maxs_insig = 60.0 + 60.0*60.0 + 24.0*60.0*60.0 + 366.0*24.0*60.0*60.0; s_sig = s + m/60.0 + h/60.0/60.0 + d/24.0/60.0/60.0; s_insig = s + m*60.0 + h*60.0*60.0 + d*24.0*60.0*60.0; s1 = s_sig / maxs_sig * 31328.0; s2 = s_insig / maxs_insig * 30081.0; *seed1 = s1; *seed2 = s2; }
Betrachtet man das etwas angestaubte Beispiel genauer, dann sieht man, das man auch die
Initialisierung per Eingabe einer Schlüsselzahl starten könnte.
Dadurch würde man immer die selben Zahlen erhalten, egal wann man das Programm startet.
Eigentlich nicht wünschenswert, es sei denn man will sich sein eigenes Verschlüsselungsprogramm
basteln.
Wichtig dazu folgende Webseiten:
https://www.reddit.com/r/linux/comments/1lucdy/did_linus_torvalds_backdoor_linux_random_number/
https://www.theregister.co.uk/2013/09/10/torvalds_on_rrrand_nsa_gchq/
https://codepen.io/mottiden/pen/VbmZZN
https://www.phoronix.com/scan.php?page=news_item&px=Linus-Torvalds-New-Politeness
https://www.zdnet.com/article/a-kinder-gentler-linus-torvalds-and-linux-4-20/
-
@rustyoldguy sagte in Zufallszahlen:
Wenn man innerhalb der Laufzeit eines Programms jedes mal srand() startet erhält man
Wer hat irgendwo behauptet daß man
srand()
x-mal aufrufen soll? Rest: tl;dr.
-
Keiner!
Aber es soll ja mehrere Leute geben, die c lernen wollen. Bevor sich diese
die Finger wund Tippen, eine kleine Erklärung.
-
-
ähm du weißt schon, dass globale variablen beim programmstart mit 0 initialisiert werden, und du dir das daher sparen kannst?
edit: wenn du mit unix tolle zufallszahlen haben willst, dann lies doch einfach aus /dev/urandom ein.
-
Normalerweise ja, sollte aber nur ein kleines Beispiel(von 1989 !!!) sein. Ich denke mal, das die meisten hier
auf dem Forum dieses Beispiel für eigene Applikationen umschreiben können. Deshalb erübrigt sich so etwas.
Die Ergebnisse der Zufallszahlen hängen immer davon ab, wie dessen Erzeugung initialisert wird.
Die meisten werden das per Timer machen. Aber die Anzahl der erzeugten Zufallszahlen, ab der
sich der Zahlen wiederholen, dürfte sich im Rahmen halten.
So weit ich weis, hat da der amerikanische Geheimdienst was dagegen.Kleiner Exkurs:
Als zum Beispiel Phil Zimmermann sein PGP schrieb, war damals der Aufwand zur Entschlüsselung
laut Ansicht der Behörden zu hoch. Das führte dazu, das in mehreren Staaten, nicht nur in den USA
Chiffrierungs-Software unter das Waffenrecht gestellt wurde. Wer sich in einigen Ländern solcher
Software bedient, macht sich strafbar als Waffenhändler. Vor einigen Jahrzehnten gab es eine Organisation
welche sich die Aufgabe Verschlüsselungssoftware für den Hausgebrauch nicht all zu gut werden zu lassen.
Diese nannte sich so weit ich weis key recovery associationEine Möglichkeit zu Erzeugung etwa bei
der Permutation von Texten auf Bit-Ebene ist ein Zahlenarray von bzw 0 bis 131072 per Erzeugung von
Zufallszahlen durcheinander zu wirbeln. Also zu permutieren. rein theoretisch wären die Möglichkeiten
dann 131072 Faktorielle, also 131072. Ich selbst habe damals Talarius geschrieben und dieses in
QT geschriebenes Programm in einem anderen Forum ins Netz gestellt, nur als Lehrmittel!
Lässt man eine bereits permutierte Zahlenreihe erneut permutieren, so lässt sich die Spanne, ab der sich
die Zufallszahlen wiederholen, vergrößern.
Dies ist enorm wichtig. Eigentlich dürfte ich dies hier nicht schreiben, aber auf Kurzwelle werden
manche schon einmal auf Sender gestoßen sein, bei der Zahlenkolonnen gesendet werden.
Etwa als Textform. Der Sprecher/in listet dann Zahlen auf wie
"Neugen Acht", "Zero", Neugen vier drei " usw.
Diese sind tatsächlich für Agenten bestimmt um so Nachrichten du dechiffrieren.
Da die Frequenzen ohnehin oft gewechselt werden und eh nur kein Schwei* sich mehr für
Kurzwelle interessiert, sollte dieser Kommentar kein Problem sein, oder?
Analysiert man diese Zahlenreihen, so wird man auf sehr wenige Wiederholungen oder gar keine stoßen.
Denn solche Wiederholungen erleichtern die Arbeit der Dechiffrierung in feindlichen Abteilungen sehr.
Erzeugen kann man solche "echten" Zufallszahlen über das Verhalten bestimmter Halbleiter,
Zehnerspannung oder das Raschverhalten bei Transistoren werden hierfür benutzt.
siehe auch
https://de.wikipedia.org/wiki/Rauschgeneratoroder
https://www.subroutine.info/elektronik/zufallsgenerator/
http://www.ibbergmann.org/GRUNDLAGEN/
http://www.jtxp.org/tech/xr232web.htmMehr zu Zimmermann:
https://de.wikipedia.org/wiki/Phil_ZimmermannWer weniger Lust zum Löten hat:
https://www.laser2000.de/de/signal-generatoren/1848-quanten-zufallszahlengenerator.html
-
Sorry sollte Rauschverhalten bei Transistoren(Unschärferelation beachten!) heißen.
-
@rustyoldguy sagte in Zufallszahlen:
Wer weniger Lust zum Löten hat:
Der besorgt sich einen Internet-Zugang: https://www.random.org/