Discussion:
[srand()/rand()] Ich brauche mehr Chaos.
(zu alt für eine Antwort)
Michael Uplawski
2025-03-09 09:47:11 UTC
Permalink
Moin.

In einer Textdatei befinden sich eine große Anzahl von „Signaturen”
– die ich augenblicklich nur in de.test verwende.

Die zufällige Auswahl einer Signatur scheint mir Schwierigkeiten zu
machen, da, beim wiederholten Testen, ca. fünf Signaturen ständig
wiederkehren, ungefähr ab dem zehnten Versuch auch noch einmal
herausgefischt werden, und nur ab und an eine andere Signatur
gewählt wird.

Um „Zufall” zu macheh, kenne ich nichts anderes als srand() und
rand().

Der Code lässt sich leicht hier reproduzieren:
----------------------------- RUBY -------------------
# pick a random signature, if a list is available.
def pick_sig(sigfile)
debug 'picking signature from ' << sigfile.to_s
if sigfile && !sigfile.empty? && File.exist?(sigfile) && File.readable?(sigfile)
allSigs = File::read(sigfile).split("\n\n")
numSigs = allSigs.length
srand(Time.now.nsec)
allSigs[rand(numSigs)]
else
error 'Cannot read signature from file ' << sigfile
nil
end
end
------------------------------------------------------

Habt Ihr einen Tipp dazu, wie ich das aufmotzen muss, damit mehr
Chaos herrscht?

