<< Chapter < Page | Chapter >> Page > |
Revisémoslas una por una.
El siguiente ciclo contiene una prueba invariante :
DO I=1,K
IF (N .EQ. 0) THENA(I) = A(I) + B(I) * C
ELSEA(I) = 0.
ENDIFENDDO
“Invariante” significa que el resultado siempre es el mismo. Sin importar lo que suceda con las variables
A
,
B
,
C
, e
I
, el valor de
N
no cambia, ni tampoco lo hará el resultado del resto.
Usted puede reestructurar el ciclo, poniendo la prueba fuera y replicando el cuerpo del ciclo dos veces - una para el caso de que la prueba sea verdadera, y la otra para el resultado falso, como en el ejemplo siguiente:
IF (N .EQ. 0) THEN
DO I=1,KA(I) = A(I) + B(I) * C
ENDDOELSE
DO I=1,KA(I) = 0
ENDDOENDIF
El efecto en el tiempo de ejecución es dramático. No sólo hemos eliminado
K-1
copias de la prueba, también hemos asegurado que los cálculos en el centro del ciclo no tengan dependencias de control sobre la sentencia selectiva, y por tanto es mucho más fácil que el compilador lo ponga en una fila de espera.
Recordamos haber ayudado a alguien a optimizar un programa con ciclos que contenían condicionales similares. Comprobaban si debía imprimirse la salida del depurador adentro de cada iteración, o bien producir un ciclo altamente optimizable. No podemos culpar a la persona por no observar cuánto reducía esto la velocidad del programa. El rendimiento no era importante en ese momento. El programador sólo trataba de lograr que el código produjera respuestas correctas. Pero después, cuando comenzó a importar el rendimiento, limpiando condicionales invariantes fuimos capaces de acelerar el programa en un factor de 100.
Para los condicionales
dependientes del índice del ciclo , la prueba es verdadera sólo para ciertos rangos de las variables usadas como índice del ciclo. Y no siempre es cierto o falso, como en otros condicionales que ya revisamos, pero cambia de acuerdo a un patrón apreciable, uno que puede usarse a nuestro favor. El siguiente ciclo tiene dos variables índice,
I
y
J
.
DO I=1,N
DO J=1,NIF (J .LT. I)
A(J,I) = A(J,I) + B(J,I) * CELSE
A(J,I) = 0.0ENDIF
ENDDOENDDO
Observe cómo la sentencia selectiva divide las iteraciones en dos conjuntos distintos: aquéllas en las cuáles es verdadero y aquéllas en las que es falso. Puede usted tomar ventaja de que tal cosa sea predecible, para reestructurar el bucle en varios bucles - cada uno personalizado para una partición distinta:
DO I=1,N
DO J=1,I-1A(J,I) = A(J,I) + B(J,I) * C
ENDDODO J=I,N
A(J,I) = 0.0ENDDO
ENDDO
La nueva versión resultará más rápida casi siempre, con la posible excepción del caso en que
N
tenga un valor pequeño, como 3, en cuyo caso hemos creado un mayor desorden. Pero aun en tal caso, el ciclo probablemente tendrá un impacto pequeño en el tiempo total de ejecución, del que hubiera tenido si se dejaba tal como está codificado.
Sería bueno que pudiera optimizar cada ciclo, particionándolo. Pero muy a menudo, el condicional no depende directamente del valor de las variables índice. Aunque una variable índice esté involucrada en el direccionamiento de un arreglo, no crea por adelantado un patrón reconocible - por lo menos no uno que pueda usted observar cuando está escribiendo el programa. He aquí uno de tales ciclos:
Notification Switch
Would you like to follow the 'Cómputo de alto rendimiento' conversation and receive update notifications?