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?
Risposte:
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.
ARC4RANDOM_MAX
debba essere definito manualmente, ma 0x100000000
è 4294967296 , che è ULONG_MAX + 1
. Dove è documentato che arc4random()
il massimo sia ULONG_MAX
comunque?
// 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].
drand48
deve essere inizializzato una volta con un seme. La documentazione di Apple suggerisce anche che dovrebbe essere inizializzato.
double
. Vedi stackoverflow.com/a/34765674/1033581 su come ottenere la massima precisione.
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.
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:
Float
(o Float32
) che ha un significato e una precisione di 24 bit per la sua mantissaÈ facile ottenere una precisione di 48 bit con drand48
( che utilizza arc4random_buf
sotto 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()
Double
e 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:
Double
(o Float64
) che ha un significato e una precisione di 52 bit per la sua mantissaFloat80
che ha un significato e una precisione di 64 bit per la sua mantissaLe risposte in cui l'intervallo esclude uno dei limiti (0 o 1) probabilmente soffrono di una distorsione di uniformità e dovrebbero essere evitate.
arc4random()
, la precisione migliore è 1 / 0xFFFFFFFF (UINT32_MAX)arc4random_uniform()
, la precisione migliore è 1 / 0xFFFFFFFE (UINT32_MAX-1)rand()
( segretamente usando arc4random ), la migliore precisione è 1 / 0x7FFFFFFF (RAND_MAX)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
, rand
o random
. Quindi le nostre soluzioni a 32 bit e 64 bit sopra dovrebbero essere le migliori che possiamo ottenere.
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;
}
Min+(Max-Min)*((float)arc4random())/ULONG_MAX
invece. Il (float)
cast è solo paranoia.
Swift 4.2 aggiunge il supporto nativo per un valore casuale in un intervallo:
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
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").
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
}
}
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.
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.
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_MAX
invece di arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-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();
float x = arc4random() % 11 * 0.1;
Questo produce un float casuale tra 0 e 1. Maggiori informazioni qui
rand()
di default produce un numero casuale (float) compreso tra 0 e 1.
rand()
non sembra esistere su iOS e, se lo fosse, produrrebbe un numero intero come su ogni altro * NIX.
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.