Permalänk
Medlem

Skapa slumpgenerator

Har en uppgift att göra en slumpgenerator, men hur jag än gör så får jag den inte att slumpa bra.
Vad menas med "Läs bit 15..8 från varje xi?

#Python3 from datetime import datetime #Functions def declare_var(): x = int(datetime.now().strftime("%f")) #Start value, get current time in ms n=1000 #loops numbers_n = [0]*10000 return x,n,numbers_n def results(numbers_n): i = 0 while i < 10000: #10000 = size of list numbers_n if numbers_n[i] != 0: print ("The number", i , "occured", numbers_n[i], "time(s)") i+=1 def slump(x,n,numbers_n): while 0 < n: x = int(((25173*x+13849)%65536)/128) #2¹⁶ = 65536 2⁷ = 128 numbers_n[x] += 1 #current number occured += 1 time n-=1 return numbers_n def main(): x,n,numbers_n = declare_var() numbers_n = slump(x,n,numbers_n) results(numbers_n) ### #Code main() ###

Permalänk
Medlem

Exempel output:

[user@localhost Python3_stuff]$ python3 slumptal_2.py The number 33 occured 1 time(s) The number 47 occured 1 time(s) The number 112 occured 1 time(s) The number 118 occured 1 time(s) The number 135 occured 1 time(s) The number 186 occured 248 time(s) The number 234 occured 1 time(s) The number 274 occured 1 time(s) The number 289 occured 1 time(s) The number 305 occured 248 time(s) The number 335 occured 248 time(s) The number 454 occured 248 time(s)

Permalänk
Medlem

Ofta består ju en integer av 16 bitar (beror på programspråk och implementation).
Dvs, en (unsigned) integer kan hålla ett värde mellan 0 och 65535 (2^16-1).
Om talet är 65 535, så är alla 16 bitar satta. Dvs: 1111111111111111
Om du ska ha bitar 15..8 så måste du välja ut dessa på något vis, dvs du vill kasta bort de lägsta 8 bittarna (bittar är nollindexerade) så kan du som det föreslås att antingen skifta ut dessa eller dividera.
I python skiftar man genom att använda >>-operatorn, precis som i Java och C.

Visa signatur

Jag är en optimist; det är aldrig så dåligt så att det inte kan bli sämre.

Permalänk
Medlem

>Ofta består ju en integer av 16 bitar
Nej, oftast är det 32 bitar. Om du nu inte sitter och kodar C på en 16 bitars processor.

>Vad menas med "Läs bit 15..8 från varje xi?
När du gör modulo 2¹⁶ så begränsar du bitlängden till 16 bitar (0-15)
När du sedan skiftar 7 bitar (eller dividerar med 2⁷, resultatet är samma) så kastar
du bort de 7 lägsta bitarna och "flyttar ner" de 9 översta och får då värdet på bit
0-8 (tidigare 15...7).

Så för att läsa ut bit 15...8 ska du alltså skifta 8 bitar (eller dividera med 2⁸).

Permalänk
Medlem

Dåligt formulerad fråga i min mening...

Bit 15...8 tolkar jag som att du ska läsa ut från och med bit 8 till och med bit 15. Mod 2^16 klipper allt över bit 15. Och /128 eller >>7 klipper allt under bit 8.

Felet du gör ser ut att vara att du dividerar x med 128. Din slumpdata ut ska divideras med 128. Men x som ska gå in i nästa iteration ska inte divideras med 128.

#!/usr/bin/python # -*- coding: utf-8 -*- from datetime import datetime def slump(): x = int(datetime.now().strftime("%f")) #Start value, get current time in ms numbers_n = [0]*512 for i in range(100000): # loops x = (25173*x+13849)%65536 r = x/128 # or r = x>>7 #print r numbers_n[r] += 1 return numbers_n print slump()

ger:

