Próbuję wygenerować losową liczbę z przedziału od 0 do 1. Wciąż czytam arc4random()
, ale nie ma żadnych informacji o uzyskaniu z niej liczby zmiennoprzecinkowej. Jak mam to zrobic?
ios
c
random
floating-point
arc4random
jini
źródło
źródło
Odpowiedzi:
Losowa wartość w [0, 1 [ (w tym 0, wyłączając 1):
double val = ((double)arc4random() / UINT32_MAX);
Trochę więcej szczegółów tutaj .
Rzeczywisty zakres to [0, 0,99999999767169356] , ponieważ górna granica to (podwójna) 0xFFFFFFFF / 0x100000000.
źródło
ARC4RANDOM_MAX
musi być zdefiniowana ręcznie, ale0x100000000
jest 4294967296 , która jestULONG_MAX + 1
. Gdzie jest udokumentowane, że w każdym raziearc4random()
jest maksimumULONG_MAX
?// Seed (only once) srand48(time(0)); double x = drand48(); // Swift version // Seed (only once) srand48(Int(Date().timeIntervalSince1970)) let x = drand48()
źródło
drand48
trzeba zainicjować raz za pomocą seeda . Dokumentacja Apple sugeruje również, że należy go zainicjować.double
. Zobacz stackoverflow.com/a/34765674/1033581, aby dowiedzieć się, jak osiągnąć najlepszą precyzję.W przypadku Swift 4.2+ patrz: https://stackoverflow.com/a/50733095/1033581
Poniżej znajdują się zalecenia dotyczące prawidłowej jednorodności i optymalnej precyzji dla ObjC i Swift 4.1.
32-bitowa precyzja (optymalna dla
Float
)Jednolita wartość losowa w [0, 1] (w tym 0,0 i 1,0), dokładność do 32 bitów:
Obj-C :
float val = (float)arc4random() / UINT32_MAX;
Szybki :
Jest optymalny dla:
Float
(lubFloat32
) który ma znaczącą precyzję 24 bitów dla mantysy48-bitowa precyzja (odradzane)
Łatwo jest osiągnąć 48-bitową precyzję
drand48
( która używaarc4random_buf
pod maską ). Ale zauważ, że drand48 ma wady ze względu na wymagania dotyczące nasion, a także na to, że jest nieoptymalny do losowania wszystkich 52 bitów mantysy Double.Jednolita wartość losowa w [0, 1] , precyzja 48 bitów:
Szybki :
// seed (only needed once) srand48(Int(Date.timeIntervalSinceReferenceDate)) // random Double value let val = drand48()
64-bitowa precyzja (optymalna dla
Double
iFloat80
)Jednolita wartość losowa w [0, 1] (w tym 0,0 i 1,0), dokładność do 64 bitów:
Swift , używając dwóch wywołań arc4random:
let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random()) let val = Float80(arc4random64) / Float80(UInt64.max)
Szybki , używając jednego wywołania arc4random_buf:
var arc4random64: UInt64 = 0 arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64)) let val = Float80(arc4random64) / Float80(UInt64.max)
Jest optymalny dla:
Double
(lubFloat64
) który ma znaczącą precyzję 52 bitów dla mantysyFloat80
który ma znaczącą precyzję 64 bitów dla swojej mantysyUwagi
Porównania z innymi metodami
Odpowiedzi, w których zakres wyklucza jedną z granic (0 lub 1), prawdopodobnie wykazują błąd jednorodności i należy ich unikać.
arc4random()
, najlepsza precyzja to 1 / 0xFFFFFFFF (UINT32_MAX)arc4random_uniform()
, najlepsza precyzja to 1 / 0xFFFFFFFE (UINT32_MAX-1)rand()
( potajemnie używając arc4random ), najlepsza precyzja to 1 / 0x7FFFFFFF (RAND_MAX)random()
( potajemnie używając arc4random ), najlepsza precyzja to 1 / 0x7FFFFFFF (RAND_MAX)Jest to matematycznie niemożliwe, aby osiągnąć dokładność lepsza niż 32 bitów z pojedynczym wywołaniu
arc4random
,arc4random_uniform
,rand
lubrandom
. Więc nasze rozwiązania powyżej 32-bitowego i 64-bitowego powinny być najlepszym, jakie możemy osiągnąć.źródło
Ta funkcja działa również dla ujemnych zakresów zmiennoprzecinkowych:
float randomFloat(float Min, float Max){ return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min; }
źródło
Min+(Max-Min)*((float)arc4random())/ULONG_MAX
zamiast tego.(float)
Obsada jest po prostu paranoja.Swift 4.2+
Swift 4.2 dodaje natywne wsparcie dla losowej wartości w zakresie:
let x = Float.random(in: 0.0...1.0) let y = Double.random(in: 0.0...1.0) let z = Float80.random(in: 0.0...1.0)
Doc:
random(in range: ClosedRange<Float>)
random(in range: Range<Float>)
random(in range: ClosedRange<Double>)
random(in range: Range<Double>)
random(in range: ClosedRange<Float80>)
random(in range: Range<Float80>)
źródło
(float)rand() / RAND_MAX
Poprzedni post zawierający sam „rand ()” był niepoprawny. To jest poprawny sposób używania rand ().
Spowoduje to utworzenie liczby z zakresu od 0 do 1
źródło
To jest rozszerzenie dla Float random number Swift 3.1
// MARK: Float Extension public extension Float { /// Returns a random floating point number between 0.0 and 1.0, inclusive. public static var random: Float { return Float(arc4random()) / Float(UInt32.max)) } /// Random float between 0 and n-1. /// /// - Parameter n: Interval max /// - Returns: Returns a random float point number between 0 and n max public static func random(min: Float, max: Float) -> Float { return Float.random * (max - min) + min } }
źródło
Swift 4.2
Swift 4.2 zawiera natywne i dość w pełni funkcjonalne API liczb losowych w standardowej bibliotece. ( Propozycja Swift Evolution SE-0202 )
let intBetween0to9 = Int.random(in: 0...9) let doubleBetween0to1 = Double.random(in: 0...1)
Wszystkie typy liczb mają funkcję static random (in :), która przyjmuje zakres i zwraca liczbę losową z podanego zakresu.
źródło
Użyj tego, aby uniknąć problemów z górną granicą arc4random ()
u_int32_t upper_bound = 1000000; float r = arc4random_uniform(upper_bound)*1.0/upper_bound;
Zwróć uwagę, że dotyczy to MAC_10_7, IPHONE_4_3 i nowszych.
źródło
upper_bound-1
. Mimo to nadal miałbyś arbitralnie niską precyzję spowodowaną przez górne_bronienie, więc powinieneś zwiększyć górne_obowiązanie do UINT32_MAX. Możesz uzyskać jeszcze lepszą precyzję, używającarc4random()*1.0 / UINT32_MAX
zamiastarc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1)
.arc4random
ma zakres do 0x100000000 (4294967296)To kolejna dobra opcja do generowania liczb losowych od 0 do 1:
srand48(time(0)); // pseudo-random number initializer. double r = drand48();
źródło
float x = arc4random() % 11 * 0.1;
To daje losowy zmiennoprzecinkowy między 0 i 1. Więcej informacji tutaj
źródło
domyślnie tworzy liczbę losową (zmiennoprzecinkową) z przedziału od 0 do 1.
źródło
rand()
nie wydaje się istnieć na iOS , a gdyby tak było, dałoby liczbę całkowitą, tak jak na każdym innym * NIX.rand()
jest częścią C, która z kolei jest częścią Objective-C (używanego w programowaniu na iOS). Funkcje C jakrand()
absolutnie istnieją na iOS, alearc4random()
są preferowane.