Genera un float casuale compreso tra 0 e 1


84

Sto cercando di generare un numero casuale compreso tra 0 e 1. Continuo a leggere arc4random(), ma non ci sono informazioni su come ottenere un float da esso. Come faccio a fare questo?


1
Non duplicati, questa sembra essere l'unica domanda esplicitamente pertinente ai float.
P i

Risposte:


139

Valore casuale in [0, 1 [ (compreso 0, escluso 1):

double val = ((double)arc4random() / UINT32_MAX);

Qualche dettaglio in più qui .

L'intervallo effettivo è [0, 0.999999999767169356] , poiché il limite superiore è (doppio) 0xFFFFFFFF / 0x100000000.


Grazie. La risposta più semplice che ho visto. Leggerò il tuo link e riceverò ulteriori dettagli su questo. Grazie ancora.
jini

3
È strano che ARC4RANDOM_MAXdebba essere definito manualmente, ma 0x100000000è 4294967296 , che è ULONG_MAX + 1. Dove è documentato che arc4random()il massimo sia ULONG_MAXcomunque?
bobobobo

@bobobobo, da qui: developer.apple.com/library/mac/#documentation/Darwin/Reference/… La funzione arc4random () restituisce numeri pseudo-casuali nell'intervallo da 0 a (2 ** 32) -1
Vladimir

8
In realtà, il valore dovrebbe essere 0xFFFFFFFF, (2 ** 32) -1 == 0x100000000 - 0x1 == 0xFFFFFFFF == UINT32_MAX come attualmente dichiarato da Jörg Bühmann sul link.
Josejulio

1
I valori generati in questo modo non sono garantiti per essere distribuiti uniformemente!
kelin

107
// Seed (only once)
srand48(time(0));

double x = drand48();

// Swift version
// Seed (only once)
srand48(Int(Date().timeIntervalSince1970))

let x = drand48()

Le funzioni drand48 () e erand48 () restituiscono valori non negativi, a doppia precisione, a virgola mobile, distribuiti uniformemente sull'intervallo [0.0, 1.0].


19
Questa dovrebbe essere la risposta migliore.
John Riselvato

Forse hai bisogno di aggiornare solo un po 'la risposta, ho letto su NSHipster che drand48deve essere inizializzato una volta con un seme. La documentazione di Apple suggerisce anche che dovrebbe essere inizializzato.
dulaccc

1
Il seme è necessario perché fornisce a questo generatore casuale un punto di partenza per i calcoli. Senza di essa, la sequenza casuale sarebbe sempre la stessa durante i lanci delle app.
Jovan Stankovic

Questa è la migliore risposta.
sabiland

Questa risposta non è una risposta di precisione ottimale per a double. Vedi stackoverflow.com/a/34765674/1033581 su come ottenere la massima precisione.
Cœur

16

Per Swift 4.2+ vedere: https://stackoverflow.com/a/50733095/1033581


Di seguito sono riportati i consigli per la corretta uniformità e precisione ottimale per ObjC e Swift 4.1.

Precisione a 32 bit (ottimale per Float)

Valore casuale uniforme in [0, 1] (inclusi 0,0 e 1,0), precisione fino a 32 bit:

Obj-C :

float val = (float)arc4random() / UINT32_MAX;

Swift :

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

È ottimale per:

  • a Float(o Float32) che ha un significato e una precisione di 24 bit per la sua mantissa

Precisione di 48 bit (sconsigliata)

È facile ottenere una precisione di 48 bit con drand48( che utilizza arc4random_bufsotto il cofano ). Ma nota che drand48 ha dei difetti a causa del requisito del seme e anche perché non è ottimale per randomizzare tutti i 52 bit di doppia mantissa.

Valore casuale uniforme in [0, 1] , precisione a 48 bit:

Swift :

// seed (only needed once)
srand48(Int(Date.timeIntervalSinceReferenceDate))
// random Double value
let val = drand48()

Precisione a 64 bit (ottimale per Doublee Float80)

Valore casuale uniforme in [0, 1] (inclusi 0,0 e 1,0), fino a 64 bit di precisione:

Swift , utilizzando due chiamate ad arc4random:

let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random())
let val = Float80(arc4random64) / Float80(UInt64.max)

Swift , utilizzando una chiamata ad arc4random_buf:

var arc4random64: UInt64 = 0
arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64))
let val = Float80(arc4random64) / Float80(UInt64.max)

È ottimale per:

  • a Double(o Float64) che ha un significato e una precisione di 52 bit per la sua mantissa
  • a Float80che ha un significato e una precisione di 64 bit per la sua mantissa

Appunti

Confronti con altri metodi

