Wygeneruj losową liczbę zmiennoprzecinkową od 0 do 1

84

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?

jini
źródło
1
To nie jest duplikat, wydaje się, że jest to jedyne pytanie bezpośrednio odnoszące się do elementów zmiennoprzecinkowych.
P i

Odpowiedzi:

139

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.

Vladimir
źródło
Dziękuję Ci. Najprostsza odpowiedź, jaką widziałem. Przeczytam Twój link i uzyskam dodatkowe informacje na ten temat. Dzięki jeszcze raz.
jini
3
To dziwne, że ARC4RANDOM_MAXmusi być zdefiniowana ręcznie, ale 0x100000000jest 4294967296 , która jest ULONG_MAX + 1. Gdzie jest udokumentowane, że w każdym razie arc4random()jest maksimum ULONG_MAX?
bobobobo
@bobobobo, stąd: developer.apple.com/library/mac/#documentation/Darwin/Reference/… Funkcja arc4random () zwraca liczby pseudolosowe z zakresu od 0 do (2 ** 32) -1
Vladimir
8
W rzeczywistości wartość powinna wynosić 0xFFFFFFFF, (2 ** 32) -1 == 0x100000000 - 0x1 == 0xFFFFFFFF == UINT32_MAX, jak obecnie podaje Jörg Bühmann w linku.
Josejulio
1
Nie ma gwarancji, że wartości wygenerowane w ten sposób będą równomiernie rozłożone!
kelin
107
// 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].

Jovan Stankovic
źródło
19
To powinna być najlepsza odpowiedź.
John Riselvato
Być może będziesz musiał zaktualizować tylko trochę odpowiedź, przeczytałem o NSHipster, który drand48trzeba zainicjować raz za pomocą seeda . Dokumentacja Apple sugeruje również, że należy go zainicjować.
dulaccc
1
Ziarno jest potrzebne, ponieważ daje temu generatorowi losowemu punkt wyjścia do obliczeń. Bez tego losowa sekwencja byłaby zawsze taka sama we wszystkich uruchomieniach aplikacji.
Jovan Stankovic
To najlepsza odpowiedź.
sabiland
Ta odpowiedź nie jest optymalną dokładną odpowiedzią dla a double. Zobacz stackoverflow.com/a/34765674/1033581, aby dowiedzieć się, jak osiągnąć najlepszą precyzję.
Cœur
16

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 :

let val = Float(arc4random()) / Float(UInt32.max)

Jest optymalny dla:

  • a Float(lub Float32) który ma znaczącą precyzję 24 bitów dla mantysy

48-bitowa precyzja (odradzane)

Łatwo jest osiągnąć 48-bitową precyzję drand48( która używa arc4random_bufpod 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 Doublei 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:

  • a Double(lub Float64) który ma znaczącą precyzję 52 bitów dla mantysy
  • a Float80który ma znaczącą precyzję 64 bitów dla swojej mantysy

Uwagi

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ć.

  • przy użyciu arc4random(), najlepsza precyzja to 1 / 0xFFFFFFFF (UINT32_MAX)
  • przy użyciu arc4random_uniform(), najlepsza precyzja to 1 / 0xFFFFFFFE (UINT32_MAX-1)
  • używając rand()( potajemnie używając arc4random ), najlepsza precyzja to 1 / 0x7FFFFFFF (RAND_MAX)
  • używając 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, randlub random. Więc nasze rozwiązania powyżej 32-bitowego i 64-bitowego powinny być najlepszym, jakie możemy osiągnąć.

Cœur
źródło
„Float80” jest niedostępny na prawdziwych urządzeniach iOS (działa tylko na symulatorze).
Cœur
10

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;
}
Héctor Sanchez
źródło
4
Działanie zewnętrznego modułu. użyj Min+(Max-Min)*((float)arc4random())/ULONG_MAXzamiast tego. (float)Obsada jest po prostu paranoja.
bobobobo
@bobobobo zgadzam się co do zewnętrznego modułu, ale radzę podzielić przez UINT32_MAX (zawsze 4294967295) zamiast ULONG_MAX (18446744073709551615 na 64 bitach).
Cœur
1
(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”).

Leslie Godwin
źródło
1

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
    }
}
YannSteph
źródło
@ Cœur Dziękuję, zmieniam to
YannSteph
1

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.

Suhit Patil
źródło
0

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.

malex
źródło
Z tym wiąże się podstawowy problem z zasięgiem. Jest to łatwo zauważalne, gdy ustawisz upper_bound na 10, arc4random_uniform zwróci wartości od 0 do 9, a ostateczny wynik wyniesie od 0,0000 do 0,9000. Zamiast tego powinieneś podzielić przez 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_MAXzamiast arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1).
Cœur
-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();
Gurunatha Dogi
źródło
Maksymalna wartość arc4random to 0xFFFFFFFF
Cœur
Dzięki @ Cœur ..max val 0xFFFFFFFF Nie wiedziałem
Gurunatha Dogi
Twoje rozwiązanie jest również identyczne z odpowiedzią Jovana Stankovicia.
Cœur
Ohh, nie widziałem tego @ Cœur
Gurunatha Dogi
-4
float x = arc4random() % 11 * 0.1;

To daje losowy zmiennoprzecinkowy między 0 i 1. Więcej informacji tutaj

jhilgert00
źródło
3
Uwaga: podaje tylko 11 dyskretnych wartości: 0,0, 0,1, 0,2, ..., 1,0
TalkLittle
8
Tak, operacja modułu powoduje, że wynik arc4random () wynosi od 0 do 10, a następnie dzieli go przez 10. Ta odpowiedź jest naprawdę zła do ogólnego użytku.
bobobobo
-4
rand() 

domyślnie tworzy liczbę losową (zmiennoprzecinkową) z przedziału od 0 do 1.

eragon1189
źródło
4
To daje mi losowy int.
AlexQueue
rand()nie wydaje się istnieć na iOS , a gdyby tak było, dałoby liczbę całkowitą, tak jak na każdym innym * NIX.
jscs
2
@JoshCaswell 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.
Frungi