2011-02-09 19 views
8

Estoy interesado en C++, aunque sospecho que simplemente importa la definición estándar de C. Creo que la respuesta es no a lo que dice el estándar, pero estoy más interesado en la respuesta práctica.¿El valor de RAND_MAX siempre es (2^n) -1?

Si RAND_MAX es siempre (2^n) -1, eso simplifica el tratamiento de un problema que apareció recientemente moviendo el código de MinGW GCC a Linux GCC. RAND_MAX parece ser más grande (no lo compruebo, pero posiblemente igual a INT_MAX o lo que sea que el símbolo sea), así que un viejo código ingenuamente escrito RAND_MAX no es lo suficientemente grande como para funcionar con el contratiempo. Ahora necesito decidir qué tan general necesito que sea esta biblioteca, teniendo en cuenta la dificultad del código de escritura que hace frente correctamente a la posibilidad de desbordamiento sin hacer suposiciones sobre, por ejemplo, el ancho de un int.

De todos modos, ¿hay algún compilador de C++ razonablemente utilizado que use algo distinto de (2^n) -1 para RAND_MAX?

Además, estoy en lo cierto ((RAND_MAX | (RAND_MAX >> 1)) == RAND_MAX) siempre y solo es verdadero si RAND_MAX es igual a ((2^n) -1) para un entero sin signo n. Creo que RAND_MAX es técnicamente un int, pero no tiene sentido tener un valor negativo o fraccionario, por lo que creo que puedo descartarlos con seguridad. Normalmente, no me molesta manipular los bits, pero sigo pensando que la expresión parece incorrecta, y no puedo entender por qué.

Finalmente, aunque no voy a estar contento hasta que tenga una solución de trabajo propia, ¿qué debería usar para números aleatorios en lugar de escribirlo yo mismo? Necesito números aleatorios en el rango 0 < = x < parámetro, y especialmente quiero las mismas probabilidades posibles para todos los números. Por ejemplo, tomar (rand()% upperbound) da un sesgo hacia valores más pequeños, especialmente cuando el límite superior es grande; quiero evitar eso.

¿Hay algo de Boost o C++ 0x para eso?

EDITAR

Tras algo en el bit "relacionada" en el lado de la página aparecen en efecto, hay una manera de obtener números aleatorios con dados límites inferior y superior de impulso.

Respuesta

3

No sé cuáles son las garantías en RAND_MAX, pero será mejor que lo evite si es posible debido a la cantidad de implementaciones rotas y porque comienza a andar en bicicleta bastante rápido en las aplicaciones actuales. Obteniendo una distribución uniforme se describe here.

Recomiendo Boost.Random en su lugar. El generador Mersenne twister representa una buena compensación entre velocidad, uso de memoria y calidad.

+0

Ya tengo una implementación de Twister de Mersenne, no es una buena razón, solo estaba cubierta en un libro. Una buena versión de la biblioteca sería más práctica, por supuesto. Gracias por los consejos. – Steve314

+1