207, 196, 196, 203, 191, 192, 199, 187, 190, 185, 201, 199, 190, 187, 197, 192, 199, 191, 193, 193, 192, 206, 196, 191, 193, 191, 201, 193, 200, 182, 196, 186, 200, 198, 192, 205, 201, 202, 187, 208, 196, 194, 197, 189, 200, 193, 195, 190, 199, 188, 200, 198, 190, 192, 198, 195, 201, 198, 194, 195, 205, 194, 195, 192, 197, 193, 194, 190, 192, 203, 192, 192, 202, 196, 188, 195, 192, 185, 205, 191, 191, 203, 209, 195, 204, 203, 199, 187, 196, 195, 194, 191, 197, 193, 193, 193, 196, 197, 202, 195, 198, 199, 192, 190, 193, 201, 193, 197, 189, 197, 201, 194, 186, 210, 192, 199, 199, 187, 191, 193, 199, 200, 193, 202, 194, 182, 205, 195, 187, 196, 193, 197, 199, 198, 196, 189, 200, 193, 194, 196, 208, 201, 190, 190, 193, 184, 209, 189, 191, 198, 201, 194, 192, 198, 200, 196, 192, 203, 196, 195, 192, 193, 196, 198, 201, 201, 201, 189, 196, 190, 195, 187, 208, 200, 197, 194, 189, 191, 196, 194, 205, 193, 199, 200, 196, 205, 196, 197, 206, 193, 192, 198, 203, 199, 209, 195, 191, 200, 196, 201, 206, 191, 196, 199, 194, 202, 189, 188, 200, 197, 201, 196, 201, 196, 191, 201, 191, 192, 188, 191, 196, 189, 196, 195, 198, 196, 189, 196, 190, 189, 186, 198, 200, 182, 194, 190, 197, 193, 205, 199, 192, 195, 204, 211, 205, 192, 195, 199, 188, 191, 198, 198, 195, 197, 193, 214, 186, 194, 199, 186, 201, 200, 187, 203, 199, 204, 189, 193, 199, 202, 190, 198, 189, 197, 194, 198, 200, 186, 192, 197, 196, 201, 186, 198, 190, 208, 197, 202, 194, 194, 201, 185, 191, 190, 204, 188, 199, 200, 193, 200, 192, 195, 192, 201, 193, 204, 195, 197, 203, 199, 194, 197, 193, 192, 199, 194, 188, 197, 200, 194, 200, 197, 194, 199, 196, 187, 205, 196, 187, 192, 206, 197, 197, 202, 187, 195, 195, 193, 181, 192, 183, 187, 186, 203, 195, 202, 194, 200, 197, 202, 200, 197, 191, 195, 186, 195, 190, 189, 200, 198, 197, 191, 196, 193, 197, 192, 190, 194, 202, 182, 197, 188, 190, 200, 200, 198, 193, 189, 199, 193, 192, 205, 188, 195, 202, 194, 197, 195, 193, 192, 195, 202, 188, 196, 193, 192, 184, 192, 205, 204, 195, 205, 185, 202, 198, 191, 189, 196, 195, 190, 192, 196, 202, 191, 192, 201, 199, 194, 191, 190, 189, 195, 186, 202, 192, 198, 196, 203, 182, 187, 192, 197, 199, 197, 190, 197, 186, 194, 192, 190, 198, 189, 192, 198, 190, 197, 198, 195, 185, 192, 185, 194, 198, 192, 194, 190, 187, 196, 198, 192, 198, 194, 199, 199, 194, 193, 188, 200, 186, 199, 198, 187, 199, 199, 199, 203, 191, 201, 196, 195, 192, 196, 205, 200, 206, 205, 203, 192, 190, 206, 201, 199, 197, 203, 187, 193, 202, 197, 192, 178, 190, 197, 199, 192, 202, 200, 192, 190, 194, 193, 197, 180

Permalänk
Medlem
Skrivet av Genesis:

Verkar detta random och bra då, eller finns det någon nackdel?

