在 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 测试。这对于内部循环来说是最佳的,因为它尽可能地减少了名义上的工作量,尽管现实世界的硬件有时会有一些挑剔的行为,这可能会导致更多的计算时间来减少实际工作。 引入了新的标识符blocklimit,但可以进行更改以避免与原始代码中的用途发生任何冲突。 除上述内容外,内部循环的运行方式与原始代码相同:它以与原始代码相同的顺序看到 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 &lt; NumberOfWholeBlocks; ++block),为内部循环执行for (int i = block*x; i &lt; (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 次迭代的主要内容,如果未能解决你的问题,请参考以下文章

python中的if循环怎么样?

VBA - 如何有条件地跳过for循环迭代

L6-2 嵌套循环

如何在 R 中迭代地产生组合? [复制]

如何强制结束 for 循环的迭代(不停止 for 循环)?

python为啥for循环只查到一次数据