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?
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?
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.
ARC4RANDOM_MAX
musi być zdefiniowana ręcznie, ale 0x100000000
jest 4294967296 , która jest ULONG_MAX + 1
. Gdzie jest udokumentowane, że w każdym razie arc4random()
jest maksimum ULONG_MAX
?
// Seed (only once)
srand48(time(0));
double x = drand48();
// Swift version
// Seed (only once)
srand48(Int(Date().timeIntervalSince1970))
let x = drand48()
Funkcje drand48 () i erand48 () zwracają nieujemne wartości zmiennoprzecinkowe o podwójnej precyzji, równomiernie rozłożone w przedziale [0,0, 1,0].
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.
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 :
let val = Float(arc4random()) / Float(UInt32.max)
Jest optymalny dla:
Float
(lub Float32
) który ma znaczącą precyzję 24 bitów dla mantysyŁatwo jest osiągnąć 48-bitową precyzję drand48
( która używa arc4random_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()
Double
i Float80
)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
(lub Float64
) który ma znaczącą precyzję 52 bitów dla mantysyFloat80
który ma znaczącą precyzję 64 bitów dla swojej mantysyOdpowiedzi, 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
lub random
. Więc nasze rozwiązania powyżej 32-bitowego i 64-bitowego powinny być najlepszym, jakie możemy osiągnąć.
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;
}
Min+(Max-Min)*((float)arc4random())/ULONG_MAX
zamiast tego. (float)
Obsada jest po prostu paranoja.
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:
(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
Dokumentacja BSD:
Funkcja rand () oblicza sekwencję pseudolosowych liczb całkowitych z
zakresu od 0 do RAND_MAX (zgodnie z definicją w pliku nagłówkowym „stdlib.h”).
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
}
}
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.
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.
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ąc arc4random()*1.0 / UINT32_MAX
zamiast arc4random_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();
float x = arc4random() % 11 * 0.1;
To daje losowy zmiennoprzecinkowy między 0 i 1. Więcej informacji tutaj
rand()
domyślnie tworzy liczbę losową (zmiennoprzecinkową) z przedziału od 0 do 1.
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 jak rand()
absolutnie istnieją na iOS, ale arc4random()
są preferowane.