Herzlichen Dank und schönen Sonntag.
(In der Normandie wird's wieder grau)

Michael
--
Geh Kaffee kochen!
Michael Uplawski
2025-03-09 17:39:55 UTC
Permalink
Michael Uplawski wrote in de.comp.lang.misc:

(…)
Post by Michael Uplawski
Um „Zufall” zu macheh, kenne ich nichts anderes als srand() und
rand().
Eine Idee wäre, die ganze Liste nach jedem Gebrauch zufällig zu
sortieren und in dieser Form in die Datei zurückzuschreiben.

Das würde zumindest die Ausgangssituation für den nächsten Durchlauf
verändern. Den Dateizugriff möchte ich mir freilich sparen, wenn es
anders geht.
--
Geh Kaffee kochen!
Tim Landscheidt
2025-03-09 19:11:12 UTC
Permalink
Post by Michael Uplawski
(…)
Post by Michael Uplawski
Um „Zufall” zu macheh, kenne ich nichts anderes als srand() und
rand().
Eine Idee wäre, die ganze Liste nach jedem Gebrauch zufällig zu
sortieren und in dieser Form in die Datei zurückzuschreiben.
Das würde zumindest die Ausgangssituation für den nächsten Durchlauf
verändern. Den Dateizugriff möchte ich mir freilich sparen, wenn es
anders geht.
Wenn Du Dein Script 10000 Auswahlen treffen lässt, wie sieht
die Verteilung aus?

Tim
Michael Uplawski
2025-03-10 06:33:47 UTC
Permalink
Moin II
Post by Tim Landscheidt
Post by Michael Uplawski
(…)
Post by Michael Uplawski
Um „Zufall” zu macheh, kenne ich nichts anderes als srand() und
rand().
Eine Idee wäre, die ganze Liste nach jedem Gebrauch zufällig zu
sortieren und in dieser Form in die Datei zurückzuschreiben.
Das würde zumindest die Ausgangssituation für den nächsten Durchlauf
verändern. Den Dateizugriff möchte ich mir freilich sparen, wenn es
anders geht.
Wenn Du Dein Script 10000 Auswahlen treffen lässt, wie sieht
die Verteilung aus?
Interessant. Ich werde versuchen, eine Statistik zu generieren und
dazu auch die Umsortierung in der Datei nochmal ausschalten.

Ich muss wieder physisch arbeiten, versuche aber am Abend wieder das
Hirn anzustrengen, vorausgesetzt, ich kann noch gerade sitzen.

Cheerio
Post by Tim Landscheidt
Tim
--
Geh Kaffee kochen!
Sieghard Schicktanz
2025-03-09 19:10:00 UTC
Permalink
Hallo Michael,
Post by Michael Uplawski
Die zufällige Auswahl einer Signatur scheint mir Schwierigkeiten zu
...
Post by Michael Uplawski
----------------------------- RUBY -------------------
# pick a random signature, if a list is available.
...
Post by Michael Uplawski
srand(Time.now.nsec)
allSigs[rand(numSigs)]
...
Post by Michael Uplawski
------------------------------------------------------
_Könnte_ es evtl. daran liegen, daß der Zufallsgenerator jedesmal wieder
auf einen "ähnlichen" Anfangswert gesetzt wird?
--
(Weitergabe von Adressdaten, Telefonnummern u.ä. ohne Zustimmung
nicht gestattet, ebenso Zusendung von Werbung oder ähnlichem)
-----------------------------------------------------------
Mit freundlichen Grüßen, S. Schicktanz
-----------------------------------------------------------
Michael Uplawski
2025-03-10 06:30:38 UTC
Permalink
Moin.
Post by Sieghard Schicktanz
Hallo Michael,
Post by Michael Uplawski
Die zufällige Auswahl einer Signatur scheint mir Schwierigkeiten zu

Post by Michael Uplawski
----------------------------- RUBY -------------------
# pick a random signature, if a list is available.

Post by Michael Uplawski
srand(Time.now.nsec)
allSigs[rand(numSigs)]

Post by Michael Uplawski
------------------------------------------------------
_Könnte_ es evtl. daran liegen, daß der Zufallsgenerator jedesmal wieder
auf einen "ähnlichen" Anfangswert gesetzt wird?
Ich kenne mich mit PRNGs nicht aus. Mein Verständnis war bisher,
dass ein abweichender Seed-Wert für ausreichende Variationen sorgen
sollte. Darum habe ich sofort auf Nano-Sekunden gesetzt. M.E. wird
das bei anderen Gelegenheiten als Overkill betrachtet… Aber wie
gesagt, ich kenne mich nicht aus.

Es war leider auch so, dass beim wiederholten Testen, lokal auf
meinem Rechner und ohne Postings über das Netz zu schicken,
ebenfalls immer eine Signatur aus einer recht beschränkten Menge
gefischt wurde.

Würde mir jemand sagen, dass die Ruby-Implementierung von irgendwas
an allem Schuld ist, möchte ich das gerne glauben.
--
Geh Kaffee kochen!
Thomas Noll
2025-03-10 16:02:57 UTC
Permalink
Post by Michael Uplawski
Würde mir jemand sagen, dass die Ruby-Implementierung von irgendwas
an allem Schuld ist, möchte ich das gerne glauben.
Halte ich für unwahrscheinlich. Falls das aber beim rand/srand so sein sollte,
die brauchst du ja sowieso nicht. Wenn du den seed für hinreichend
zufällig hältst, kannst du den bei einmaliger Verwendung auch direkt nehmen.
Z.b.

allSigs[Time.now.nsec%numSigs]

Überprüfen solltest du aber auch den split. Ist der Input wirklich durch
"\n\n" getrennt? Wieviele Einträge hat die Datei, wie viele das Array?
Stefan Reuther
2025-03-10 17:13:46 UTC
Permalink
Post by Michael Uplawski
Post by Sieghard Schicktanz
Post by Michael Uplawski
srand(Time.now.nsec)
allSigs[rand(numSigs)]
_Könnte_ es evtl. daran liegen, daß der Zufallsgenerator jedesmal wieder
auf einen "ähnlichen" Anfangswert gesetzt wird?
Ich kenne mich mit PRNGs nicht aus. Mein Verständnis war bisher,
dass ein abweichender Seed-Wert für ausreichende Variationen sorgen
sollte.
Die Frage ist, wieviele der Bits von 'Time.now.nsec' durch 'srand'
ausgewertet werden - und andererseits, wieviele der Bits überhaupt
gültig sind. Der klassische C-Zufallsgenerator nutzt nur 15 Bit. Und
wenn im Extremfall dein Betriebssystem die Zeit in Zeitscheiben von 16
Millisekunden misst, und dir folglich als Nanosekunden nur Vielfache von
16000000 gibt, hast du von den 15 Bit schon 11 verloren.

Ich würde als Seed für den Zufallsgenerator immer ein paar Bytes aus
/dev/urandom benutzen.

Wenn du das nicht hast, dann wenigstens die Nanosekunden irgendwie mit
xor zusammenfalten (also in C sowas wie 'x ^= (x >> 16)') und ggf. die
pid mit einbeziehen.


Stefan
Tim Landscheidt
2025-03-10 17:59:11 UTC
Permalink
Post by Stefan Reuther
Post by Michael Uplawski
Post by Sieghard Schicktanz
Post by Michael Uplawski
srand(Time.now.nsec)
allSigs[rand(numSigs)]
_Könnte_ es evtl. daran liegen, daß der Zufallsgenerator jedesmal wieder
auf einen "ähnlichen" Anfangswert gesetzt wird?
Ich kenne mich mit PRNGs nicht aus. Mein Verständnis war bisher,
dass ein abweichender Seed-Wert für ausreichende Variationen sorgen
sollte.
Die Frage ist, wieviele der Bits von 'Time.now.nsec' durch 'srand'
ausgewertet werden - und andererseits, wieviele der Bits überhaupt
gültig sind. Der klassische C-Zufallsgenerator nutzt nur 15 Bit. Und
wenn im Extremfall dein Betriebssystem die Zeit in Zeitscheiben von 16
Millisekunden misst, und dir folglich als Nanosekunden nur Vielfache von
16000000 gibt, hast du von den 15 Bit schon 11 verloren.
Ich würde als Seed für den Zufallsgenerator immer ein paar Bytes aus
/dev/urandom benutzen.
Wenn du das nicht hast, dann wenigstens die Nanosekunden irgendwie mit
xor zusammenfalten (also in C sowas wie 'x ^= (x >> 16)') und ggf. die
pid mit einbeziehen.
Ich kenne mich mit Ruby nicht aus, aber
https://ruby-doc.org/3.3.7/Kernel.html#method-i-srand sagt:

| […]

| srand(number = Random.new_seed) → old_seed

| Seeds the system pseudo-random number generator, with num-
| ber. The previous seed value is returned.

| If number is omitted, seeds the generator using a source of
| entropy provided by the operating system, if available
| (/dev/urandom on Unix systems or the RSA cryptographic pro-
| vider on Windows), which is then combined with the time, the
| process id, and a sequence number.

| […]

Das hört sich an, als ob der Aufruf ohne Parameter sinnvol-
ler sein sollte.

Tim
Michael Uplawski
2025-03-11 06:52:35 UTC
Permalink
Moin.
Post by Tim Landscheidt
Post by Stefan Reuther
Ich würde als Seed für den Zufallsgenerator immer ein paar Bytes aus
/dev/urandom benutzen.
(…)
Post by Tim Landscheidt
| If number is omitted, seeds the generator using a source of
| entropy provided by the operating system, if available
| (/dev/urandom on Unix systems or the RSA cryptographic pro-
| vider on Windows), which is then combined with the time, the
| process id, and a sequence number.
| […]
Das hört sich an, als ob der Aufruf ohne Parameter sinnvol-
ler sein sollte.
Ein Beispiel dafür, dass „Erfahrung” relatif ist (relatif wichtig,
relatif zuverlässig etc.). Der Hilfetext zu srand() (:^$ ri srand)
enthält dieselbe Passage, ich nehme an, dass die Web-Seite nur die
Reproduktion ist. Wann habt Ihr zuletzt man srand gelesen? „Man”
weiß ja, wie das geht, nüch…

Danke in jedem Fall. Ich werde alle Vorschläge testen.

Cheerio
--
Geh Kaffee kochen!
Michael Uplawski
2025-03-12 06:46:44 UTC
Permalink
Post by Michael Uplawski
Danke in jedem Fall. Ich werde alle Vorschläge testen.
Letzte Nacht hatte ich Kopfschmerzen und habe darum – weil es
manchmal hilft – ausgewertet, wie sich der Wechsel zwischen
srand(Time.now.nsec) und srand() auf die die zufällige Auswahl von
Signaturen auswirkt.

1000 mal habe ich ein Posting erzeugt und eine Signatur zufällig
gesetzt. $1 ist eine Datei, in die die Liste der ausgewählten
Signaturen geschrieben wird, „post_de_test“ ist ein Post, wie er von
flnews an den Post-Prozessor geliefert wird.
------------
for f in `seq 1 1000`
do
../../bin/flnews_post_proc < ../post_de_test | grep "\-\- " -A 5 -- >> "$1"
done
----------

Dann habe ich gezählt, mit der jeweiligen Liste in ARGV[0]:
-------------
#!/usr/env ruby

File.open(ARGV[0]) do |f|
visited = Array.new
sigs = f.readlines('-- ', chomp: true)
sigs.each do |s|
if !visited.include?(s)
puts s.dup << ": " << sigs.count(s).to_s
visited << s
end
end
puts "Number of used sigs: " << visited.length.to_s
end
-------------

Es fehlt im Ergebnis keine der 33 unterschiedlichen Signaturen, jede
einzelne wurde bei srand() zwischen 18 und 44 mal ausgewählt. Eine
Häufung gibt es vielleicht bei 33.

Bei srand(Time.now.nsec) werden einzelne Signaturen zwischen 21 und
41 mal gesetzt. Es fehlt ebenfalls keine der ursprünglichen
Signaturen. Eine Häufung einzelner Zahlen sehe ich kaum.

Sicherlich kann ich den Vorgang noch ein paar Mal wiederholen.
Tatsächlich glaube ich aber nicht mehr, dass es tatsächlich einen
großen Unterschied macht, wie der seed-Wert ermittelt wird.

Meine ursprüngliche Beobachtung ist wahrscheinlich nicht
repräsentativ für die Ausgabe des PRNG. Mehr noch als vorher fehlt
mir jetzt jede Erklärung.
--
Geh Kaffee kochen!
Michael Uplawski
2025-03-13 06:29:58 UTC
Permalink
Post by Michael Uplawski
Bei srand(Time.now.nsec) werden einzelne Signaturen zwischen 21 und
41 mal gesetzt. Es fehlt ebenfalls keine der ursprünglichen
Signaturen. Eine Häufung einzelner Zahlen sehe ich kaum.
(…)
Post by Michael Uplawski
Meine ursprüngliche Beobachtung ist wahrscheinlich nicht
repräsentativ für die Ausgabe des PRNG. Mehr noch als vorher fehlt
mir jetzt jede Erklärung.
Vielleicht muss ich bereits während des Auswählens der 1000
Signaturen den Vorgang anhalten, sobald die Differenz der Treffer
„signifikant” wird. Ich denke an die Möglichkeit, dass eine initiale
Häufung von Treffern sukzessive ausgemerzt wird.

Das liest sich schön.

Bis auf weiteres lasse ich das mal ruhen, glaube ich. ;)

