Solución:
Sus intentos de optimizar el bucle mediante el uso de alguna construcción (incluido cortar y pegar manualmente el código) para optimizar la velocidad de ejecución del bucle son desaconsejados. No lo hagas; en su lugar, probablemente “des-optimizara” la velocidad de ejecución.
En cualquier implementación de C ++ que haya encontrado (MSVC 6.0, 2003, 2005, 2010, varias versiones de GCC, varias versiones de Diab), hay absolutamente cero, lo siento, no enfaticé lo suficiente, CERO, tiempo involucrado con la asignación de un bucle variable de recuento, asumiendo que se asignaron otras variables para la función en la que se asigna la variable de recuento de bucle. Para un bucle simple que no realiza llamadas a funciones, es posible que la variable de conteo de bucles nunca llegue a la memoria; puede mantenerse en su totalidad en un solo registro de CPU durante toda su vida útil. Incluso si está almacenado en la memoria, estaría en la pila de tiempo de ejecución, y el espacio para él (y cualquier otra variable local) se reclamaría de una vez en una sola operación, lo que no toma más o menos tiempo dependiendo del número de variables asignadas en la pila. Las variables locales como su variable de contador de bucle se asignan en la pila, y las asignaciones de pila son BARATAS BARATAS BARATAS, a diferencia de las asignaciones de pila.
Ejemplo de asignación de variables de contador de bucles en la pila:
for (int i=0; i<50; ++i) {
....
}
Otro ejemplo de asignación de variables de contador de bucles en la pila:
int i = 0;
for (; i<50; ++i) {
....
}
Ejemplo de variable de contador de bucle asignada en el montón (no hagas esto; es estúpido):
int* ip = new int;
for (*ip=0; *ip<50; ++(*ip)) {
....
}
delete ip;
Ahora, para abordar el problema de intentar optimizar su bucle copiando y pegando manualmente en lugar de usar un bucle y un contador:
Lo que está considerando hacer es una forma manual de desenrollado de bucle. El desenrollado de bucle es una optimización que los compiladores utilizan a veces para reducir la sobrecarga involucrada en un bucle. Los compiladores pueden hacerlo solo si se puede conocer el número de iteraciones del ciclo en el momento de la compilación (es decir, el número de iteraciones es una constante, incluso si la constante implica un cálculo basado en otras constantes). En algunos casos, el compilador puede determinar que vale la pena desenrollar el ciclo, pero a menudo no lo desenrollará por completo. Por ejemplo, en su ejemplo, el compilador puede determinar que sería una ventaja de velocidad desenrollar el ciclo de 50 iteraciones a solo 10 iteraciones con 5 copias del cuerpo del ciclo. La variable de ciclo todavía estaría allí, pero en lugar de hacer 50 comparaciones del contador de ciclo, ahora el código solo tiene que hacer la comparación 10 veces. Es una compensación, porque las 5 copias del cuerpo del bucle consumen 5 veces más espacio en la caché, lo que significa que cargar esas copias adicionales de las mismas instrucciones obliga a la caché a desalojar (tirar) muchas instrucciones que ya están en la caché y que quizás quisiera que permaneciera en la caché. Además, cargar esas 4 copias adicionales de las instrucciones del cuerpo del bucle desde la memoria principal lleva mucho, mucho más tiempo que simplemente tomar las instrucciones ya cargadas del caché en el caso de que el bucle no se desenrolle en absoluto.
Entonces, en general, a menudo es más ventajoso usar solo una copia del cuerpo del bucle y seguir adelante y dejar la lógica del bucle en su lugar. (Es decir, no se desenrolla ningún bucle).
Sería completamente posible tener un repeat(x)
como parte del lenguaje, pero no existe tal cosa por alguna razón: el diseño de C y C ++ sigue en cierto modo lo que pueden hacer los procesadores, y no estoy familiarizado con un solo procesador (he trabajado con aproximadamente 10 arquitecturas de procesador diferentes) que pueden hacer un “bucle tantas veces” sin algún tipo de “comprobar si alcanzamos el número”.
Entonces, tendrá que escribir un código que verifique cuántas veces ha repetido algo (o cuántas veces queda por hacer; hay una instrucción x86 llamada “bucle” que hace exactamente eso, cuenta regresiva y si el contador no es cero, salte al comienzo del ciclo).
Si el compilador desea entonces “desenrollar” un bucle porque tiene un número constante de iteraciones, y decide “desenrollar esto es más rápido” [compilers decide these sort of things all the time, and often get it right], entonces el compilador puede hacerlo. Pero todavía tienes que escribir código que “compruebe”.