达夫的设备是如何工作的?

Duff的设备是一个技巧,它可以直接在C或C++中循环展开循环,而不需要额外的代码来处理剩余的部分循环。诀窍是使用一个开关语句,其中所有的情况下只有一个标签是在中间的while循环。此外,所有案例都会在while循环结束时结束。尽管有印象,它使Duff的设备是合法的C和C++代码(但是,它在java中无效)。

null

它有什么用处?

达夫的设备有两个关键点。

  1. 首先,循环展开。通过避免检查循环是否完成以及跳回循环顶部所涉及的一些开销,我们可以获得更快的速度。当CPU执行直线代码而不是跳转时,它可以运行得更快。然而,代码大小变得更大。
  2. 第二个方面是switch语句。它允许代码第一次跳转到循环的中间。令大多数人惊讶的是,这样的事情是被允许的。嗯,这是允许的。

实例

// C program to illustrate the working of
// Duff's Device. The program copies given
// number of elements bool array src[] to
// dest[]
#include<stdio.h>
#include<string.h>
#include <stdlib.h>
// Copies size bits from src[] to dest[]
void copyBoolArray( bool src[], bool dest[],
int size)
{
// Do copy in rounds of size 8.
int rounds = size / 8;
int i = 0;
switch (size % 8)
{
case 0:
while (!(rounds == 0))
{
rounds = rounds - 1;
dest[i] = src[i];
i = i + 1;
// An important point is, the switch
// control can directly reach below labels
case 7:
dest[i] = src[i];
i = i + 1;
case 6:
dest[i] = src[i];
i = i + 1;
case 5:
dest[i] = src[i];
i = i + 1;
case 4:
dest[i] = src[i];
i = i + 1;
case 3:
dest[i] = src[i];
i = i + 1;
case 2:
dest[i] = src[i];
i = i + 1;
case 1:
dest[i] = src[i];
i = i + 1;
};
}
}
// Driver code
int main()
{
int size = 20;
bool dest[size], src[size];
// Assign some random values to src[]
int i;
for (i=0; i<size; i++)
src[i] = rand ()%2;
copyBoolArray(src, dest, size);
for (i=0; i<size ; i++)
printf ( "%d %d" , src[i], dest[i]);
}


输出:

1    1
0    0
1    1
1    1
1    1
1    1
0    0
0    0
1    1
1    1
0    0
1    1
0    0
1    1
1    1
0    0
0    0
0    0
0    0
1       1

上述计划是如何运作的? 在上面的示例中,我们处理20个字节,并将这20个随机位从src数组复制到目标数组。它将运行的过程数也取决于源阵列的大小。

对于第一个过程,执行从计算出的case标签开始,然后进入每个连续的赋值语句,就像任何其他switch语句一样。在最后一个case标签之后,执行到达循环的底部,然后跳回到顶部。循环的顶部在switch语句中,因此不再重新计算开关。

原始循环被展开八次,因此迭代次数除以八。如果要复制的字节数不是8的倍数,那么还有一些字节剩余。大多数一次复制字节块的算法将在最后处理剩余字节,但达夫的设备在开始时处理它们。该函数计算switch语句的count%8,以计算剩余的字节数,跳转到大小写标签中的字节数,并复制它们。然后,循环继续在左边的过程中复制八个字节的组。

Flow Chart

第一关:

rounds = count / 8;

// rounds = 2 for count =20
i = 0;
switch(count % 8)
{

// The remainder is 4 (20 modulo 8)
// so jump to the case 4
case 0:
    while( !(rounds == 0) )
    {
        //[skipped]
        rounds = rounds - 1;
        dest[i] = src[i];
        i = i + 1;

    case 7:
        dest[i] = src[i];
        i = i + 1;     //[skipped]
    case 6:
        dest[i] = src[i];
        i = i + 1;     //[skipped]
    case 5:
        dest[i] = src[i];
        i = i + 1;     //[skipped]

    case 4:
        dest[i] = src[i];
        i = i + 1;     //Start here. Copy 1 byte (total 1)
    case 3:
        dest[i] = src[i];
        i = i + 1;     //Copy 1 byte (total 2)
    case 2:
        dest[i] = src[i];
        i = i + 1;     //Copy 1 byte (total 3)
    case 1:
        dest[i] = src[i];
        i = i + 1;     //Copy 1 byte (total 4)
    };
}

第二关:

rounds = count / 8;
i = 0;
switch(count % 8)
{
case 0:
    while( !(rounds == 0) )
    {
        // rounds is decremented by 1 as while
        // loop works, now rounds=1
        rounds = rounds - 1;
        dest[i] = src[i];
        i = i + 1;     // Copy 1 byte (total 5)
    case 7:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 6)
    case 6:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 7)
    case 5:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 8)
    case 4:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 9)
    case 3:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 10)
    case 2:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 11)
    case 1:
        dest[i] = src[i];
        i = i + 1; // Copy 1 byte (total 12)
    }
}

第三关:

rounds = count / 8;
i = 0;
switch(count % 8)
{
case 0:
    while( !(rounds == 0) )
    {
        //now while loop works
        rounds = rounds - 1;    //rounds is decremented by 1, now rounds=0
        dest[i] = src[i];
        i = i + 1;         // Copy 1 byte (total 13)

    case 7:
        dest[i] = src[i];
        i = i + 1;    // Copy 1 byte (total 14)
    case 6:
        dest[i] = src[i];
        i = i + 1;    // Copy 1 byte (total 15)
    case 5:
        dest[i] = src[i];
        i = i + 1;    // Copy 1 byte (total 16)
    case 4:
        dest[i] = src[i];
        i = i + 1;    // Copy 1 byte (total 17)
    case 3:
        dest[i] = src[i];
        i = i + 1;     // Copy 1 byte (total 18)
    case 2:
        dest[i] = src[i];
        i = i + 1;     // Copy 1 byte (total 19)
    case 1:
        dest[i] = src[i];
        i = i + 1;     // Copy 1 byte (total 20)
    };
}

参考资料: 维基百科 http://www.lysator.liu.se/c/duffs-device.html

本文由 尼希尔·库马尔·夏尔马 .如果你喜欢GeekSforgek,并想贡献自己的力量,你也可以使用 贡献极客。组织 或者把你的文章寄到contribute@geeksforgeeks.org.看到你的文章出现在Geeksforgeks主页上,并帮助其他极客。

如果您发现任何不正确的地方,或者您想分享有关上述主题的更多信息,请写下评论。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享