Version 1.71 meines Post-Prozessors für flnews >1 arbeitet mit
Nanosekunden und sortiert die bekannten Signaturen jedes Mal um. Das
bleibt bis auf weiteres so.

Cheerio
----------------
1) Readme: <https://www.rubydoc.info/gems/flnews_post_proc/1.71>
--
Geh Kaffee kochen!
Michael Uplawski
2025-03-13 06:30:43 UTC
Permalink
Supersedes wegen Ω im Subject.
Post by Michael Uplawski
Bei srand(Time.now.nsec) werden einzelne Signaturen zwischen 21 und
41 mal gesetzt. Es fehlt ebenfalls keine der ursprünglichen
Signaturen. Eine Häufung einzelner Zahlen sehe ich kaum.
(…)
Post by Michael Uplawski
Meine ursprüngliche Beobachtung ist wahrscheinlich nicht
repräsentativ für die Ausgabe des PRNG. Mehr noch als vorher fehlt
mir jetzt jede Erklärung.
Vielleicht muss ich bereits während des Auswählens der 1000
Signaturen den Vorgang anhalten, sobald die Differenz der Treffer
„signifikant” wird. Ich denke an die Möglichkeit, dass eine initiale
Häufung von Treffern sukzessive ausgemerzt wird.

Das liest sich schön.