from datetime import datetime import time #Functions #Declare stuff def declare_var(): n = int(input("Loops: ")) numbers_n = [0]*2100 return n, numbers_n # #Print outcome def results(numbers_n): i = 0 while i < 2100: #size of list numbers_n if numbers_n[i] != 0: print ("The number", i , "occured", numbers_n[i], "time(s)") i+=1 # #Get random number, add to list, sleep def slump(x,numbers_n): rand_number = int(((25173*x+13849)%65536) >> 7) #2¹⁶ = 65536 2⁷ = 128 numbers_n [rand_number] += 1 #current number occured += 1 time #Sleep to make next number more random time.sleep(x/1000000000) time.sleep(rand_number/500000) return numbers_n # #call slump()*loops def loop(n,numbers_n): x = int(datetime.now().strftime("%f")) #Start value, get current time in ms numbers_n = slump(x,numbers_n) while n > 1: loop(n-1,numbers_n) return numbers_n else: return numbers_n # #Main def main(): n, numbers_n = declare_var() numbers_n = loop(n,numbers_n) results(numbers_n) # ### #Code main() ###

Loops: 5 The number 67 occured 1 time(s) The number 115 occured 1 time(s) The number 154 occured 1 time(s) The number 258 occured 1 time(s) The number 365 occured 1 time(s)

Permalänk
Medlem

Jag förstår inte alls vad du håller på med. Det där stämmer inte alls överens med vad som frågas efter. x ska vara x från förra körningen, inte nytt värde baserat på tid varje gång. Vilket du verkade förstå i din första version av ditt program.
I frågan står det: x_n+1 = ((25173*x_n) + 13849) % 65536)
inte: x_n+1 = ((25173*tid) + 13849) % 65536)
Att du själv valt att sätta x_0 till ett värde baserat på tiden är ett bra initiativ, då frågan inte säger något om initialvärdet för x. Men du kan inte förändra frågan till att alltid, inte enbart initialt, använda tiden som invärde till formeln.

Det enda felet du gjorde först var att du dividerade x med 128. Nu har du inte rättat till ditt fel, utan hittat på en helt ny och egen lösning som inte är i närheten av vad som frågas efter.

Och att testa fem gånger när talen varierar mellan 0 och 511? Det är på tok för få körningar för att testa din slumpgenerator. Med så få körningar så hade du ju inte upptäckt felen i din förra kod.

Jag har skrivit den fulla fungerande koden i mitt första inlägg. (Jag har plockat bort allt onödigt junk från din kod bara, för att få den mer lättläst)
Är det någon del av den som du inte förstår? Förstår du fortfarande inte vad som frågas efter? Är du ovan med programmering i allmänhet? Eller är du bara ovan med python?

Permalänk
Medlem
Skrivet av Genesis:

Jag förstår inte alls vad du håller på med. Det där stämmer inte alls överens med vad som frågas efter. x ska vara x från förra körningen, inte nytt värde baserat på tid varje gång. Vilket du verkade förstå i din första version av ditt program.
I frågan står det: x_n+1 = ((25173*x_n) + 13849) % 65536)
inte: x_n+1 = ((25173*tid) + 13849) % 65536)
Att du själv valt att sätta x_0 till ett värde baserat på tiden är ett bra initiativ, då frågan inte säger något om initialvärdet för x. Men du kan inte förändra frågan till att alltid, inte enbart initialt, använda tiden som invärde till formeln.

Det enda felet du gjorde först var att du dividerade x med 128. Nu har du inte rättat till ditt fel, utan hittat på en helt ny och egen lösning som inte är i närheten av vad som frågas efter.

Och att testa fem gånger när talen varierar mellan 0 och 511? Det är på tok för få körningar för att testa din slumpgenerator. Med så få körningar så hade du ju inte upptäckt felen i din förra kod.

Jag har skrivit den fulla fungerande koden i mitt första inlägg. (Jag har plockat bort allt onödigt junk från din kod bara, för att få den mer lättläst)
Är det någon del av den som du inte förstår? Förstår du fortfarande inte vad som frågas efter? Är du ovan med programmering i allmänhet? Eller är du bara ovan med python?

Hey, go easy on him. Han verkar ju uppenbart vara under upplärning.

