2015-10-16 14 views
11

z funkcją Math.random(), która zwraca liczbę między [0,1) a minmax wartości, aby określić zakres, w jaki sposób możemy generować liczby dla następujących przypadkach:Generowanie liczb losowych w określonym zakresie - różne przypadki (int, float, inclusive, exclusive)

Case chcemy całkowitą:

  • A: (min,max) ?
  • B: [min,max) return Math.floor(Math.random() * (max - min)) + min;
  • C: (min,max] ?
  • D: [min,max] return Math.floor(Math.random() * (max - min + 1)) + min;

Case chcemy pływak:

  • A: (min,max) ?
  • B: [min,max) return Math.random() * (max - min) + min;
  • C: (min,max] ?
  • D: [min,max] ?
+0

mój odniesienia jest od [MDN] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) – tgogos

+0

stoję poprawione –

+0

Twój 'unosić B' Sprawa nie działa: w wielu przypadkach formuła ta będzie w stanie wygenerować zarówno górną, jak i dolną granicę. –

Odpowiedz

0

całkowita:

  • A: return Math.floor(Math.random() * (max - min - 1)) + min + 1;
  • B. Dokładny
  • C: Jest takie samo jak [min + 1 max + 1), więc: return Math.floor(Math.random() * (max - min)) + min + 1;
  • D: Prawidłowe

Dla pływaków, musisz wiedzieć, jaką masz arytmetykę zmiennoprzecinkową. Jeśli nie używasz specjalnej biblioteki, równość w float to coś, co zwykle się nie dzieje, więc nie ma sensu mieć zamkniętych zakresów. Jako takie nie powinno być żadnej różnicy pomiędzy wszystkimi czterema i można po prostu iść z:

return Math.random() * (max-min) + min;

Na pytanie sensu, trzeba określić minimalny dopuszczalny zakres dla równości (np r=0.00000000000000001). Następnie możesz przekształcić równania w zakresie otwartego zakresu (tj. (min, max)) na [min+r, max-r].

2

Integers Twoja formuła B jest poprawna, wszystko inne jest otrzymywany przez trywialne +1-1 korekt:

  • A. (min, max) = [min + 1, max), dlatego z B. otrzymujemy min + 1 + Math.floor(Math.random() * (max - min - 1))
  • B. min + Math.floor(Math.random() * (max - min))
  • C. Ponieważ w przedziale arytmetycznym (min, max] = max - [0, max - min), można również napisać max - Math.floor(Math.random() * (max - min))
  • D.[min, max] = [min, max + 1), dlatego: min + Math.floor(Math.random() * (max + 1 - min))

Pływa. Jak już zauważyliśmy w V13, pytanie jest w pewnym sensie niepoprawne: jeśli uważamy pojedyncze punkty za zestawy zerowe, prawie (w sensie miarowo-teoretycznym) nie ma różnicy między czterema zestawami ... Jednakże, jeśli chcesz w celu zagwarantowania, że ​​wykluczone granice interwału nie są (nie tylko „prawie nigdy”) próbki, a jeśli przyjąć, że nie ma żadnych błędów zaokrągleń, można zrobić coś takiego:

  • a: var middle = (min + max)/2; var sign = Math.random() > 0.5 ? 1 : -1; return middle + sign * (max - min)/2 * Math.random(); to rozwiązanie puts odrobinę więcej masy na 0, ale to powinno być pomijalne dla wszystkich praktycznych zastosowań.

  • B: min + Math.random() * (max - min), tak.

  • C: max - Math.random() * (max - min), symetryczna do powyższego.
  • D: Nie można zagwarantować, że kiedykolwiek trafimy w górną granicę przedziału, więc możemy po prostu użyć min + Math.random() * (max - min).

Różnica między A i D jest następująca: jeśli staraliśmy się stosować formułę min + Math.random() * (max - min) w A, możemy od czasu do czasu dostać 0 (ponieważ zakres możliwych liczb jest właściwie skończony). Jednak żadna rozsądna statystyka nie może kiedykolwiek narzekać, że górna granica nie jest trafiona w D.

0

Zacznę od zdefiniowania następnych dwóch funkcji pomocnika, a następnie skorzystam z nich, aby uzyskać wartości. Te metody są twoimi definicjami przypadków B.

int nextInt(int min, int max) { 
    return Math.floor(Math.random() * (max - min)) + min; 
} 

float nextFloat(float min, float max) { 
    return Math.random() * (max - min) + min; 
} 

Następnie przez całkowite

  • A: powrotu nextInt (min + 1, max);
  • B: return nextInt (min, max);
  • C: return nextInt (min + 1, maks. + 1);
  • D: return nextInt (min, max + 1);

Pływaki są nieco bardziej złożone. Niektórzy mogą twierdzić, że nie ma dużej różnicy, czy punkty końcowe są uwzględnione, czy nie - szczególnie rozwiązanie otwarte może być używane zamiast zamkniętego - ponieważ punkty końcowe są rzadko wybierane. Ale ponieważ jest to całkowicie możliwe, aby zrealizować wszystkie scenariusze, myślę, że istnieje matematyczne zainteresowanie, w jaki sposób można to zrobić.

A: W tym przypadku możemy prosty upewnić się, że nielegalne wartość zostanie wyrzucona ponownie:

float f; 
do { 
    f = nextFloat(min, max); 
} while (f == min); 
return f; 

B:

return nextFloat(min, max); 

C: Tu wystarczy przełączyć punkt końcowy

float f = nextFloat(min, max); 
if (f == min) { 
    return max; 
} 
return f; 

D: Jest to najbardziej skomplikowany scenariusz wszystkim, ale można osiągnąć w następujący sposób:

float f = nextFloat(min, max); 
if (f == min) { 
    return max; 
} 
return nextFloat(min, max); 

przypadków A i D są trochę brudne w tym sensie, że mogą one wymagać generowania więcej niż jeden losowa liczba, która może być problemem w niektórych konkretnych sytuacjach. Rozwiązanie tego problemu wymagałoby wniknięcia w specyfikację zmiennoprzecinkowej w celu znalezienia alternatywnych implementacji. Ponadto należy zauważyć, że w przypadku D, propozycja wartości maksymalnej ma bardzo nieznacznie większą zdolność niż jakakolwiek inna liczba, jeśli funkcja odniesienia jest całkowicie jednorodna (zwykle nie), ale zazwyczaj jest to tylko kwestia teoretyczna. (Aby być precyzyjnym, jeśli istnieje n możliwych wartości w zakresie, propability maksymalnej wartości pmax = 1/(n-1) i propability dowolnej innej wartości jest (1-pmax)/(n-1)).

Należy zwrócić uwagę na mały problem, który należy rozwiązać przy precyzyjnych implementacjach przypadku zmiennoprzecinkowego A. Istnieje możliwość, że wywołujący funkcję wywoła go z sąsiednimi punktami zmiennoprzecinkowymi. Nie jest to łatwe do sprawdzenia przez jakąkolwiek próbną kontrolę parametrów, więc aby być pewnym, powinien istnieć limit określający ile razy pętla może zostać wykonana.

Powiązane problemy