Bis auf weiteres lasse ich das mal ruhen, glaube ich. ;)

Version 1.71 meines Post-Prozessors für flnews >1 arbeitet mit
Nanosekunden und sortiert die bekannten Signaturen jedes Mal um. Das
bleibt bis auf weiteres so.

Cheerio
----------------
1) Readme: <https://www.rubydoc.info/gems/flnews_post_proc/1.71>
--
Geh Kaffee kochen!
Martin Klaiber
2025-03-16 11:00:17 UTC
Permalink
In einer Textdatei befinden sich eine große Anzahl von »Signaturen»
- die ich augenblicklich nur in de.test verwende.
Die zufällige Auswahl einer Signatur scheint mir Schwierigkeiten zu
machen, da, beim wiederholten Testen, ca. fünf Signaturen ständig
wiederkehren, ungefähr ab dem zehnten Versuch auch noch einmal
herausgefischt werden, und nur ab und an eine andere Signatur
gewählt wird.
Um »Zufall» zu macheh, kenne ich nichts anderes als srand() und
rand().
----------------------------- RUBY -------------------
# pick a random signature, if a list is available.
def pick_sig(sigfile)
debug 'picking signature from ' << sigfile.to_s
if sigfile && !sigfile.empty? && File.exist?(sigfile) && File.readable?(sigfile)
allSigs = File::read(sigfile).split("\n\n")
numSigs = allSigs.length
srand(Time.now.nsec)
allSigs[rand(numSigs)]
else
error 'Cannot read signature from file ' << sigfile
nil
end
end
------------------------------------------------------
Habt Ihr einen Tipp dazu, wie ich das aufmotzen muss, damit mehr
Chaos herrscht?
Muss es unbedingt ein Ruby-Programm sein?