Själv förstår jag inte ett skvatt av det här. Ni verkar high tech ^^

Visa signatur

🖥 AMD 5600X (+ Noctua NH-L9a-AM4 chromax.black) | ROG Strix B550-I | 32GB Corsair Vengeance 3600Mhz | Asus TUF RTX 4070 Ti | Samsung 980 Pro NVMe | Corsair SF600 | Lian Li A4-H2O | 2 x Noctua NF-A12x25 | Acer Predator XB271HU | ⌨️ Varmilo VA109M | 🖱 Razer Deathadder V2

Permalänk
Medlem
Skrivet av Gling:

Hey, go easy on him. Han verkar ju uppenbart vara under upplärning.

Själv förstår jag inte ett skvatt av det här. Ni verkar high tech ^^

Var jag hård mot honom tycker du? Det upplevde inte jag, och menade jag inte heller.

Så som han frågar så tycker jag det känns ganska uppenbart att han har svårigheter för något mer än enbart denna skoluppgiften. Så att jag i detalj förklarar vad han har gjort för fel, och försöker fiska mer för vad han har svårt för, är inte för att visa mig stöddig och säga att jag kan mer än honom. Utan för att försöka vara så tydlig som möjlig så att han förhoppningsvis förstår mer utan att missuppfatta det hela.

Det är svårt att förklara något för någon när man inte förstår vad det är i problemet som personen i fråga inte förstår fullt ut. Och då hans första kod var ganska nära rätt med bara ett litet fel så tolkade jag det först som att han förstod det mesta av det, och att jag inte behövde förklara så ingående.

Permalänk
Medlem
Skrivet av Genesis:

Jag uppskattar din kritik.
Nu ska det fungera som i uppgiften hade jag tänkt:
http://pastebin.com/adL3AuMT

Men efter ett tag verkar den hänga sig och adderar samma värde om igen.
Är det fel i (((25173*x+13849)%65536) >> 7) eller i min kod?
The number 3 occured 1 time(s)
The number 186 occured 90 time(s)
The number 228 occured 1 time(s)
The number 305 occured 89 time(s)
The number 335 occured 90 time(s)
The number 403 occured 1 time(s)
The number 454 occured 89 time(s)

Edit: får samma problem när jag ändrade min gamla kod http://pastebin.com/aDiF6asc

Permalänk
Medlem

Då ska vi se om jag kan förtydliga det hela mer:

Nu är vi tillbaka till samma läge som din första kod, fast med mer kod runt om kring, men det är exakt samma felaktiga system för att generera slumptalen.

Du gör fortfarande fel med x, och följer inte (så som jag tolkar) uppgiften.
Du dividerar inte längre x med 128, utan shiftar det 7 steg åt höger. Men det spelar ingen roll vilken av de två du gör. Att dividera ett tal med 2^n (heltalsdividering där inte decimalerna tas med) ger alltid samma resultat som att shifta det n steg åt höger.

Det kanske kan vara lättare att tänka i bas 10 om du inte förstår detta, där ett tal dividerat med 10^n där man sedan plockar bort decimalerna (ej avrundning) ger samma resultat som att man plockar bort n siffror till höger i talet.
exempelvis:
123456 / 10^2 = 1234 (observera att det är heltalsdivision och saknar avrundning eller decimaler)
123456 >> 2 = 1234 (om vi shiftar i bas 10)

Dold text

Du ska dock varken dividera med 128 eller shifta det 7 steg åt höger. Så att byta från dividering till shiftning löser ej problemet.
X är inte ditt slumptal. X är ett värde som tas in i din beräkning, och kommer ut ur beräkningen, men är inte det slutgiltiga slumpvärdet som du är ute efter.

Den korrekta beräkningen för x är:
x = (25173*x+13849)%65536
Observera att det inte tar med /128 eller >>7 (som gör samma sak).

Alla delar är alltid heltal i fromeln, så du behöver inte casta till int, men om du föredrar det av någon anledning så kan du använda
x = int((25173*x+13849)%65536)

