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?


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.


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


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


„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;
}

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”).


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
    }
}

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


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.


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();

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


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.


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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.