C++ 打印进度,对运行时的影响最小
C++ print progress with minimal impact on runtime
我有一个带有长 运行 循环的 C++ 程序。它有大约 500000 次迭代。
我想每 5% 打印一次进度。
目前我所拥有的如下。
问题是它会一遍又一遍地写同一行(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();
}
}
编辑:
感谢您的回答。我选择了 christophes',它的指令数量最少。
它节省了 25% 的运行时间,非常重要!
怎么样:
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();
不用每次都计算百分比,你可以算出总数的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);
}
}
}
在我的机器上,对于足够大的总值,第二个要快得多。当我将所有内容更改为 unsigned long longs 并将总数设置为 50 亿时,第二个用了 9.336 秒,第一个用了 40.159 秒
考虑到 totalWindows
似乎保持不变,并且 integer
increments/decrements 可能会比许多转换为 int 的 double
操作更快,我建议:
// 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% 执行一次在每次迭代中。
我有一个带有长 运行 循环的 C++ 程序。它有大约 500000 次迭代。 我想每 5% 打印一次进度。
目前我所拥有的如下。 问题是它会一遍又一遍地写同一行(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();
}
}
编辑: 感谢您的回答。我选择了 christophes',它的指令数量最少。 它节省了 25% 的运行时间,非常重要!
怎么样:
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();
不用每次都计算百分比,你可以算出总数的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);
}
}
}
在我的机器上,对于足够大的总值,第二个要快得多。当我将所有内容更改为 unsigned long longs 并将总数设置为 50 亿时,第二个用了 9.336 秒,第一个用了 40.159 秒
考虑到 totalWindows
似乎保持不变,并且 integer
increments/decrements 可能会比许多转换为 int 的 double
操作更快,我建议:
// 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% 执行一次在每次迭代中。