Le risposte in cui l'intervallo esclude uno dei limiti (0 o 1) probabilmente soffrono di una distorsione di uniformità e dovrebbero essere evitate.

  • utilizzando arc4random(), la precisione migliore è 1 / 0xFFFFFFFF (UINT32_MAX)
  • utilizzando arc4random_uniform(), la precisione migliore è 1 / 0xFFFFFFFE (UINT32_MAX-1)
  • usando rand()( segretamente usando arc4random ), la migliore precisione è 1 / 0x7FFFFFFF (RAND_MAX)
  • usando random()( segretamente usando arc4random ), la migliore precisione è 1 / 0x7FFFFFFF (RAND_MAX)

È matematicamente impossibile ottenere una migliore di 32 bit di precisione con una singola chiamata a arc4random, arc4random_uniform, rando random. Quindi le nostre soluzioni a 32 bit e 64 bit sopra dovrebbero essere le migliori che possiamo ottenere.


"Float80" non è disponibile su dispositivi iOS reali (funziona solo su simulatore).
Cœur

10

Questa funzione funziona anche per gli intervalli di float negativi:

float randomFloat(float Min, float Max){
    return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min;
}

4
Funzionamento del modulo estraneo. usa Min+(Max-Min)*((float)arc4random())/ULONG_MAXinvece. Il (float)cast è solo paranoia.
bobobobo

@bobobobo mentre sono d'accordo sul modulo estraneo, consiglio di dividere per UINT32_MAX (4294967295 sempre) invece di ULONG_MAX (18446744073709551615 su 64 bit).
Cœur


1
(float)rand() / RAND_MAX

Il post precedente che dichiarava "rand ()" da solo non era corretto. Questo è il modo corretto di usare rand ().

Questo creerà un numero compreso tra 0 e 1

Documenti BSD:

La funzione rand () calcola una sequenza di interi pseudo-casuali
nell'intervallo da 0 a RAND_MAX (come definito dal file di intestazione "stdlib.h").


1

Questa è l'estensione per il numero casuale Float 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 Grazie, cambio quello
YannSteph,

1

Swift 4.2

Swift 4.2 ha incluso un'API di numeri casuali nativa e abbastanza completa nella libreria standard. ( Proposta Swift Evolution SE-0202 )

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

Tutti i tipi di numeri hanno la funzione random (in :) che prende l'intervallo e restituisce il numero casuale nell'intervallo dato.


0

Usalo per evitare problemi con il limite superiore di arc4random ()

u_int32_t upper_bound = 1000000;

float r = arc4random_uniform(upper_bound)*1.0/upper_bound;

Nota che è applicabile per MAC_10_7, IPHONE_4_3 e versioni successive.


C'è un problema di portata fondamentale con questo. È facilmente visibile quando si imposta upper_bound su 10, arc4random_uniform restituirà valori da 0 a 9 e il risultato finale sarà compreso tra 0,0000 e 0,9000. Dovresti invece dividere per upper_bound-1. Tuttavia, avresti ancora una precisione arbitrariamente bassa causata da upper_bound, quindi dovresti aumentare upper_bound a UINT32_MAX. E puoi ottenere una precisione ancora migliore usando arc4random()*1.0 / UINT32_MAXinvece di arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1).
Cœur,

-1

arc4random ha un intervallo fino a 0x100000000 (4294967296)

Questa è un'altra buona opzione per generare numeri casuali compresi tra 0 e 1:

srand48(time(0));      // pseudo-random number initializer.
double r = drand48();

Il valore massimo di arc4random è 0xFFFFFFFF
Cœur

Grazie @ Cœur ..max val 0xFFFFFFFF non lo sapevo
Gurunatha Dogi

anche la tua soluzione è identica alla risposta di Jovan Stankovic.
Cœur

Ohh non l'ho visto @ Cœur
Gurunatha Dogi

-4
float x = arc4random() % 11 * 0.1;

Questo produce un float casuale tra 0 e 1. Maggiori informazioni qui


3
Nota: fornisce solo 11 valori discreti: 0,0, 0,1, 0,2, ..., 1,0
TalkLittle

8
Sì, l'operazione del modulo riduce il risultato di arc4random () portandolo tra 0 e 10, quindi lo divide per 10. Questa risposta è davvero negativa per un uso generale.
bobobobo

-4
rand() 

di default produce un numero casuale (float) compreso tra 0 e 1.


4
Questo produce un int casuale per me.
AlexQueue

rand()non sembra esistere su iOS e, se lo fosse, produrrebbe un numero intero come su ogni altro * NIX.
jscs

2
@JoshCaswell rand()fa parte di C, che a sua volta fa parte di Objective-C (che viene utilizzato nella programmazione iOS). Le funzioni C come rand()esistono assolutamente su iOS, ma arc4random()sono preferite.
Frungi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.