Autor Zpráva
quest
Profil
Chtěl bych se zeptat jak v JS vypadá něco jako random.randrange v Py.
Děkuji.
juriad
Profil
Viz examples v dokumantaci:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random

V podstatě vezmeš náhodné číslo v intervalu 0 - 1 a to přetransformuješ. Pozor na to, že hodně implementací může vracet některou hodnotu častěji (kvůli zaokrouhlování)
quest
Profil
Nemohl by jsi mi tu napsat konkrétní příklad? Vyměnil jsem to za čísla ale nic mi to nevypíše...
margin
Profil *
quest:
a to přetransformuješ“, to znamená použít přímou úměru, pokud si pamatuji, tak je to učivo 8. třídy základní školy.
quest
Profil
<script type="text/javascript">
var x = Math.ceil(Math.random()*6);

document.write(x)
</script>
Tenhle kód mi napíše náhodné číslo mezi 1 a 6 ale já bych chtěl aby mi to vypaslo náhodné číslo např.: mezi 4 a 6..
juriad:
Podle examples v dokumentaci jsem to zkusil ale nějak mi to nevyšlo takže pořád přesně nevím jak to udělat.
Děkuji za každou odpověď.
margin
Profil *
Zkus si ještě vzpomenout na sčítání a odčítání.
juriad
Profil
<script>
function randrange(min, max) {
  // budeme potřebovat náhodné číslo o jedna větší než je rozdíl, protože zaokrouhlujeme vždy dolů
  // nule odpovídá interval <0, 1), jedničce interval <1, 2), ...
  var rozsah = max - min + 1; 
  var nahodne = Math.floor(Math.random()*rozsah) + min; // k náhodnému číslu po vynásobení rozsahem a zaokrouhlení dolů přičteme min  
  if(nahodne > max) { // někdy se může stát, že Math.random vrátí přesně 1, a tedy Math.floor bude 1 a tedy nám vyjde číslo o jedna větší než max
    nahodne--; // tak ho prostě snížíme o jedničku na hodnotu maxima :)
  }
  return nahodne;
}

for(var i = 0; i < 10; i++) { // desetkrát pokusů na otestování
    var min = parseInt(window.prompt("min:"));
    var max = parseInt(window.prompt("max:"));
    alert(randrange(min, max));
}
</script>
1Pupik1989
Profil
Já používám:

function random(min,max){
  return ~~(Math.random() * (max - min + 1)) + min;
}

Zatím se mi nestalo, že by hodnota přesáhla horní hranici. Tedy že by Math.random vrátilo 1. Zkoušel jsem 1000000000 pokusů a 1 nevyšlo ani jednou. Nicméně stát se to asi logicky může.
juriad
Profil
1Pupik1989:
Ono ve většině situací to ani nevadí, třeba když generuješ efekt sněhové vločky na pozadí stránky :)
Ale jakmile indexuješ tím náhodným číslem prvky pole a při předváděčce aplikace spadne, tak si zkus vysvětlit, že to stane v jednom z 2^62 případů.

Psychiatr Chocholoušek se omlouvá panu Hudečkovi, že ho omylem dopravili do jeho ordinace.
"Náš ústav se vám, pane Hudečku, mými ústy co nejsrdečněji omlouvá za toto politováníhodné nedopatření, ke kterému dochází maximálně jednou za deset let!"


Může také být zajímavé přečíst si třeba zdrojáky třídy Random v javě: http://developer.classpath.org/doc/java/util/Random-source.html . A vůbec, k teorii a praxi generování náhodných čísel a třeba i permutací se dá nalézt toho spoustu pěkného a překvapivého.
Chamurappi
Profil
Reaguji na juriada:
Poslední týden jsem náhodnost v JS zkoumal docela podrobně a odkazovaná zmínka o pravděpodobnosti vyklouznutí z očekávaného intervalu mě docela překvapila. Také jsem našel informace, že starší verze Chromu uměla generovat jen 2^32 různých čísel. A že seedem bývá timestamp, takže když nějakou službu používá opravdu hodně lidí najednou a se stejným prohlížečem, některým z nich vrací Math.random stejná čísla, což pak dokáže překvapit :-)

