Générer un flottant aléatoire entre 0 et 1

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?

jini
la source
1
Pas de doublons, cela semble être la seule question concernant explicitement les flottants.
P i

Réponses:

139

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.

Vladimir
la source
Merci. La réponse la plus simple que j'ai vue. Je vais lire votre lien et obtenir des détails supplémentaires à ce sujet. Merci encore.
jini
3
C'est bizarre qui ARC4RANDOM_MAXdoit être défini manuellement, mais 0x100000000c'est 4294967296 , ce qui l'est ULONG_MAX + 1. Où est-il documenté que arc4random()le maximum est de ULONG_MAXtoute façon?
bobobobo du
@bobobobo, à partir d'ici: developer.apple.com/library/mac/#documentation/Darwin/Reference/… La fonction arc4random () renvoie des nombres pseudo-aléatoires dans la plage de 0 à (2 ** 32) -1
Vladimir
8
En fait, la valeur doit être 0xFFFFFFFF, (2 ** 32) -1 == 0x100000000 - 0x1 == 0xFFFFFFFF == UINT32_MAX comme actuellement indiqué par Jörg Bühmann sur le lien.
Josejulio
1
Les valeurs générées de cette manière ne sont pas garanties d'être uniformément distribuées!
kelin
107
// Seed (only once)
srand48(time(0));

double x = drand48();

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

let x = drand48()

Les fonctions drand48 () et erand48 () renvoient des valeurs non négatives, double précision, à virgule flottante, uniformément réparties sur l'intervalle [0,0, 1,0].

Jovan Stankovic
la source
19
Cela devrait être la meilleure réponse.
John Riselvato
Vous avez peut-être besoin de mettre à jour juste un peu la réponse, j'ai lu sur NSHipster qu'il drand48faut initialiser une fois avec une graine. La documentation Apple suggère également qu'il devrait être initialisé.
dulaccc le
1
La graine est nécessaire car elle donne à ce générateur aléatoire un point de départ pour les calculs. Sans cela, la séquence aléatoire serait toujours la même entre les lancements d'applications.
Jovan Stankovic le
C'est la meilleure réponse.
sabiland
Cette réponse n'est pas une réponse de précision optimale pour a double. Consultez stackoverflow.com/a/34765674/1033581 pour savoir comment obtenir la meilleure précision.
Cœur
16

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 :

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

C'est optimal pour:

  • a Float(ou Float32) qui a une précision de significande de 24 bits pour sa mantisse

Précision 48 bits (déconseillée)

Il est facile d'obtenir une précision de 48 bits avec drand48( qui utilise arc4random_bufsous 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 Doubleet Float80)

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:

  • a Double(ou Float64) qui a une précision de significande de 52 bits pour sa mantisse
  • a Float80qui a une précision significand de 64 bits pour sa mantisse

Remarques

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.

  • en utilisant arc4random(), la meilleure précision est 1 / 0xFFFFFFFF (UINT32_MAX)
  • en utilisant arc4random_uniform(), la meilleure précision est 1 / 0xFFFFFFFE (UINT32_MAX-1)
  • en utilisant rand()( secrètement en utilisant arc4random ), la meilleure précision est 1 / 0x7FFFFFFF (RAND_MAX)
  • en utilisant 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, randou random. Ainsi, nos solutions 32 bits et 64 bits ci-dessus devraient être les meilleures que nous puissions réaliser.

Cœur
la source
'Float80' n'est pas disponible sur les vrais appareils iOS (il ne fonctionne que sur le simulateur).
Cœur
10

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;
}
Héctor Sanchez
la source
4
Fonctionnement du module externe. utiliser à la Min+(Max-Min)*((float)arc4random())/ULONG_MAXplace. Le (float)casting est juste de la paranoïa.
bobobobo
@bobobobo alors que je suis d'accord sur le module externe, je conseille de diviser par UINT32_MAX (4294967295 toujours) au lieu de ULONG_MAX (18446744073709551615 sur 64 bits).
Cœur
1
(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

Documents BSD:

La fonction rand () calcule une séquence d'entiers pseudo-aléatoires dans la
plage de 0 à RAND_MAX (comme défini par le fichier d'en-tête "stdlib.h").

Leslie Godwin
la source
1

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
    }
}
YannSteph
la source
@ Cœur Merci, je change ça
YannSteph
1

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.

Suhit Patil
la source
0

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.

malex
la source
Il y a un problème de gamme fondamental avec cela. C'est facilement perceptible lorsque vous définissez upper_bound sur 10, arc4random_uniform renverra des valeurs de 0 à 9 et le résultat final sera de 0,0000 à 0,9000. Vous devriez plutôt diviser par 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 utilisant arc4random()*1.0 / UINT32_MAXau lieu de arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1).
Cœur du
-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();
Gurunatha Dogi
la source
La valeur maximale d'arc4random est 0xFFFFFFFF
Cœur
Merci @ Cœur ..max val 0xFFFFFFFF je ne savais pas
Gurunatha Dogi
votre solution est également identique à la réponse de Jovan Stankovic.
Cœur du
Ohh je n'ai pas vu ça @ Cœur
Gurunatha Dogi
-4
float x = arc4random() % 11 * 0.1;

Cela produit un flottant aléatoire entre 0 et 1. Plus d'informations ici

jhilgert00
la source
3
Remarque: donne seulement 11 valeurs discrètes: 0,0, 0,1, 0,2, ..., 1,0
TalkLittle
8
Oui, l'opération module coupe le résultat d'arc4random () entre 0 et 10, puis il le divise par 10. Cette réponse est vraiment mauvaise pour une utilisation générale.
bobobobo du
-4
rand() 

par défaut produit un nombre aléatoire (float) entre 0 et 1.

eragon1189
la source
4
Cela produit un int aléatoire pour moi.
AlexQueue
rand()ne semble pas exister sur iOS , et si c'était le cas, il produirait un entier comme sur tous les autres * NIX.
jscs
2
@JoshCaswell rand()fait partie de C, qui fait à son tour partie d'Objective-C (qui est utilisé dans la programmation iOS). Les fonctions C comme rand()existent absolument sur iOS, mais elles arc4random()sont préférées.
Frungi