c - que - ¿Es legal usar memset(, 0,) en una matriz de dobles?
para que se utiliza memset en c (7)
¿Es legal cero array de dobles (usando memset (, 0,)) o struct que contiene dobles?
La pregunta implica dos cosas diferentes:
(1) Desde el punto de vista del estándar C, ¿es este UB de no? (En una plataforma fija, ¿cómo puede este UB ... solo depende de la representación flotante, eso es todo ...)
(2) Desde el punto de vista práctico: ¿está bien en la plataforma Intel? (no importa qué estándar está diciendo).
Aunque es poco probable que encuentre una máquina donde esto tenga problemas, también puede evitar esto de forma relativamente fácil si realmente está hablando de matrices como indica en el título de la pregunta, y si estas matrices son de longitud conocida en el momento de la compilación ( no es VLA), entonces simplemente inicializarlos es probablemente aún más conveniente:
double A[133] = { 0 };
siempre debería funcionar Si tuviera que volver a cero una matriz de este tipo, más adelante, y su compilador cumple con la C (C99) moderna, puede hacerlo con un literal compuesto.
memcpy(A, (double const[133]){ 0 }, 133*sizeof(double));
en cualquier compilador moderno esto debería ser tan eficiente como memset
, pero tiene la ventaja de no depender de una codificación particular de double
.
Bueno, creo que la puesta a cero es "legal" (después de todo, está poniendo a cero un buffer regular), pero no tengo idea si el estándar le permite asumir algo sobre el valor lógico resultante. Supongo que el estándar C lo deja como indefinido.
Como dice Matteo Italia, eso es legal de acuerdo con el estándar, pero yo no lo usaría. Algo como
double *p = V, *last = V + N; // N - count
while(p != last) *(p++) = 0;
es al menos dos veces más rápido.
David Heffernan ha dado una buena respuesta para la parte (2) de su pregunta. Para la parte (1):
El estándar C99 no garantiza la representación de los valores de coma flotante en el caso general. §6.2.6.1 dice:
Las representaciones de todos los tipos no están especificadas excepto como se indica en esta subcláusula.
... y esa subcláusula no menciona más el punto flotante.
Tu dijiste:
(En una plataforma fija, ¿cómo puede este UB ... solo depende de la representación flotante, eso es todo ...)
De hecho, existe una diferencia entre "comportamiento indefinido ", "comportamiento no especificado " y "comportamiento definido por la implementación ":
- "comportamiento indefinido " significa que cualquier cosa podría suceder (incluido un bloqueo en tiempo de ejecución);
- "comportamiento no especificado " significa que el compilador es libre de implementar algo sensato de la manera que quiera, pero no es necesario documentar la elección de la implementación;
- "comportamiento definido por la implementación " significa que el compilador es libre de implementar algo sensato de la manera que quiera, y se supone que debe documentar esa elección (por ejemplo, consulte here las opciones de implementación documentadas en la versión más reciente de GCC );
y así, como la representación de coma flotante es un comportamiento no especificado , puede variar de forma indocumentada de una plataforma a otra (donde "plataforma" aquí significa "la combinación de hardware y compilador" en lugar de solo "hardware").
(No estoy seguro de cuán útil es la garantía de que un double
esté representado de modo que todos los bits cero sea +0.0
si se define __STDC_IEC_559__
, como se describe en la respuesta de Matteo Italia, en la práctica. Por ejemplo, GCC nunca define esto , a pesar de que usa IEEE 754 / IEC 60559 en muchas plataformas de hardware).
El anexo F estándar C99 dice:
Este anexo especifica el soporte de lenguaje C para el estándar de punto flotante IEC 60559. El estándar de punto flotante IEC 60559 es específicamente aritmética de punto flotante binario para sistemas de microprocesador, segunda edición (IEC 60559: 1989) , previamente designada IEC 559: 1989 y como estándar IEEE para aritmética de punto flotante binario (ANSI / IEEE 754-1985 ) El estándar IEEE para la aritmética de punto flotante independiente de la base (ANSI / IEEE 854-1987) generaliza el estándar binario para eliminar dependencias en la longitud de la raíz y de la palabra. IEC 60559 generalmente se refiere al estándar de coma flotante, como en la operación IEC 60559, el formato IEC 60559, etc. Una implementación que define
__STDC_IEC_559__
debe cumplir con las especificaciones de este anexo. Cuando se indique una unión entre el lenguaje C e IEC 60559, el comportamiento especificado por IEC 60559 se adoptará por referencia, a menos que se indique lo contrario.
Y, inmediatamente después,
Los tipos flotantes C coinciden con los formatos IEC 60559 de la siguiente manera:
- El tipo de letra
float
coincide con el formato único IEC 60559.- El tipo
double
coincide con el doble formato IEC 60559.
Entonces, si IEC 60559 es básicamente IEEE 754-1985 y esto especifica que 8 bytes cero significan 0.0 (como dijo @David Heffernan), esto significa que si encuentra __STDC_IEC_559__
definido, puede hacer una inicialización 0.0 con memset
.
Es "legal" usar memset. El problema es si produce un patrón de bits donde array [x] == 0.0 es verdadero. Si bien el estándar básico C no requiere que eso sea cierto, ¡me interesaría escuchar ejemplos donde no lo es!
Parece que memset es equivalente a 0.0 en IBM-AIX, HP-UX (PARISC), HP-UX (IA-64), Linux (IA-64, creo).
{
double dFloat1 = 0.0;
double dFloat2 = 111111.1111111;
memset(&dFloat2, 0, sizeof(dFloat2));
if(dFloat1 == dFloat2)
{
fprintf(stdout, "memset appears to be equivalent to = 0.0/n");
}
else
{
fprintf(stdout, "memset is NOT equivalent to = 0.0/n");
}
}
Si está hablando de IEEE754, el estándar define +0.0 a la precisión doble como 8 bytes cero. Si sabe que está respaldado por el punto flotante IEEE754, entonces esto está bien definido.
En cuanto a Intel, no puedo pensar en un compilador que no use IEEE754 en Intel x86 / x64.