2012-05-22 15 views
13

He buscado el estándar C (desde 1999) y solo dice que RAND_MAX debe ser al menos 32767 pero no dice nada sobre si esta macro debe expandirse a una int firmada o no firmada. Las especificaciones únicas de UNIX (link 1, link 2) y Linux man (link) no agregan ninguna claridad.macro RAND_MAX: ¿firmado o sin firmar?

Uno pensaría que RAND_MAX debería ser un , ya que eso es lo que rand() devuelve.

Sin embargo, he encontrado que algunos compiladores lo definen como sin signo:

  • La antigua Turbo C++ 1.01: #define RAND_MAX 0x7FFFU
  • El no tan antigua C++ Builder 5.5: #define RAND_MAX 0x7FFFU
  • El sigue vivo abierto Watcom C/C++ 1.9: #define RAND_MAX 32767U
  • DJGPP (gcc 3.3.4 para DOS): #define RAND_MAX 2147483647
  • MinGW (4.6.2 gcc para Windows): #define RAND_MAX 0x7FFF
  • MS Visual Studio 2010 (link): RAND_MAX se define como el valor 0x7FFF
  • compilador C Tiny 0.9.25: # definir RAND_MAX 0x7FFF
  • lcc-win32 3,8: #define RAND_MAX 0x7FFF
  • Pelles C 6,50: #define RAND_MAX 0x3FFFFFFF O #define RAND_MAX 0x7FFF
  • digital Marte C/C++ 8.52: #define RAND_MAX 32767

Esto hace que el código aparentemente inocuo como el no portátil a continuación convertido y volar debido al firmado con la promoción sin firmar:

cos(w * t) + (rand() - RAND_MAX/2) * 0.1/(RAND_MAX/2); 

rand() devuelve un signed int en el rango [0, RAND_MAX].

Si RAND_MAX se define como un unsigned int, el valor de rand() es ascendido a unsigned int también.

Y si ese es el caso, la diferencia (rand() - RAND_MAX/2) se convierte en una diferencia sin signo de enteros sin signo con el valor en los rangos de [0, RAND_MAX - RAND_MAX/2] & [UINT_MAX + 1- RAND_MAX/2, UINT_MAX -1] en lugar de ser una diferencia firmada de enteros con signo con el valor en el rango [- RAND_MAX/2, RAND_MAX - RAND_MAX/2].

De todos modos, parece que RAND_MAX debe estar firmado y la mayoría de los compiladores (?) Lo definen como tal, pero ¿hay alguna fuente autorizada que diga que debe estar firmado? Mayor estándar? K & R? ¿Otra especificación de UNIX?

+0

El libro _Standard C_ por Plaguer y Brodie (1989) en el estándar ANSI/ISO dice 'RAND_MAX' es' '. El lenguaje de programación de K & R _ (2nd-Ed 1988) solo lo menciona en relación con la función 'int rand()' que dice que este último devuelve un valor en el rango '0' a' RAND_MAX'. Sonidos firmados para mí. – martineau

+0

@martineau Me suena inesperado. 'entero 'no significa' int' exclusivamente, 'unsigned' es como' integer' como 'int'. –

+0

Un 'int' no calificado es equivalente a un' signed' o 'signed int', por lo que sería razonable asociar las mismas reglas a todos los usos de la palabra" integer "en la especificación del lenguaje. Además de eso, el hecho es que el único propósito de 'RAND_MAX' era tener algo con lo que describir los límites de los valores devueltos por la función' int rand() 'solo refuerza aún más esa suposición. es decir, ¿por qué '# define' algo para ser una cantidad' unsigned' que solo se usaría para especificar el rango de posibles valores de retorno de una función de biblioteca que devolvió una cantidad 'signed '? – martineau

Respuesta

3

La respuesta es: que el código está haciendo una suposición injustificada, por lo que necesita ser arreglado. Lo que ese código debería haber hecho es emitir RAND_MAX a (int) en el uso.

Si bien los compiladores tendrían más sentido definir sus macros RAND_MAX como firmadas, la norma evita cuidadosamente que se les solicite hacerlo. Eso hace que sea un error de portabilidad para cualquier código asumir ciegamente que se firmará.

+0

Dado que nadie hasta ahora ha encontrado una respuesta autorizada a la pregunta principal "¿firmado o no firmado?" y ha habido suficiente tiempo y realmente parece un defecto en el estándar, creo que la pregunta ahora puede cerrarse. Debido a que las otras respuestas expresan suposiciones adicionales, que considero irrazonables, elijo su respuesta. –

+0

No estoy de acuerdo en que sea una "suposición injustificada". Vea mi comentario bajo la pregunta. – martineau

7

Sí, esto parece un defecto en el estándar.

En primer lugar, hoy en día probablemente nadie definiría rand() para devolver un int. La intención es claramente devolver un número positivo y no hay retorno de error que podría usar los retornos negativos. Dicha función, si se introdujera hoy, se diseñará con un tipo de entero sin signo como tipo de retorno. Supongo que es anterior a C89 y la introducción del concepto de enteros sin signo al lenguaje.

Entonces, claramente hay que esperar que una definición del valor máximo que devuelve una función tiene el mismo tipo que el de la función. En otros lugares, las macros están bien definidas como expandir a expresiones con un cierto tipo, así que esto también habría sido posible aquí.

En cuanto a su problema, creo que lo más fácil de tener algo portátil es escalar el valor primero a un doble en [0, 1) haciendo algo como rand()/(RAND_MAX+1.0) y derivar todos sus cálculos desde allí. En cualquier caso, debe usar rand() solo como último recurso si su plataforma no tiene un generador pseudoaleatorio mejor disponible. Por ejemplo, en sistemas POSIX, la familia rand48 es un reemplazo conveniente con propiedades bien descritas.

+1

No creo que vuelva 'unsigned' si se diseñó hoy. Hacerlo conduciría a una promoción innecesaria y generalmente dañina para 'unsigned', en la forma exacta que OP está describiendo. –

+3

@R .. opinión contra opinión: creo que sí, y 'RAND_MAX' sería el valor máximo de ese tipo de devolución sin firmar. No hay ninguna razón para desperdiciar un poco el signo aquí y no tener "números" aleatorios que comprendan fácilmente a los vectores de bits aleatorios más amplios. –

Cuestiones relacionadas