Laut Header benutzt Du Linux, reicht da nicht ein:

shuf sigfile | head -1

um eine Signatur auszuwählen, oder alternativ "unsort -r", falls es
"shuf" bei Dir nicht gibt?

Das ergibt bei mir für Deinen Zweck ausreichend zufällige Ergebnisse.

Hier mal 1000 Durchläufe einer Datei mit 30 Zeilen. Angegeben ist die
Häufigkeit, mit der jede Zeile ausgegeben wird (pseudographisch für die
Anschaulichkeit):

1 |***********************************....|.........|
2 |************************************...|.........|
3 |*********************************......|.........|
4 |*********************************......|.........|
5 |*****************************************........|
6 |*************************************..|.........|
7 |*********************************......|.........|
8 |*********************************......|.........|
9 |******************************.........|.........|
10 |********************************.......|.........|
11 |********************************.......|.........|
12 |**************************************.|.........|
13 |***********************************....|.........|
14 |**************************...|.........|.........|
15 |*****************************************........|
16 |*********************************......|.........|
17 |**********************************.....|.........|
18 |*********************************......|.........|
19 |******************************.........|.........|
20 |*********************************......|.........|
21 |****************************.|.........|.........|
22 |******************************.........|.........|
23 |*********************************......|.........|
24 |**********************************.....|.........|
25 |************************************...|.........|
26 |**************************...|.........|.........|
27 |********************************.......|.........|
28 |*****************************|.........|.........|
29 |***************************************|.........|
30 |***********************************....|.........|
| | | | | |
0 10 20 30 40 50

