周期性地循环通过 3 值 C# 枚举的单个(且成本低廉的)操作(即使用 wrap)

Single(and inexpensive) operation to cycle through a 3 value C# enum periodically(ie with wrap)

我有一个 3 元素枚举,它定义了三个上下文之一,例如红色、绿色或蓝色。此枚举用于具有数百万次迭代的循环中,例如,像素很多。这些字段当前相隔一个 int,这是默认值。给定所需的 R,G,B,R,G,B... 的生产顺序,我目前使用检查值当前是否为 B,从而将其分配给 R,否则递增值。

private enum CHANNEL_CONTEXT {RED, GREEN, BLUE} //here is a sample enum

//here is a sample loop with the relevant construct
CHANNEL_CONTEXT current = CHANNEL_CONTEXT.RED;
while(condition)
{
    use current;
    //...
    if(current == CHANNEL_CONTEXT.BLUE)
        current = CHANNEL_CONTEXT.RED
    else
        current+=1;

}

有没有一种方法可以通过一次操作包装一个 3 字段枚举,这样就不需要分支来确定是否需要包装。我知道模数 (%) 符合要求,但我的动机是基于性能的,我最多只能通过如此昂贵的操作实现收支平衡(测试证实,但并非详尽无遗)。

为了正确看待我的议程,如果我有 256 个相关字段,我可以创建一个基于字节的枚举,并不受惩罚地递增和有意溢出。 las,我只有三个,而且我想不出一种方法来使用轻量级 ALU 运算(+,-,&,^,|,<<.. ETC)。我也无法想出一种方法来使用这种操作在没有临时性的情况下交换位,但是有一种很少实用但可行的方法可以做到这一点。

有人可以指导我分配 3 个整数枚举值,以便它们可以定期遍历,不需要分支,也不需要使用基于除法的运算符(如模数)吗?

虽然听起来不太可能击败 x = (x + 1) % 3,但您可以尝试使用映射 table:

var map = new[]{1,2,0};
x = map[x];

您可能需要将其包装在 unsafe 中以删除对数组访问的边界检查。


如果您真的设置位操作而不考虑代码的可读性 - 您感兴趣的转换数字的 table 足够小,可以为每个位手动构建然后组合。

真相table:

Source     Result
Bit2 Bit1  Bit2 Bit1
0    0     0    1
0    1     1    0
1    0     0    0
1    1     x    x 

如您所见,我们感兴趣的值仅产生 2 non-zero 位,因此生成的表达式将非常简单 - 1 的一种情况用于低位,另一种情况用于高位(假设值永远不会落在 0-2 范围之外(如果这是唯一的转换,这是安全的)。

var b1 = (x & 1) >> 0; // extract lower bit  0
var b2 = (x & 2) >> 1; // extract higher bit 1
// only care of cases when pair of bits results in 1 
var resultBit1 =  1 & (~b1 & ~b2); // 00 -> x1, other cases is 0
var resultBit2 = (1 & (b1 & ~b2)) << 1;               // 01 -> 1x, other cases is 0
x = resultBit1 | resultBit2;

或将所有内容内联到一个不可读的行中:

x = 1 & ~(x | x >> 1) | 2 & (x & 1 & ~x >> 1) << 1;