# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# + [markdown] id="fsm9o_BEMvb0" colab_type="text"
# # 4. gyakorlat: importok - és a "véletlen" számok
#
# A múlt órai házi feladat 2. részét megnézve találkozhattatok valami ehhez hasonlóval:

# + id="eBSZJGdIMvb1" colab_type="code" colab={}
import konyvtar

"""
...
"""

ertek = konyvtar.fuggveny(argumentumok)

"""
...
"""

# + [markdown] id="LqKBlLz7Mvb3" colab_type="text"
# Tapasztalhattátok, hogy ilyen módon olyan függvényeket is használhattunk (pl. időmérő vagy grafikonrajzoló függvénykét), amit nem mi írtunk, és nem is akarunk megírni. A Python-ban ezeket a "plusz" függvényeket tartalmazó objektumokat nevezzük "könyvtáraknak" (libraries). Vannak a Python-nak olyan könyvtárai, amik a nyelvvel együtt települnek (ilyen az időzítésre szolgáló **time**, vagy a fájl/mappaműveletkez hasznos **os**), de vannak olyanok is, amiket külön telepíteni kell (a második feladatban használt **matplotlib** általában ilyen.
#
# ## Hogyan keríthetünk könyvtárakat?
#
# Akinek valamiért nem volt fenn a matplotlib, annak már muszáj volt utánanéznie, de azért nem olyan vészes így utólag sem: command line-ból (vagy Anaconda Promtból) telepíthettek új könyvtárakat, az internetről letöltve. [Itt](https://packaging.python.org/tutorials/installing-packages/) egy összefoglaló a csomagok telepítéséről Pythonban.
#
# ## Saját fájljaink újrahasználata
#
# Nem csak a beépített vagy letöltött könyvtárakkal dolgozhatunk: ha a fájlotok mappjában található egy másik .py fájl, annak függvényeit is tudjátok használni, ha importoljátok **import fájlnév** -el, kiterjesztés nélkül.
#
# ## Véletlenszámok - a feladat
#
# Az órán azzal foglalkoztunk, hogy hogyan tudunk szoftveresen "kb. véletlen számokat" készíteni. Ennek [itt](https://en.wikipedia.org/wiki/Pseudorandom_number_generator) olvashattok utána. Három algoritmusról beszélgettünk:
#
# ### Véletlen számok a rendszeróra felhasználásával
#
# A Python **time** függvényébe beépített óra kb. 200 nanoses-enként vált értéket. Első közelítésben a rendszeróra utolsó számjegyeit vehetjük kb. véletlennek, mert olyan gyorsan pörög, hogy nem tudjuk, éppen hol tarthat, amikor lefuttatjuk a programunkat.
#

# + id="hnmFO5ctMvb3" colab_type="code" colab={}
import time #a time könyvtárat használni fogom

def randomTimeInt(upperBound):
    timeSeed = time.time() #megmérem az időt
    randInt = (int(timeSeed*10000000))%upperBound #time.time floatot ad vissza, felszorzom, hogy egész legyen, majd maradékot veszem
    return randInt
    
    

# + [markdown] id="5L-MLmtkP7gt" colab_type="text"
# Igazából a rendszeróra használatával csaltunk egy kicsit: az igazi pszeudorandom generátorok nem függenek semmilyen fizikai jelenségtől, csak annyit csinálnak, egy számból - amit "seed"-nek nevezünk - csinálnak egy másikat, úgy, hogy ne nagyon lehessen felfedezni a két szám közötti összefüggést. Jöjjön pár "igazi" váletlenszám generátor; persze ilyen röviden csak a gagyibbakat tudjuk megnézegetni.
#
# ### Middle square módszer
#
# Ez az algoritmus az egyik legnagyobb magyar matematikushoz, Neumann Jánoshoz köthető; az ő korában, az 50-es/60-as években használták véletlen számok generálására. A [wikipédia](https://en.wikipedia.org/wiki/Middle-square_method) elég szépen részletezi a működését. A **len** függvényről még lehet, hogy nem volt szó: ez megmondja egy lista vagy str hosszát egész számként.

# + id="a-LPDLOzMvb7" colab_type="code" colab={}
def middleSquare(seed, intUpperBound):
  lenRandomNumber = len(str(seed))
  seed = seed**2
  seed = str(seed)
  while (len(seed) < lenRandomNumber*2):
    seed = '0'+seed
    
  newSeed = int(seed[lenRandomNumber//2:lenRandomNumber+lenRandomNumber//2])
  randomNumber = newSeed/(10**(lenRandomNumber))
  randomNumber *= intUpperBound
  return int(randomNumber), newSeed


# + [markdown] id="B-6IdIsCbYUG" colab_type="text"
# ## A maradékok módszere: LCG
#
# Az LCG-gk olyan algoritmusok, amik a seed-ből úgy állítanak elő új számokat, hogy megszorozzák $a$ tetszőleges számmal, hozzáadnak $b$ tetszőleges számot, majd veszik az összeg maradékát egy $c$ tetszőleges számmal osztva. Képlettel leírva így néz ki:
#
# $$ rand = (a*seed+b)mod (c) $$
#
# Az $a$, $b$ és $c$ együtthatók jó megválasztása fontos ahhoz, hogy jól működjön az LCG-nk; egy intő példa erre a [RANDU](https://en.wikipedia.org/wiki/RANDU) angolitmus, ami egy olyan LCG, ahol $a=65539$, $b=0$, $c=2^{31}$ és ha jól megnézzük, [kicsit sem tűnik véletlenszerűnek.](https://www.purinchu.net/wp/2009/02/06/the-randu-pseudo-random-number-generator/)

# + id="WRvaqczPMvb8" colab_type="code" colab={}
def RANDU(seed, intUpperBound):
  newSeed = (65539*seed)%(2**31)
  newSeedNormalized = newSeed/(10**(len(str(newSeed))))
  randInt = int((intUpperBound+1)*newSeedNormalized)
  return randInt-1, newSeed

StarcoderdataJupyterScriptsDedupFiltered