Cambiaría a Boost si fuera tú; separa limpiamente el PRNG de las distribuciones de probabilidad e incluye una clase 'random_device' para el correcto sembrado (http://www.boost.org/doc/libs/release/doc/html/boost/random_device.html). –

+0

Se acepta aproximadamente el 80% debido al concepto erróneo sobre el enlace del rand: el punto de Boost es más práctico, pero ese enlace es muy interesante. – Steve314

5
  • No sé cualquier aplicación para la que RAND_MAX no es uno menos que una potencia de dos, pero eso no es un mandato de la norma;

  • ((RAND_MAX | (RAND_MAX >> 1)) == RAND_MAX) es de hecho una manera de probar si RAND_MAX es uno menos de una potencia de dos.

  • estoy usando

    int alea(int n){ 
        assert (0 < n && n <= RAND_MAX); 
        int partSize = 
        n == RAND_MAX ? 1 : 1 + (RAND_MAX-n)/(n+1); 
        int maxUsefull = partSize * n + (partSize-1); 
        int draw; 
        do { 
        draw = rand(); 
        } while (draw > maxUsefull); 
        return draw/partSize; 
    } 
    

hacer como distribuido uniformemente como posibles números aleatorios de rand().

+0

No puedo ' Bastante uso de esa función, porque el RAND_MAX es un problema demasiado pequeño que todavía existe en Windows. Dicho esto, podría compilar de forma condicional para elegir entre eso y la versión de use-two-randoms-to-make-one (el código existente combina eso con algo muy similar a tu código). Eso es lo que hice para cerrar el error por el momento de todos modos, parece que hacer trampa es todo. – Steve314

4

Para las implementaciones de rand que usan una (variante de) Generador congruente lineal (la mayoría de ellas), entonces RAND_MAX será un número primo, no necesariamente de la forma 2^n - 1 (un "primer Mersenne") .

Además, 2^31-1 es un número primo, pero si n no es primo, 2^n - 1 no es primo.

(De hecho, si n = ab, entonces 2^n - 1 = (2^a - 1) (1 + 2^b + 2^(2b) + ...))

Alrededor de 2^64, el único primo de Mersenne es 2^61 - 1.

Y realmente debería evitar los generadores congruenciales lineales si tiene algún requisito medio serio sobre la generación de números aleatorios. En realidad, diría que a excepción de un juego de tetris, debes evitar rand() de la biblioteca de C.

+1

Interesante. OTOH - "tetris" no está tan lejos de la marca, y para muchas personas, no solo para mí.La cantidad de personas que desarrollan criptobibliotecas críticas para la seguridad, u otras aplicaciones en las que realmente te importa qué tan aleatorio sea realmente ese generador, es probablemente bastante pequeña en comparación con, por ejemplo, el número de personas que desean complementar sus pruebas de regresión con algunas pruebas basadas en datos de prueba al azar o el número de personas que escriben juegos simples. – Steve314

+0

@ Steve314: cong. Lineal los generadores tienen fallas serias que los incapacita incluso para las aplicaciones matemáticas más sencillas. Ver por ej. http://www.javamex.com/tutorials/random_numbers/lcg_planes.shtml para ver a qué me refiero. –

+0

las palabras clave son "aplicaciones matemáticas", y puedo aceptar que incluso para algunas muy simples puede necesitar un generador más potente. Agregaré "simulación de ingeniería", que probablemente también esté debajo de mi manta "otras aplicaciones donde realmente te importa". Pero en serio: para muchos programadores, los números aleatorios son algo que rara vez necesitamos, y cuando lo hacemos, 'rand' casi siempre es lo suficientemente bueno. A veces, incluso "agregar uno al último número" es suficiente para generar algunos datos arbitrarios, guardando los pequeños problemas de siembra y buscando el encabezado correcto para incluir. – Steve314

1

En GCC (4.6) RAND_MAX = 0x7FFFFFFF (31bit) En MS Visual Studio (2012) RAND_MAX = 0x7FFF (15bit)

1

En embacadero C++ Builder, hay dos variables definidas en stdlib.h:

/* Maximum value returned by "rand" function*/ 
#define RAND_MAX 0x7FFFU 

/* Maximum value returned by "_lrand" function (also used by random() macro)*/ 
#define LRAND_MAX 0x7FFFFFFFU 
1

en el archivo de cabecera estándar de GNU, stdlib.h, hay una definición de RAND_MAX que debería ser la única definición en su sistema:

#define RAND_MAX 2147483647 

el valor 2147 483647 = 0x7fffffff es el entero de 32 bits sin signo más grande.

Las funciones rand, definidas en stdlib.h, son confiables en entornos GNU estándar con una advertencia: los entornos multi-threading (pthread) necesitarán pthread code para sincronizarse a fin de proteger el rand(), srand(), y rand_r() llama ya que no son reentrantes. Vea el man page for srand para una explicación.

RAND_MAX no se debe definir en ningún otro lugar en su sistema. Si ve un valor diferente para RAND_MAX o ve una definición de RAND_MAX en algún lugar, además de stdlib.h, este debe ser un entorno no estándar y no portátil. Windows es notorio por dificultar la estandarización y la portabilidad (por ejemplo, la implementación de sockets y las API).

+1

Esto es incorrecto "value 2147483647 = 0x7fffffff es el entero más grande de 32 bits sin signo". El valor 4294967295 = 0xffffffff es el entero de 32 bits sin signo más grande. Quizás quisiste decir "... el entero más grande de 32 bits firmado". – chux

Cuestiones relacionadas