2015-08-12 7 views
4

У меня есть программа на C++ с длинным ходом. Он имеет около 500000 итераций. Я хотел бы распечатать прогресс каждые 5%.Успех печати C++ с минимальным воздействием на время выполнения

Что я до сих пор ниже. Проблема заключается в том, что он будет продолжать писать одну и ту же строку (0%,% 5 и т. Д.) Снова и снова. Это связано с тем, что после усечения процента в целое число есть 1000 итераций, которые будут поражены кратным 5. Это делает программу заметно медленнее.

С другой стороны, если я не укоротить до целого числа, то результат percent % 5.0 вряд ли будут точно 0.

Как я могу напечатать индикатор прогресса с минимально возможным влиянием на время выполнения?

// Counters for progress indicator 
int i = 0; 
float totalWindows = (float)(win.nX * win.nY); 
int percent; 

while (win.next() == 0) 
{ 
    // Read the data 

    // Nicely formatted progress indicator 
    i++; 
    percent = (i/totalWindows) * 100; 
    if (percent % 5 == 0) 
    { 
     std::cout << "\r" << std::string(percent/5, '|') << percent << "%"; 
     std::cout.flush(); 
    } 



} 

EDIT: Спасибо за ответы. Я отправился с христианами, которые пришли к наименьшему количеству инструкций. Он побрил 25% времени выполнения, поэтому довольно значителен!

ответ

2

Учитывая, что totalWindows, кажется, остается неизменным, и integer приращения/декремент, вероятно, будет быстрее, чем многие из double операций с преобразованием в INT, я предлагаю:

// Counters for progress indicator 
int i = 0; 
float totalWindows = (float)(win.nX * win.nY); 
int increment5 = 0.05 * totalWindows; // how many iterations does 5% represent ? 
int countdown = increment5; // decrement countdown instead of modulo 
int percent5 = 0; // number of elements in the progress bar (1 means 5%) 

while (win.next() == 0) 
{ 
    // Read the data 

    // Nicely formatted progress indicator 
    i++; 
    if (--countdown == 0) 
    { 
      percent5++; 
      std::cout << "\r" << std::string(percent5, '|') << percent5*5 << "%"; 
      countdown = increment5; 
      std::cout.flush(); 
    } 

} 

Если вы боитесь, что кумулятивные закругления не были бы приемлемыми для отображения прогресса, вы всегда можете выбрать, чтобы вычислить точное значение в if -блоке: расчет будет выполняться только один раз каждые 5% вместо каждой итерации.

+0

totalWindows остается без изменений, да. Умное решение, мне нравится использование обратного отсчета – jramm

+1

@ Christophe - Я думаю, что в вашем коде есть небольшая проблема.'Cout' использует конструктор заполнения строки, используя переменную' percent', которая не является частью вашего кода. Может быть, вы хотите вместо этого 'percent5 * 5'. – 4386427

+0

@StillLearning точное! Спасибо, я отредактировал ответ :-). Кстати, чтобы избежать alloc/dealloc временной строки, можно было бы рассмотреть возможность создания строковой переменной вне цикла, зарезервировать достаточную емкость для нее, и каждое взаимодействие добавит '|' в конце строки. Но это улучшение было бы незначительным, так как этот код выполняется только 20 раз. – Christophe

1

Как насчет:

int step = 5; 
int nextPrint = step; 

while (win.next() == 0) 
{ 
    // Read the data 

    // Nicely formatted progress indicator 
    i++; 
    percent = (100 * i)/totalWindows; 
    if (percent >= nextPrint) 
    { 
     std::cout << "\r" << std::string(percent/5, '|') << percent << "%"; 
     std::cout.flush(); 
     nextPrint += step; 
    } 
} 

КСТАТИ: Почему у вас totalWindows как поплавок? Это также ущемляет производительность. Если число итераций составляет 500000, должно быть достаточно 32 бита int.

Другой и лучший подход, потому что процент не рассчитывается в каждом цикле:

const int percentPrint = 5; 
int step = totalWindows/(100/percentPrint); 
int nextPrint = step; 

while (win.next() == 0) 
{ 
    // Read the data 

    // Nicely formatted progress indicator 
    i++; 
    if (i >= nextPrint) 
    { 
     percent = (100 * i)/totalWindows; 
     std::cout << "\r" << std::string(percent/percentPrint , '|') << percent << "%"; 
     std::cout.flush(); 
     nextPrint += step; 
    } 
} 
std::cout << "\r" << std::string(100/percentPrint , '|') << percent << "%"; 
std::cout.flush(); 
+0

Да, это хорошо, гораздо лучший подход, чем мой, оставаясь таким же ясным и простым – jramm

0

Вместо вычисления процента каждый раз, вы можете рассчитывать, что 5% от общего числа и использовать его это непосредственно.

Рассмотрим упрощенный пример:

int main(int argc, char * argv) { 
    int total = 50000; 
    int total_percent_stop = total * 5/100; //Set the percentage here. 

    for (int i = 0; i < total; i++) { 
    if (i % total_percent_stop == 0) { 
     printf("%d percent done\n", (i/total_percent_stop) * 5); 
    } 
    } 
} 

Если производительность данного конкретного кода очень важно для вас, вы можете избежать относительно дорогих операций деления, делая что-то вроде этого (за счет некоторой дискретностью) ,

int main(int argc, char * argv) { 
    int total = 50000; 
    int total_percent_stop = total * 5/100; //Set the percentage here 

    for (int i = 0, percent_counter = 0, n_percent = 0; 
     i < total; 
     i++, percent_counter++) { 
    if (percent_counter == total_percent_stop) { 
     percent_counter = 0; 
     n_percent++; 
     printf("%d percent done\n", n_percent * 5); 
    } 
    } 
} 

На моей машине при достаточно больших значениях сумма вторая значительно быстрее. Когда я изменил все, чтобы беззнаковых длинных долгот и установить общее количество до 5 миллиардов, то второй занял 9.336 секунд, и первый взял 40.159 секунды

 Смежные вопросы

  • Нет связанных вопросов^_^