Estoy escribiendo un programa en el que cierto ciclo for se repite muchas veces.

Una sola iteración no lleva mucho tiempo, pero dado que el programa itera el ciclo con tanta frecuencia, lleva bastante tiempo calcularlo.

En un esfuerzo por obtener más información sobre el progreso del programa sin ralentizarlo demasiado, me gustaría imprimir el progreso cada x paso.

¿Hay una manera diferente de hacer esto, que un condicional con un módulo como este:

for(int i = 0; i < some_large_number; i++){
    if(i % x == 0)
        printf("%f%%\r", percent);
    //some other code
    .
    .
    .
}

?

Gracias es avance

4
lookatdatcake 29 abr. 2020 a las 15:54

4 respuestas

La mejor respuesta

Este código:

for(int i = 0; i < some_large_number; i++){
    if(i % x == 0)
        printf("%f%%\r", percent);
    //some other code
    .
    .
    .
}

Se puede reestructurar como:

/*  Partition the execution into blocks of x iterations, possibly including a
    final fragmentary block.  The expression (some_large_number+(x-1))/x
    calculates some_large_number/x with any fraction rounded up.
*/
for (int block = 0, i = 0; block < (some_large_number+(x-1))/x; ++block)
{
    printf("%f%%\r", percent);

    //  Set limit to the lesser of the end of the current block or some_large_number.
    int limit = (block+1) * x;
    if (some_large_number < limit) limit = some_large_number;

    //  Iterate the original code.
    for (; i < limit; ++i)
    {
        //some other code
    }
}

Con las siguientes advertencias y propiedades:

  • El bucle interno no tiene más trabajo que el bucle original (no tiene variables adicionales para contar o probar) y tiene la prueba i % x == 0 completamente eliminada. Esto es óptimo para el bucle interno en el sentido de que reduce la cantidad nominal de trabajo tanto como sea posible, aunque el hardware del mundo real a veces tiene comportamientos delicados que pueden resultar en más tiempo de cómputo por menos trabajo real.
  • Se introducen nuevos identificadores block y limit, pero se pueden cambiar para evitar conflictos con los usos en el código original.
  • Aparte de lo anterior, el bucle interno opera de manera idéntica al código original: ve los mismos valores de i en el mismo orden que el código original, por lo que no se necesitan cambios en ese código.
  • some_large_number+(x-1) podría desbordarse int.
2
Eric Postpischil 29 abr. 2020 a las 14:18

Lo haría así:

int j = x;
for (int i = 0; i < some_large_number; i++){
    if(--j == 0) {
        printf("%f%%\r", percent);
        j = x;
    }
    //some other code
    .
    .
    .
}
1
Pierre François 29 abr. 2020 a las 13:03

Divida el some_large_number entre x. Ahora repita x veces y anídelo con el nuevo entero y luego imprima el porcentaje. Quise decir esto:

int temp = some_large_number/x;
for (int i = 0; i < x; i++){
   for (int j = 0; j < temp; j++){
        //some code
   }
   printf("%f%%\r", percent);
}
2
Rithik Banerjee 29 abr. 2020 a las 13:32

El enfoque más rápido con respecto a su preocupación por el rendimiento sería utilizar un bucle anidado:

unsigned int x = 6;
unsigned int segments = some_large_number / x; 
unsigned int y;

for ( unsigned int i = 0; i < segments; i++ ) {

    printf("%f%%\r", percent); 

    for ( unsigned int j = 0; j < x; j++ ) {

       /* some code here */

    }
}


// If some_large_number can´t be divided evenly through `x`:

if (( y = (some_large_number % x)) != 0 )
{
    for ( unsigned int i = 0; i < y; i++ ) {

       /* same code as inside of the former inner loop. */

    }
}

Otro ejemplo sería usar una variable de conteo diferente para la verificación para ejecutar el proceso de impresión comparándolo con x - 1 y restablecer la variable a -1 si coincide:

unsigned int x = 6;
unsigned int some_large_number = 100000000;

for ( unsigned int i = 0, int j = 0; i < some_large_number; i++, j++ ) {

    if(j == (x - 1))
    {
        printf("%f%%\r", percent);
        j = -1;
    }
    /* some code here */
}
2
RobertS supports Monica Cellio 30 abr. 2020 a las 08:38