J'essaie de générer un nombre aléatoire compris entre 0 et 1. Je continue à lire arc4random()
, mais il n'y a aucune information sur l'obtention d'un flottant. Comment puis-je faire cela?
84
J'essaie de générer un nombre aléatoire compris entre 0 et 1. Je continue à lire arc4random()
, mais il n'y a aucune information sur l'obtention d'un flottant. Comment puis-je faire cela?
Réponses:
Valeur aléatoire dans [0, 1 [ (y compris 0, sauf 1):
double val = ((double)arc4random() / UINT32_MAX);
Un peu plus de détails ici .
La plage réelle est [0, 0,999999999767169356] , car la limite supérieure est (double) 0xFFFFFFFF / 0x100000000.
la source
ARC4RANDOM_MAX
doit être défini manuellement, mais0x100000000
c'est 4294967296 , ce qui l'estULONG_MAX + 1
. Où est-il documenté quearc4random()
le maximum est deULONG_MAX
toute façon?// Seed (only once) srand48(time(0)); double x = drand48(); // Swift version // Seed (only once) srand48(Int(Date().timeIntervalSince1970)) let x = drand48()
la source
drand48
faut initialiser une fois avec une graine. La documentation Apple suggère également qu'il devrait être initialisé.double
. Consultez stackoverflow.com/a/34765674/1033581 pour savoir comment obtenir la meilleure précision.Pour Swift 4.2+, voir: https://stackoverflow.com/a/50733095/1033581
Vous trouverez ci-dessous des recommandations pour une uniformité correcte et une précision optimale pour ObjC et Swift 4.1.
Précision 32 bits (optimale pour
Float
)Valeur aléatoire uniforme dans [0, 1] (y compris 0.0 et 1.0), précision jusqu'à 32 bits:
Obj-C :
float val = (float)arc4random() / UINT32_MAX;
Swift :
C'est optimal pour:
Float
(ouFloat32
) qui a une précision de significande de 24 bits pour sa mantissePrécision 48 bits (déconseillée)
Il est facile d'obtenir une précision de 48 bits avec
drand48
( qui utilisearc4random_buf
sous le capot ). Mais notez que drand48 a des défauts en raison de l'exigence d'amorçage et aussi parce qu'il n'est pas optimal pour randomiser les 52 bits de la double mantisse.Valeur aléatoire uniforme en [0, 1] , précision de 48 bits:
Swift :
// seed (only needed once) srand48(Int(Date.timeIntervalSinceReferenceDate)) // random Double value let val = drand48()
Précision 64 bits (optimale pour
Double
etFloat80
)Valeur aléatoire uniforme dans [0, 1] (y compris 0.0 et 1.0), précision jusqu'à 64 bits:
Swift , utilisant deux appels à arc4random:
let arc4random64 = UInt64(arc4random()) << 32 &+ UInt64(arc4random()) let val = Float80(arc4random64) / Float80(UInt64.max)
Swift , en utilisant un appel à arc4random_buf:
var arc4random64: UInt64 = 0 arc4random_buf(&arc4random64, MemoryLayout.size(ofValue: arc4random64)) let val = Float80(arc4random64) / Float80(UInt64.max)
C'est optimal pour:
Double
(ouFloat64
) qui a une précision de significande de 52 bits pour sa mantisseFloat80
qui a une précision significand de 64 bits pour sa mantisseRemarques
Comparaisons avec d'autres méthodes
Les réponses dans lesquelles la fourchette exclut l'une des bornes (0 ou 1) souffrent probablement d'un biais d'uniformité et doivent être évitées.
arc4random()
, la meilleure précision est 1 / 0xFFFFFFFF (UINT32_MAX)arc4random_uniform()
, la meilleure précision est 1 / 0xFFFFFFFE (UINT32_MAX-1)rand()
( secrètement en utilisant arc4random ), la meilleure précision est 1 / 0x7FFFFFFF (RAND_MAX)random()
( secrètement en utilisant arc4random ), la meilleure précision est 1 / 0x7FFFFFFF (RAND_MAX)Il est mathématiquement impossible d'obtenir mieux que 32 bits de précision avec un seul appel à
arc4random
,arc4random_uniform
,rand
ourandom
. Ainsi, nos solutions 32 bits et 64 bits ci-dessus devraient être les meilleures que nous puissions réaliser.la source
Cette fonction fonctionne également pour les plages de flotteurs négatifs:
float randomFloat(float Min, float Max){ return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min; }
la source
Min+(Max-Min)*((float)arc4random())/ULONG_MAX
place. Le(float)
casting est juste de la paranoïa.Swift 4.2+
Swift 4.2 ajoute la prise en charge native d'une valeur aléatoire dans une plage:
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:
random(in range: ClosedRange<Float>)
random(in range: Range<Float>)
random(in range: ClosedRange<Double>)
random(in range: Range<Double>)
random(in range: ClosedRange<Float80>)
random(in range: Range<Float80>)
la source
(float)rand() / RAND_MAX
Le message précédent indiquant "rand ()" seul était incorrect. C'est la bonne façon d'utiliser rand ().
Cela créera un nombre entre 0 -> 1
la source
Ceci est une extension pour le nombre aléatoire flottant 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 } }
la source
Swift 4.2
Swift 4.2 a inclus une API de nombres aléatoires native et assez complète dans la bibliothèque standard. ( Proposition Swift Evolution SE-0202 )
let intBetween0to9 = Int.random(in: 0...9) let doubleBetween0to1 = Double.random(in: 0...1)
Tous les types de nombres ont la fonction statique aléatoire (in :) qui prend la plage et renvoie le nombre aléatoire dans la plage donnée.
la source
Utilisez ceci pour éviter les problèmes avec la limite supérieure d' arc4random ()
u_int32_t upper_bound = 1000000; float r = arc4random_uniform(upper_bound)*1.0/upper_bound;
Notez qu'il est applicable pour MAC_10_7, IPHONE_4_3 et supérieur.
la source
upper_bound-1
. Cependant, vous auriez toujours une précision arbitrairement basse causée par upper_bound, vous devez donc augmenter la valeur upper_bound à UINT32_MAX. Et vous pouvez obtenir une précision encore meilleure en utilisantarc4random()*1.0 / UINT32_MAX
au lieu dearc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1)
.arc4random
a une plage allant jusqu'à 0x100000000 (4294967296)C'est une autre bonne option pour générer des nombres aléatoires entre 0 et 1:
srand48(time(0)); // pseudo-random number initializer. double r = drand48();
la source
float x = arc4random() % 11 * 0.1;
Cela produit un flottant aléatoire entre 0 et 1. Plus d'informations ici
la source
par défaut produit un nombre aléatoire (float) entre 0 et 1.
la source
rand()
ne semble pas exister sur iOS , et si c'était le cas, il produirait un entier comme sur tous les autres * NIX.rand()
fait partie de C, qui fait à son tour partie d'Objective-C (qui est utilisé dans la programmation iOS). Les fonctions C commerand()
existent absolument sur iOS, mais ellesarc4random()
sont préférées.