Dold text

Ditt slumptal får du om du dividerar x med 128 eller shiftar det 7 steg åt höger (vilket är identiskt).
Ditt slumptal är inte x, och ska inte gå tillbaka in i formeln för att beräkna nästa x.
Jag hanterade slumptalet i min kod med att skapa en ny variabel vid namn r (för random), som jag gerererade från varje x genom:
r = x/128 # or r = x>>7
Du kan använda rand_number eller vad du vill i stället för r om du föredrar det.

Och för att hålla koll på fördelningen mellan slumptalen så lägger jag till r, inte x, i numbers_n.
numbers_n[r] += 1
inte
numbers_n[x] += 1

(Sedan tycker jag personligen att din stil att programmera på, där du verkar gilla att splittra ut så mycket som möjligt i många små funktioner, gör koden stor och svårläst.
Men det spelar ju egentligen ingen roll för denna uppgift, och om du trivs med det och det fungerar bra för dig så fortsätt så för all del.)

Permalänk
Medlem
Skrivet av Genesis:

Mycket du skrev bara för ett så litet fel, men antar det funkar nu.

def slump(x,numbers_n): x = ((25173*x+13849)%65536) rand_nr = x >>7 numbers_n[rand_nr] += 1 #current number occured += 1 time return x, numbers_n #nästa gång kommer detta x användas

Hur tycker du jag ska göra för att göra koden lättare att läsa?

Permalänk
Medlem

Tja, mycket text verkar ju vara vad som tillslut fick dig att förstå. Jag beskrev ditt fel i två meningar i mitt första inlägg, men det verkar du skummat lite för snabbt över och sedan aldrig försökt läsa igen...

Men det där ser tillslut rätt ut.

Vad det gäller lättlästheten i koden så antar jag att det är personligt till viss del. Men exempelvis att kalla på en funktion som enbart kallar på en annan funktion gör enbart koden längre och jobbigare att snabbt sätta sig in i.
Sedan att returnera värden fram och tillbaka, och kalla variablerna olika i de olika funktionerna hjälper inte.

Hade jag fått uppgiften så hade jag presenterat något i stil med:

import datetime # Set initial value of x to something somewhat random. x = int(datetime.datetime.now().strftime("%f")) def getRandomNumber(): global x x = (25173*x + 13849) % 65536 return x >> 7 # Testing distribution loops = 1000000 occurrences = [0]*512 # Bit 15...8 gives 9 bits. 2^9=512. Random numbers varies between 0 and 511. for i in range(loops): occurrences[getRandomNumber()] += 1 print occurrences

Så lite kod som möjligt utan att göra den svårläst. Inte så mycket "krimskrams" runt om som det inte frågas efter i uppgiften.
Inga onödigt lagrade variabler som ej behöver mellanlagras eller skickas mellan funktioner. Och vettiga namn på variabler och funktioner så att man lätt förstår vad de är till för utan att läsa koden eller kommentarerna för den.

Och jag hade nog använt en global variabel för x, så att man får en snygg funktion för att generera slumptal, där man inte behöver hålla koll på x för att få ett slumptal.

Permalänk
Medlem

Andra tips för att öka läsbarheten är
Undvik globala variabler, alltid. De är svåra att följa och man får in de även där man inte förväntar sig det.
Använd bra och beskrivande namn, x kan vara vad som helst.
Undvik "magiska nummer". 2**16 gör mycket enklare att förstå att det rör sig om 16 bitar än 65536.

Begrunda denna http://abstrusegoose.com/432

import datetime class Random: def __init__(self): # Set initial value of seed to current microseconds. self.seed = int(datetime.datetime.now().strftime("%f")) def next(self): self.seed = (25173*self.seed + 13849) % 2**16 # Calculate a pseude random number and limit it to 16 bits return self.seed >> 7 # Testing distribution loops = 1000000 occurrences = [0]*512 # Bit 15...7 gives 9 bits. 2^9=512. Random numbers varies between 0 and 511. random = Random() for i in range(loops): occurrences[random.next()] += 1 print occurrences