někdy se může stát, že Math.random vrátí přesně 1
Myslím, že takhle vyřčené to není pravda. Že to vyklouznutí (pokud je skutečně možné*) je dáno omezenou přesností doublů a nastane až po nějaké matematické operaci (což vynásobení rozsahem je) s náhodným číslem velmi blízkým jedničce. Odhaduji, že pravděpodobnost tohoto jevu nejspíš i bude závislá na tom, co se provádí a případně jaký je ten druhý operand. Třeba násobení mocninou dvojky by asi mělo být vždy spolehlivé, protože se hne jen s exponentem.
Kdyby byla malá šance, že sám Math.random vrátí přímo jedničku, nemělo by smysl říkat, že vrací číslo v intervalu <0, 1), protože šance, že vrátí nulu, by byla obdobně malá.

tak si zkus vysvětlit, že to se stane v jednom z 2^62 případů
Ona je to opravdu extrémně malá šance. Chuť zanedbat ji je skoro neodolatelná :-)
Číslo 2^62 mi připadá trochu podezřelé. Je sice pravda, že cca čtvrtina všech doublů je mezi nulou a jedničkou, ale drtivá většina z nich se tiskne k nule. Na příklad: 1e-100 a 2e-100 jsou dvě různá čísla, ale 0.9 + 1e-100 a 0.9 + 2e-100 už ne. Náhodný generátor musí vybírat rovnoměrně, takže musí tuto disproporci doublů vyvažovat.

*) Hraju si v konzoli s číslem 0.99999999999999994 a začínám pochybovat, zda to není jen velmi důmyslně vymyšlená pověra. Na MDN je od 2. srpna 2007 jako reakce na komentář z talk page, kterou nikde nevidím. Zřídil jsem si tam teď v rychlosti i účet… a talk page pořád nikde.
quest
Profil
Všem moc děkuji.
juriad:
Nakonec jsem použil tvůj kód.
Chamurappi
Profil
Reaguji na juriada:
Myslím, že už mi docvaklo, jak to s tím dosažením horní meze je. Jak jsem již psal, sám Math.random funguje spolehlivě, vrací číslo v rozsahu <0, 1). Toto číslo je double, takže rozsah je přesně:
<0, 0.99999999999999988897769753748434595763683319091796875>
… to dlouhé číslo je nejbližší možné k jedničce, odpovídá binárnímu zápisu 0.111… — kde je 53 jedniček, lze se k němu dopracovat i výpočtem (2^53 - 1) / 2^53. Desítkově jde zapsat do kódu i stručněji jako 0.99999999999999994, jak jsem zmiňoval výše.

Myslím, že některé doubly z tohoto rozsahu se nevygenerují nikdy, protože generátor, ze kterého by lezly přímo bity doublů s rovnoměrným rozložením po celém rozsahu, by asi byl dost komplikovaný. I ten odkázaný zdroják Randomu z Javy (kterým se údajně inspiroval i javascriptový generátor v Mozille) získává nextDouble tím, že vygeneruje long v rozmezí <0, 2^53) a vydělí ho 2^53. Takže pravděpodobnost, že vyjde nějaké konkrétní číslo z rozsahu, je pouze 1 ku 2^53, přestože všech doublů mezi nulou a jedničkou je cca 2^62.

Pokud tedy v jednom případě z 2^53 vyjde číslo 0.99999999999999994, co se s ním musí stát, aby zdánlivě sklouzlo na 1? Vynásobení nestačí — vždy se tam ten jeden rozdílný bit udrží. Nikdy neplatí, že x * 0.99999999999999994 == x, pokud je x konečné a nenulové. Proto se na Math.floor(Math.random() * rozsah) uvedený ve tvém kódu dá stoprocentně spolehnout.

Riskantní operací je sčítání, teprve tam se ten poslední klíčový bit doublovy mantisy může ztratit. Nejjednodušší případ: 0.99999999999999994 + 1 vyjde přesně 2. Nemusí se ztratit jen jeden poslední bit, při přičtení většího čísla budou ztráty (a tedy i pravděpodobnost dosažení horní meze) větší. Extrémní případ: když se k výsledku Math.randomu přičte 2^52, je šance, že vyjde přesně 2^52 + 1, už 1 ku 2.

Poučení tedy je, že pokud chci generovat celé číslo, neměl bych přičtení dolní meze nikdy dávat dovnitř Math.flooru — a pak můžu být v klidu. Pokud chci generovat desetinné číslo a změnit mu dolní mez, riziku se nevyhnu a šance na dosažení horní meze závisí na tom, jaké jsou meze.
juriad
Profil
Chamurappi:
Díky za skvěle provedenou analýzu, sám jsem se na to chystal, ale nemám momentálně čas. Fakt to vypadá na to, že někdo nevhodně přičítal a ještě měl hroznou smůlu.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0