Das variiert natürlich von Aufruf zu Aufruf.

Hier das schnell zusammengehackte Testprogramm für die obige Ausgabe:

--- schnipp ---

#!/bin/bash

DAT=/tmp/random-test

# Datei mit n Zeilen erstellen:
n=30

# Datei erstellen:
echo 1 > $DAT
for i in $(seq 2 $n)
do
echo $i >> $DAT
done

# Array erstellen:
for i in $(seq 1 $n)
do
a[$i]=0
done

# Test:
max=0
for k in $(seq 1000)
do
# w=$(unsort -r $DAT | head -1)
w=$(shuf $DAT | head -1)
o=$(( ${a[$w]} + 1 ))
a[$w]=$o
if [ $o -gt $max ]
then
max=$(( $o / 10 * 10 + 10 ))
fi
# echo $w $o $max
done

# Auswertung:
# echo ${a[*]}
for i in $(seq 1 $n)
do
printf "%2d |" $i
for k in $(seq 1 ${a[$i]})
do
printf "*"
done
for k in $(seq $(( ${a[$i]} + 1 )) $max)
do
if [ $(( $k % 10 )) -eq 0 ]
then
printf "|"
else
printf "."
fi
done
echo
done

printf " "
for k in $(seq 0 $max)
do
if [ $(( $k % 10 )) -eq 0 ]
then
printf "|"
else
printf " "
fi
done
echo

printf " 0"
for k in $(seq 1 $max)
do
if [ $(( $k % 10 )) -eq 0 ]
then
printf "%10d" $k
fi
done
echo

--- schnapp ---

Martin
Michael Uplawski
2025-03-16 11:38:34 UTC
Permalink
Post by Martin Klaiber
Muss es unbedingt ein Ruby-Programm sein?
Siehe <news:***@ferrat.uplawski.eu>, d.h.
meinen letzten Beitrag in diesem Thread und dort das Ende des Posts.

Das Ruby-Programm gibt es schon länger und es macht mehr, als
Signaturen setzen. :)

Der Einfachheit wegen nochmal der Link zum Readme:
<https://www.rubydoc.info/gems/flnews_post_proc/1.71>

Das zum aktuellen Thema. Generell gefällt mir Ruby besser als alle
anderen Sprachen. Auch, wenn ich der schnellen Abfolge von Versionen
nicht immer folge, drücke ich mich in Ruby „natürlicher” aus, als in
Bash.

Cheerio

Michael
--
Geh Kaffee kochen!
Patrick Rudin
2025-03-16 13:56:30 UTC
Permalink
Post by Martin Klaiber
Muss es unbedingt ein Ruby-Programm sein?
Echte Kerle machen das doch mit R

library(tidyverse)

sigs <- tibble(text=c("Guten Morgen","Guten Abend","Linux ist
cool","Rettet die Welt","Tötet Windows","Huldigt Linus","Das ist keine
Normalverteilung","R ist cooler als Ruby"))


sigs %>%
slice_sample(n=10000, replace=T) %>%
count(text) %>%
mutate(anteil=n*100/sum(n))


# A tibble: 8 × 3
text n anteil
<chr> <int> <dbl>
1 Das ist keine Normalverteilung 1286 12.9
2 Guten Abend 1232 12.3
3 Guten Morgen 1275 12.8
4 Huldigt Linus 1250 12.5
5 Linux ist cool 1212 12.1
6 R ist cooler als Ruby 1232 12.3
7 Rettet die Welt 1208 12.1
8 Tötet Windows 1305 13.0

Man spürt die Tendenz...


SCNR

Patrick

Loading...