我使用unsigned char
来存储8个标志。每个标志代表一个立方体的角落。因此00000001
将成为角落1 01000100
将是角落3和7等。我当前的解决方案是&
结果1,2,4,8,16,32,64和128,检查结果是否为零并存储角落。也就是if (result & 1) corners.push_back(1);
。我有机会摆脱那个“如果”的陈述吗?我希望我可以通过按位运算符摆脱它,但我想不出任何。
关于我为什么要摆脱if语句的一些背景知识。此多维数据集实际上是一个体素,它是网格的一部分,其大小至少为512x512x512。这超过1.34亿体素。我正在对每个体素进行计算(嗯,不完全是,但我不会详细介绍,因为这里不相关),这是很多计算。我需要每帧执行这些计算。每个函数调用的任何速度提升都是微不足道的,这将有助于这些计算量。为了给你一个想法,我的算法(在某些时候)需要确定浮点数是负数,正数还是零(在某些错误内)。我在那里有if语句,比检查更大/更小。我用快速浮点数转换为int函数并将其削减了四分之一秒。目前,128x128x128网格中的每个帧需要4秒多一点。
答案 0 :(得分:5)
我会完全考虑一种不同的方法:不同的标志组合只有256种可能性。预先计算256个向量并根据需要将其索引。
std::vector<std::vector<int> > corners(256);
for (int i = 0; i < 256; ++i) {
std::vector<int>& v = corners[i];
if (i & 1) v.push_back(1);
if (i & 2) v.push_back(2);
if (i & 4) v.push_back(4);
if (i & 8) v.push_back(8);
if (i & 16) v.push_back(16);
if (i & 32) v.push_back(32);
if (i & 64) v.push_back(64);
if (i & 128) v.push_back(128);
}
for (int i = 0; i < NumVoxels(); ++i) {
unsigned char flags = GetFlags(i);
const std::vector& v = corners[flags];
... // do whatever with v
}
这样可以避免所有带有push_back call new
的条件和,我怀疑它会更贵。
答案 1 :(得分:1)
Hackers's Delight,第一页:
x & (-x) // isolates the lowest set bit
x & (x - 1) // clears the lowest set bit
内联push_back
方法也会有所帮助(更好地创建一个接收所有标志的函数)。
通常,如果您需要性能,您应该考虑到这一点来设计整个系统。也许如果您发布更多代码,它将更容易提供帮助。
编辑:这是个好主意:unsigned char LOG2_LUT[256] = {...};
int t;
switch (count_set_bits(flags)){
case 8: t = flags;
flags &= (flags - 1); // clearing a bit that was set
t ^= flags; // getting the changed bit
corners.push_back(LOG2_LUT[t]);
case 7: t = flags;
flags &= (flags - 1);
t ^= flags;
corners.push_back(LOG2_LUT[t]);
case 6: t = flags;
flags &= (flags - 1);
t ^= flags;
corners.push_back(LOG2_LUT[t]);
// etc...
};
count_set_bits()
是一个众所周知的函数:http://www-graphics.stanford.edu/~seander/bithacks.html#CountBitsSetTable
答案 2 :(得分:1)
如果设置了某些操作需要进行操作,如果没有设置则不需要进行操作,那么您似乎必须在某处具有某种条件。如果它可以某种方式表达为计算,你可以这样解决它,例如:
numCorners = ((result >> 0) & 1) + ((result >> 1) & 1) + ((result >> 2) & 1) + ...
答案 3 :(得分:0)
嗯......我不确定你会比你现在使用的按位运算符快得多。 corner.push_back方法在做什么?
编辑:这应该是评论&gt; _&gt;我的坏......
答案 4 :(得分:0)
有一种方法,它不是“漂亮”,但它有效。
(result & 1) && corners.push_back(1);
(result & 2) && corners.push_back(2);
(result & 4) && corners.push_back(3);
(result & 8) && corners.push_back(4);
(result & 16) && corners.push_back(5);
(result & 32) && corners.push_back(6);
(result & 64) && corners.push_back(7);
(result & 128) && corners.push_back(8);
它使用C ++语言的一种很少已知的特性:布尔快捷方式。
答案 5 :(得分:0)
我在OpenTTD代码中注意到了类似的算法。事实证明这完全是无用的:你可以通过而不是打破这样的数字来加快速度。相反,通过对字节位的迭代替换现在的vector<>
上的迭代。这对缓存更友好。
即。
unsigned char flags = Foo(); // the value you didn't put in a vector<>
for (unsigned char c = (UCHAR_MAX >> 1) + 1; c !=0 ; c >>= 1)
{
if (flags & c)
Bar(flags&c);
}