Sen blir 15...8 bara 8 bitar, inte 9.

Permalänk
Medlem
Skrivet av Pie-or-paj:

Undvik "magiska nummer". 2**16 gör mycket enklare att förstå att det rör sig om 16 bitar än 65536.

Så man förlorar ingen prestanda om man ska loopa 2**16 en massa gånger istället för 65536?

Permalänk
Medlem

Ja, Pie-or-paj's kod kanske är snyggare än min. I viss mån personligt där i alla fall jag inte tycker globala variabler är så farligt i korta program, och föredrar det framför en egen class när det rör sig om korta program. Men när man ska försöka lära andra hur de ska koda snyggt så kanske det är lika bra att lära de ett enhetligt sätt som fungerar bra även i längre/komplexare program.

Och något är fel med 15...8, och %65536 och >>7. 15...8 ger 8 bitar, men %65536 och >>7 ger 9 bitar. Så uppgiften är felaktigt formulerad.
9 bitar är ovanligt. Jag gissar att de snarare vill ha 8 bitar, med 15...8 med %65536 och >>8. Men bara en gissning...

spel565:
Nej, pythons interpreterare är intelligent nog att enbart beräkna 2^16/2**16 en gång. Så den behöver enbart räkna ut det en gång så sedan återanvänder den resultatet av det till varje loop.
Och även om den hade behövt beräkna det på nytt varje gång så hade det rört sig om en väldigt liten skillnad i prestanda.
Och det efterfrågas ändå inte att testa slumptalsgeneratorn så optimerat som möjligt, så för denna uppgift så behöver du inte bry dig om prestandan direkt.

Permalänk
Medlem

@Genesis jag menade inte att klaga på dig, jag håller också med om att globala variabler är
tillåtet i ett litet program som endast gör en sak. Men det var en gyllene regel som jag ville
lära ut. Ibland får man bryta mot den, men då bör man veta vad man gör.
Så för utlärningssyfte tycker jag det är bäst att följa den

Skrivet av spel565:

Så man förlorar ingen prestanda om man ska loopa 2**16 en massa gånger istället för 65536?

En annan gyllene regel är att mät två gånger, optimera en.
Om du har prestandaproblem, då kan du börja mäta var flaskhalsen är. Efter det kan du
optimera och mäta igen.
Om du optimerar utan att mäta så kommer du lägga mer tid och ofta få mer svårläst kod
utan att vinna något på det. I vissa fall kan du även få långsammare kod då skaparna av
programspråken prioriterar att optimera vanliga saker.
I ditt fall så skulle du tjäna mest på att köra i en optimerande JIT (t.ex. Pypy) och då skulle
den uträkningen vara det första som optimerades ut då det är en sån extremt enkel optimering.

Nu var det ju tydligen så att även CPython optimerade bort det

Permalänk
Medlem
Skrivet av Genesis:
Skrivet av Pie-or-paj:

Tack för er hjälp!

from datetime import datetime rand_nr = None x = int(datetime.now().strftime("%f")) #x0= datorns tid i ms, “vårt frö” while 1: #oändlig loop input("Hit me! ") #Tryck enter för att få nästa tal x = ((25173*x+13849)%(2**16)) # x+1 = 25173x+13849 mod 2¹⁶ rand_nr = x >> 8 #detta är vårt nummer, reducerat från 2¹⁶ till 2⁽¹⁶⁻⁸⁾, 8 bitar print ("Your number is:", rand_nr) #Skriver ut ditt nummer

Jag har redan fått svar på min fråga, men jag tar tillfället i akt och ställer ytterligare en.
Jag förstår inte nästa fråga: om hur bra slumpgeneratorn är och hur lång perioden är (dvs hur ofta sekvensen upprepas).
Efter 1 miljard loopar skiljde det ~0.007 promille mellan lägsta och högsta tal, vilket måste vara väldigt bra? och någon period hittar jag inte. Har jag missuppfattat?