在 for 循环中有效地打印每 x 次迭代
Posted
技术标签:
【中文标题】在 for 循环中有效地打印每 x 次迭代【英文标题】:Efficiently print every x iterations in for loop 【发布时间】:2020-04-29 12:54:59 【问题描述】:我正在编写一个程序,其中某个 for 循环被多次迭代。
单次迭代不需要很长时间,但由于程序迭代循环如此频繁,因此需要相当长的时间来计算。
为了在不减慢程序进度的情况下获得有关程序进度的更多信息,我希望每第 x 步打印一次进度。
有没有其他方法可以做到这一点,而不是像这样的模数条件:
for(int i = 0; i < some_large_number; i++)
if(i % x == 0)
printf("%f%%\r", percent);
//some other code
.
.
.
?
先谢谢了
【问题讨论】:
是性能问题吗? 如果模数是性能问题,请改用计数器。 嵌套循环更快。 当然I/O会主导性能;相比之下,模计算会很快。如果您选择 2 的幂,您还可以将最后一位的掩码与比除法更快的 0 进行比较(您的编译器甚至可以在优化时为您执行此操作)。 @Yunnosch:“做不同的事,然后衡量”是一把锤子。熟练的从业者研究处理器规格,了解系统的行为方式,并运用推理来制定潜在的解决方案,将许多部分放在一起以完成复杂的代码。人们不能指望通过反复试验来优化缓存使用的最佳阵列几何形状,就像通过将零件粉碎在一起来制造精美的机械表一样。推荐测量作为优化的主要工具对学生来说是个坏建议。最好的工具是知识。 【参考方案1】:这段代码:
for(int i = 0; i < some_large_number; i++)
if(i % x == 0)
printf("%f%%\r", percent);
//some other code
.
.
.
可以改写为:
/* 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
具有以下注意事项和属性:
内部循环没有比原始循环更多的工作(它没有额外的变量来计算或测试)并且完全删除了i % x == 0
测试。这对于内部循环来说是最佳的,因为它尽可能地减少了名义上的工作量,尽管现实世界的硬件有时会有一些挑剔的行为,这可能会导致更多的计算时间来减少实际工作。
引入了新的标识符block
和limit
,但可以进行更改以避免与原始代码中的用途发生任何冲突。
除上述内容外,内部循环的运行方式与原始代码相同:它以与原始代码相同的顺序看到 i
的相同值,因此无需更改该代码。
some_large_number+(x-1)
可能会溢出 int
。
【讨论】:
【参考方案2】:我会这样做:
int j = x;
for (int i = 0; i < some_large_number; i++)
if(--j == 0)
printf("%f%%\r", percent);
j = x;
//some other code
.
.
.
【讨论】:
从我迄今为止尝试过的解决方案来看,这似乎是最快的,当我没有减去并与 0 进行比较时,我将 x 相加,然后将变量设置回 0 这增加了另一个计数器。正如已经展示的那样,这不是必需的,因为使用嵌套循环导致大多数迭代的成本不高于原始代码,因为没有额外的变量来增加和测试。内部循环只是以“全速”运行,并且只有在它终止时,才需要为打印做一些额外的工作。【参考方案3】:将 some_large_number 除以 x。现在循环 x 次并用新整数嵌套它,然后打印百分比。我的意思是:
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);
【讨论】:
这是一个正确的做法,但细节错误。内部循环应该运行x
迭代,而不是temp
,因为它希望每x
迭代打印一次。所以外部循环应该运行temp
迭代。当x
不均分some_large_number
时,需要一些代码来处理留下的片段。此外,i
的原始值可能会在原始循环的主体中使用,在这种情况下,必须做出一些规定以使其可用。
例如,可以为外部循环执行int NumberOfWholeBlocks = some_large_number/x; for (int block = 0; block < NumberOfWholeBlocks; ++block)
,为内部循环执行for (int i = block*x; i < (block+1)*x; ++i)
。然后,在内部循环中,i
始终具有与原始代码的相应迭代中相同的值。
关键概念是 x* temp=some_large_number
你可以做 x* temp 或 temp* x 这是我们的选择【参考方案4】:
解决性能问题的最快方法是使用嵌套循环:
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. */
另一个例子是使用不同的计数变量进行检查,通过将其与x - 1
进行比较来执行打印过程,如果匹配则将变量重置为-1
:
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 */
【讨论】:
谢谢,这比@Pierre François 解决方案差了一点 @EricPostpischil 如果不完全重构循环代码,我就无法真正实现嵌套循环...... @EricPostpischil 啊,是的,抱歉,我忽略了你评论中的那部分以上是关于在 for 循环中有效地打印每 x 次迭代的主要内容,如果未能解决你的问题,请参考以下文章