FORTRAN de estilo antiguo requería que un programador que quisiera poner a disposición de una función parte de una matriz necesitaba pasar una referencia a toda la matriz, junto con uno o más valores enteros que especificaran el subíndice inicial y el subíndice final o el número de elementos . C hace posible simplificar esto al pasar un puntero al inicio de la parte de interés junto con el número de elementos. En términos directos, esto aceleraría las cosas (pasar dos cosas en lugar de tres). Sin embargo, indirectamente, puede terminar ralentizando las cosas al limitar los tipos de optimización que puede realizar un compilador.
Considere la función:
void diff(float dest[], float src1[], float src2[], int n)
{
for (int i=0; i<n; i++)
dest[i] = src1[i] - src2[i];
}
Si un compilador supiera que cada uno de los punteros identificaría el inicio de una matriz, podría generar código que actuaría sobre los elementos de la matriz en paralelo, o en cualquier orden, ya que para cualquier operación x! = y, en dest [x ] no afectará a src1 [y] ni a src2 [y]. Por ejemplo, en algunos sistemas un compilador puede beneficiarse de generar código equivalente a:
void dif(float dest[], float src1[], float src2[], int n)
{
int i=0;
float t1a,t1b,t2a,t2b,tsa,tsb;
if (n > 2)
{
n-=4;
t1a = src1[n+3]; t1b = src2[n+3]; t1b=src2[n+2]; t2b = src2[n+2];
do
{
tsa = t1a-t2a;
t1a = src1[n+1]; t2a = src2[n+1];
tsb = t2b-t2b;
dest[n+3] = tsa;
t1b = src1[n]; t2b = src2[n];
n-=2;
dest[n+4] = tsb;
} while(n >= 0);
... add some extra code to handle cleanup
}
else
... add some extra code to handle small values of n
}
Tenga en cuenta que cada operación que carga o calcula un valor tiene al menos una operación más entre él y la siguiente operación que usa ese valor. Algunos procesadores pueden superponer el procesamiento de diferentes operaciones cuando se cumplen tales condiciones, mejorando así el rendimiento. Sin embargo, tenga en cuenta que debido a que un compilador de C no tiene forma de saber que el código no se pasará a punteros a regiones parcialmente superpuestas de una matriz común, un compilador de C no puede realizar la transformación anterior. Los compiladores de FORTRAN a los que se les dio un código equivalente, sin embargo, pudieron hacer una transformación.
Si bien un programador en C podría intentar lograr un rendimiento comparable escribiendo explícitamente el código que desenrollaba el ciclo y superponía las operaciones de los pases adyacentes, dicho código podría degradar fácilmente el rendimiento si utilizara tantas variables automáticas que un compilador tuvo que "derramarlas" memoria. El optimizador de un compilador FORTRAN probablemente sabría más que un programador acerca de qué formas de entrelazado producirían un rendimiento óptimo en un escenario dado, y esas decisiones a menudo son mejores para esos compiladores. Si bien C99 intentó mejorar la situación de C agregando un restrict
calificador, eso solo se podría usar aquí si dest[]
fuera una matriz separada de ambos src1[]
y src2[]
, o si el programador agregó versiones separadas del bucle para manejar los casos en los que todo dest
era disjunto desrc1
y src2
, dónde src1[]
y dest
eran iguales y src2
eran disjuntos, dónde src2[]
y dest[]
eran iguales y src1
eran disjuntos, y dónde las tres matrices eran iguales. FORTRAN, por el contrario, podría manejar los cuatro casos sin dificultad utilizando el mismo código fuente y el mismo código de máquina.