Genera un flotador aleatorio entre 0 y 1

84

Estoy tratando de generar un número aleatorio que esté entre 0 y 1. Sigo leyendo arc4random(), pero no hay ninguna información sobre cómo obtener un flotador. ¿Cómo hago esto?

jini
fuente
1
No duplicados, esta parece ser la única pregunta explícitamente relacionada con los flotadores.
P i

Respuestas:

139

Valor aleatorio en [0, 1 [ (incluido 0, excluido 1):

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

Un poco más de detalles aquí .

El rango real es [0, 0.999999999767169356] , ya que el límite superior es (doble) 0xFFFFFFFF / 0x100000000.

Vladimir
fuente
Gracias. La respuesta más directa que he visto. Leeré su enlace y obtendré detalles adicionales sobre esto. Gracias de nuevo.
jini
3
Es extraño que ARC4RANDOM_MAXtenga que definirse manualmente, pero 0x100000000es 4294967296 , que es ULONG_MAX + 1. ¿Dónde está documentado que arc4random()es máximo de ULONG_MAXtodos modos?
bobobobo
@bobobobo, desde aquí: developer.apple.com/library/mac/#documentation/Darwin/Reference/… La función arc4random () devuelve números pseudoaleatorios en el rango de 0 a (2 ** 32) -1
Vladimir
8
En realidad, el valor debería ser 0xFFFFFFFF, (2 ** 32) -1 == 0x100000000 - 0x1 == 0xFFFFFFFF == UINT32_MAX como lo indica actualmente Jörg Bühmann en el enlace.
Josejulio
1
¡No se garantiza que los valores generados de esta manera se distribuyan uniformemente!
Kelin
107
// Seed (only once)
srand48(time(0));

double x = drand48();

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

let x = drand48()

Las funciones drand48 () y erand48 () devuelven valores de coma flotante no negativos, de doble precisión, distribuidos uniformemente en el intervalo [0.0, 1.0].

Jovan Stankovic
fuente
19
Esta debería ser la mejor respuesta.
John Riselvato
Tal vez necesite actualizar solo un poco la respuesta, leí en NSHipster que drand48debe inicializarse una vez con una semilla. La documentación de Apple también sugiere que debe inicializarse.
dulaccc
1
Se necesita semilla porque le da a este generador aleatorio un punto de partida para los cálculos. Sin ella, la secuencia aleatoria siempre sería la misma en todos los lanzamientos de aplicaciones.
Jovan Stankovic
Esta es la mejor respuesta.
sabiland
Esta respuesta no es una respuesta de precisión óptima para a double. Consulte stackoverflow.com/a/34765674/1033581 sobre cómo lograr la mejor precisión.
Cœur
16

Para Swift 4.2+, consulte: https://stackoverflow.com/a/50733095/1033581


A continuación se presentan recomendaciones para una uniformidad correcta y una precisión óptima para ObjC y Swift 4.1.

Precisión de 32 bits (óptima para Float )

Valor aleatorio uniforme en [0, 1] (incluidos 0.0 y 1.0), hasta 32 bits de precisión:

Obj-C :

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

Rápido :

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

Es óptimo para:

  • a Float(o Float32) que tiene una precisión significativa de 24 bits para su mantisa

Precisión de 48 bits (desaconsejado)

Es fácil lograr una precisión de 48 bits con drand48( que se usa arc4random_bufdebajo del capó ). Pero tenga en cuenta que drand48 tiene fallas debido al requisito de semilla y también por no ser óptimo para aleatorizar los 52 bits de la mantisa doble.

Valor aleatorio uniforme en [0, 1] , precisión de 48 bits:

Rápido :

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

Precisión de 64 bits (óptima para Doubley Float80)

Valor aleatorio uniforme en [0, 1] (incluidos 0,0 y 1,0), precisión de hasta 64 bits:

Swift , usando dos llamadas a arc4random:

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

Swift , usando una llamada a arc4random_buf:

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

Es óptimo para:

  • a Double(o Float64) que tiene una precisión significativa de 52 bits para su mantisa
  • a Float80que tiene una precisión significativa de 64 bits para su mantisa

Notas

Comparaciones con otros métodos

Las respuestas en las que el rango excluye uno de los límites (0 o 1) probablemente adolecen de un sesgo de uniformidad y deben evitarse.

  • usando arc4random(), la mejor precisión es 1 / 0xFFFFFFFF (UINT32_MAX)
  • usando arc4random_uniform(), la mejor precisión es 1 / 0xFFFFFFFE (UINT32_MAX-1)
  • usando rand()( usando secretamente arc4random ), la mejor precisión es 1 / 0x7FFFFFFF (RAND_MAX)
  • usando random()( usando secretamente arc4random ), la mejor precisión es 1 / 0x7FFFFFFF (RAND_MAX)

Es matemáticamente imposible de lograr mejor que 32 bits de precisión con una sola llamada a arc4random, arc4random_uniform, rando random. Por lo tanto, nuestras soluciones anteriores de 32 bits y 64 bits deberían ser las mejores que podamos lograr.

Cœur
fuente
'Float80' no está disponible en dispositivos iOS reales (solo funciona en el simulador).
Cœur
10

Esta función también funciona para rangos de flotación negativos:

float randomFloat(float Min, float Max){
    return ((arc4random()%RAND_MAX)/(RAND_MAX*1.0))*(Max-Min)+Min;
}
Héctor Sánchez
fuente
4
Operación de módulo extraño. utilizar Min+(Max-Min)*((float)arc4random())/ULONG_MAXen su lugar. El (float)elenco es solo paranoia.
bobobobo
@bobobobo mientras estoy de acuerdo con el módulo extraño, recomiendo dividir por UINT32_MAX (4294967295 siempre) en lugar de ULONG_MAX (18446744073709551615 en 64 bits).
Cœur
1
(float)rand() / RAND_MAX

La publicación anterior que decía "rand ()" solo era incorrecta. Esta es la forma correcta de usar rand ().

Esto creará un número entre 0 -> 1

Documentos BSD:

La función rand () calcula una secuencia de enteros pseudoaleatorios en el
rango de 0 a RAND_MAX (como lo define el archivo de encabezado "stdlib.h").

Leslie Godwin
fuente
1

Esta es la extensión para Float número aleatorio 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
fuente
@ Cœur Gracias, cambio eso
YannSteph
1

Rápido 4.2

Swift 4.2 ha incluido una API de números aleatorios nativa y bastante completa en la biblioteca estándar. ( Propuesta de Swift Evolution SE-0202 )

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

Todos los tipos de números tienen la función aleatoria estática (en :) que toma el rango y devuelve el número aleatorio en el rango dado.

Suhit Patil
fuente
0

Use esto para evitar problemas con el límite superior de arc4random ()

u_int32_t upper_bound = 1000000;

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

Tenga en cuenta que es aplicable para MAC_10_7, IPHONE_4_3 y superior.

malex
fuente
Hay un problema de rango fundamental con esto. Se nota fácilmente cuando establece upper_bound en 10, arc4random_uniform devolverá valores de 0 a 9 y el resultado final será de 0,0000 a 0,9000. En su lugar, debería dividir por upper_bound-1. Sin embargo, todavía tendría una precisión arbitrariamente baja causada por upper_bound, por lo que debería aumentar el upper_bound a UINT32_MAX. Y puede obtener una precisión aún mayor al usar en arc4random()*1.0 / UINT32_MAXlugar de arc4random_uniform(UINT32_MAX)*1.0 / (UINT32_MAX-1).
Cœur
-1

arc4random tiene un rango de hasta 0x100000000 (4294967296)

Esta es otra buena opción para generar números aleatorios entre 0 y 1:

srand48(time(0));      // pseudo-random number initializer.
double r = drand48();
Gurunatha Dogi
fuente
El valor máximo de arc4random es 0xFFFFFFFF
Cœur
Gracias @ Cœur ..max val 0xFFFFFFFF no lo sabía
Gurunatha Dogi
su solución también es idéntica a la respuesta de Jovan Stankovic.
Cœur
Ohh, no vi eso @ Cœur
Gurunatha Dogi
-4
float x = arc4random() % 11 * 0.1;

Eso produce un flotador aleatorio entre 0 y 1. Más información aquí

jhilgert00
fuente
3
Nota: solo da 11 valores discretos: 0.0, 0.1, 0.2, ..., 1.0
TalkLittle
8
Sí, la operación de módulo corta el resultado de arc4random () a un valor entre 0 y 10, luego lo divide por 10. Esta respuesta es realmente mala para uso general.
bobobobo
-4
rand() 

por defecto produce un número aleatorio (flotante) entre 0 y 1.

eragon1189
fuente
4
Esto produce un int aleatorio para mí.
AlexQueue
rand()no parece existir en iOS , y si lo hiciera, produciría un número entero como lo hace en cualquier otro * NIX.
jscs
2
@JoshCaswell rand()es parte de C, que a su vez es parte de Objective-C (que se usa en la programación de iOS). Las funciones de C como rand()absolutamente existen en iOS, pero arc4random()se prefiere.
Viernes