Zdaję sobie sprawę, że książka Swift zapewnia implementację generatora liczb losowych. Czy najlepszą praktyką jest kopiowanie i wklejanie tej implementacji we własnym programie? A może jest biblioteka, z której możemy teraz korzystać?
443
Użyj
arc4random_uniform(n)
dla losowej liczby całkowitej od 0 do n-1.Rzuć wynik na Int, abyś nie musiał jawnie wpisywać swoich warów jako
UInt32
(co wydaje się nie-Swifty).źródło
0
. W twoim kodziediceRoll
może być0
. Tylko mówię ...Int(arc4random_uniform(6)+1)
.arc3random_uniform(n)
a,UInt32(n)
jeśli używasz wartości, która nie jest jeszcze tego typu.Edycja: Zaktualizowano dla Swift 3.0
arc4random
działa dobrze w Swift, ale podstawowe funkcje są ograniczone do 32-bitowych liczb całkowitych (Int
64-bit na iPhone 5S i współczesnych komputerach Mac). Oto ogólna funkcja dla losowej liczby typu wyrażanego literałami całkowitymi:Możemy użyć tej nowej funkcji ogólnej do rozszerzenia
UInt64
, dodania argumentów granicznych i złagodzenia błędu modulo. (To jest podnoszone prosto z arc4random.c )Dzięki temu możemy przedłużyć
Int64
o te same argumenty, zajmując się przepełnieniem:Aby uzupełnić rodzinę ...
Po tym wszystkim możemy wreszcie zrobić coś takiego:
źródło
var r = arc4random(UInt64)
. Proszę o poradę, co miałeś na myśli?arc4random
(zdefiniowanej w pierwszym bloku kodu) z argumentem,UInt64
który jestType
.arc4random_buf
. Celem tych rozszerzeń jest robienie dokładnie tego, coarc4random_uniform
robi (łagodzenie błędu modulo), z wyjątkiem typów 64-bitowych.Edycja dla Swift 4.2
Począwszy od Swift 4.2, zamiast korzystać z importowanej funkcji C arc4random_uniform (), możesz teraz używać własnych funkcji natywnych Swift.
Możesz użyć
random(in:)
aby uzyskać losowe wartości również dla innych pierwotnych wartości; takie jak Int, Double, Float, a nawet Bool.Szybkie wersje <4.2
Ta metoda wygeneruje losową
Int
wartość między podanym minimum a maksimumźródło
Użyłem tego kodu:
źródło
random is unavailable in Swift: Use arc4random instead.
Począwszy od iOS 9, możesz używać nowych klas GameplayKit do generowania liczb losowych na różne sposoby.
Masz do wyboru cztery typy źródeł: ogólne losowe źródło (bez nazwy, aż do systemu, który wybiera, co robi), liniowy congruential, ARC4 i Mersenne Twister. Mogą generować losowe liczby całkowite, zmiennoprzecinkowe i boole.
Na najprostszym poziomie możesz wygenerować losową liczbę z wbudowanego losowego źródła systemu, jak to:
To generuje liczbę między -2 147 483 648 a 2 147 483 647. Jeśli chcesz liczbę z zakresu od 0 do górnej granicy (wyłącznie), użyj tego:
GameplayKit ma wbudowane kilka wygodnych konstruktorów do pracy z kostkami. Na przykład możesz rzucić sześciościenną kostką w następujący sposób:
Ponadto możesz kształtować losowy rozkład, używając rzeczy takich jak GKShuffledDistribution. To wymaga trochę więcej wyjaśnienia, ale jeśli jesteś zainteresowany, możesz przeczytać mój poradnik na temat losowych liczb GameplayKit .
źródło
import GameplayKit
. Swift 3 zmienił składnię naGKRandomSource.sharedRandom().nextInt(upperBound: 6)
Możesz to zrobić w taki sam sposób, jak w C:
randomNumber
jest wywnioskowane, że jest typuUInt32
(32-bitowa liczba całkowita bez znaku)źródło
rand
,arc4random
,drand48
i przyjaciele są wDarwin
module. Jest już zaimportowany, jeśli budujesz aplikację Cocoa, UIKit lub Foundation, ale musisz to zrobićimport Darwin
na placach zabaw.Posługiwać się
arc4random_uniform()
Stosowanie:
arc4random_uniform(someNumber: UInt32) -> UInt32
Daje to losowe liczby całkowite z zakresu
0
dosomeNumber - 1
.Maksymalna wartość
UInt32
wynosi 4 294 967 295 (to znaczy,2^32 - 1
).Przykłady:
Rzut monetą
Rzut kostką
Losowy dzień w październiku
Losowy rok w latach 90
Ogólna forma:
gdzie
number
,max
imin
sąUInt32
.Co powiesz na...
arc4random ()
Możesz także uzyskać losową liczbę, używając
arc4random()
, co dajeUInt32
od 0 do 2 ^ 32-1. Tak więc, aby uzyskać losową liczbę między0
ix-1
, możesz ją podzielić przezx
i wziąć resztę. Innymi słowy, użyj Remainder Operator (%) :Powoduje to jednak nieznaczne odchylenie modulo (patrz także tutaj i tutaj ), dlatego
arc4random_uniform()
jest zalecane.Konwersja do i z
Int
Zwykle dobrze byłoby zrobić coś takiego, aby przekonwertować między
Int
iUInt32
:Problem polega jednak na tym, że
Int
ma on zasięg w-2,147,483,648...2,147,483,647
systemach 32-bitowych i zakres w-9,223,372,036,854,775,808...9,223,372,036,854,775,807
systemach 64-bitowych. Porównaj to zUInt32
zakresem0...4,294,967,295
.U
ZUInt32
pomocą unsigned .Rozważ następujące błędy:
Musisz tylko upewnić się, że parametry wejściowe mieszczą się w
UInt32
zakresie i że nie potrzebujesz również wyjścia, które jest poza tym zakresem.źródło
Przykład losowej liczby między 10 (0-9);
Bardzo łatwy kod - prosty i krótki.
źródło
Byłem w stanie po prostu użyć
rand()
losowego CInt. Możesz zrobić z tego Int, używając czegoś takiego:Możesz użyć swojej ulubionej funkcji losowej C. W razie potrzeby wystarczy przekonwertować wartość na Int.
źródło
random()
, który zwracaInt
raczej niżUInt32
- i jak wspomniano @SomeGuy, po prostu zadzwońsrandom(arc4random())
raz w dowolnym miejscu przed użyciem, aby upewnić się, że ma on inne, losowe źródło dla każdego wykonania twojego programu.Odpowiedź @ jstn jest dobra, ale nieco gadatliwa. Swift jest znany jako język zorientowany na protokół, dzięki czemu możemy osiągnąć ten sam wynik bez konieczności implementowania kodu typu Booster dla każdej klasy w rodzinie liczb całkowitych, dodając domyślną implementację rozszerzenia protokołu.
Teraz możemy zrobić:
i wszystkie inne klasy całkowite są w porządku.
źródło
W Swift 4.2 możesz generować losowe liczby, wywołując
random()
metodę na dowolnym typie liczbowym, podając zakres, z którym chcesz pracować. Na przykład generuje losową liczbę z zakresu od 1 do 9, włącznie po obu stronachRównież z innymi typami
źródło
Oto biblioteka, która dobrze wykonuje to zadanie https://github.com/thellimist/SwiftRandom
źródło
źródło
Chciałbym dodać do istniejących odpowiedzi, że przykład generatora liczb losowych w książce Swift to Generator liniowej zbieżności (LCG), jest on mocno ograniczony i nie powinien być wyjątkiem trywialnych przykładów, w których jakość losowości nie to nie ma znaczenia. I LCG nigdy nie powinien być używany do celów kryptograficznych .
arc4random()
jest znacznie lepszy i może być używany do większości celów, ale ponownie nie powinien być wykorzystywany do celów kryptograficznych.Jeśli chcesz mieć coś, co gwarantuje bezpieczeństwo kryptograficzne, użyj
SecCopyRandomBytes()
. Zauważ, że jeśli w coś wbudujesz generator liczb losowych, ktoś inny może (nie) użyć go do celów kryptograficznych (takich jak generowanie hasła, klucza lub soli), powinieneś rozważyć użycie goSecCopyRandomBytes()
, nawet jeśli twoja potrzeba tego nie robi. całkiem tego wymaga.źródło
Od wersji Swift 4.2
Istnieje nowy zestaw interfejsów API:
Wszystkie typy numeryczne mają teraz wybraną
random(in:)
metodęrange
.Zwraca liczbę równomiernie rozmieszczoną w tym zakresie.
TL; DR
Cóż jest nie tak z „dobrym” starym sposobem?
Musisz użyć importowanych interfejsów API C (różnią się one między platformami) .
A ponadto ...
Jeśli używasz
arc4random()
(aby obliczyć resztę) jakarc4random() % aNumber
, wynik nie jest równomiernie rozłożone pomiędzy0
iaNumber
. Istnieje problem zwany stronniczością Modulo .Odchylenie modulo
Zwykle funkcja generuje losową liczbę między
0
i MAX (zależy od typu itp . ) . Aby zrobić szybki, łatwy przykład, załóżmy, że maksymalna liczba to7
i zależy Ci na losowej liczbie w zakresie0 ..< 2
(lub odstępie [0, 3), jeśli wolisz) .Te prawdopodobieństwa dla poszczególnych numerów są:
Innymi słowy, bardziej prawdopodobne jest, że skończysz z 0 lub 1 niż 2 . Oczywiście należy pamiętać, że jest to bardzo uproszczone, a liczba MAX jest znacznie wyższa, dzięki czemu jest bardziej „sprawiedliwa”.
źródło
Bez arc4Random_uniform () w niektórych wersjach Xcode (w 7.1 działa, ale nie wykonuje autouzupełniania). Możesz to zrobić zamiast tego.
Aby wygenerować losową liczbę od 0-5. Pierwszy
Następnie
źródło
Tutaj 5 upewni się, że liczba losowa zostanie wygenerowana od zera do czterech. Możesz odpowiednio ustawić wartość.
źródło
Szybki 4.2
Pa pa, aby zaimportować libellę Foundation C.
arc4random_uniform()
Więcej @ Oficjalny
źródło
Poniższy kod wygeneruje bezpieczną liczbę losową z przedziału od 0 do 255:
Nazywasz to tak:
W przypadku większych liczb staje się to bardziej skomplikowane.
To najlepsze, co mogłem wymyślić:
W tych metodach używa się dodatkowej liczby losowej, aby określić, ile
UInt8
s będzie używanych do utworzenia liczby losowej. Ostatnia linia zamienia[UInt8]
sięUInt16
lubUInt32
.Nie wiem, czy dwa ostatnie nadal liczą się jako naprawdę losowe, ale możesz je dostosować do własnych upodobań :)
źródło
Szybki 4.2
Swift 4.2 zawiera natywny i dość w pełni funkcjonalny interfejs API liczb losowych w standardowej bibliotece. ( Propozycja Swift Evolution SE-0202 )
Wszystkie typy liczb mają statyczne losowe (w :), które przyjmuje zakres i zwraca liczbę losową z podanego zakresu
źródło
W systemach iOS, macOS i tvOS można używać losowego źródła systemowego w środowisku Xcode
GameKit
. Tutaj możesz znaleźćGKRandomSource
klasę za pomocą jejsharedRandom()
metody klasowej:Lub po prostu użyj
randomElement()
metody, która zwraca losowy element kolekcji:źródło
Możesz użyć w
GeneratorOf
ten sposób:źródło
Używam tego kodu, aby wygenerować losową liczbę:
źródło
Detale
xCode 9.1, Swift 4
Rozwiązanie zorientowane matematycznie (1)
Zastosowanie rozwiązania (1)
Rozwiązanie zorientowane na programistów (2)
Zastosowanie rozwiązania (2)
Pełna próbka
Przykładowy wynik
źródło