如何改进一堆在已知值范围内评估变量的 else-if 条件?

How to improve a bunch of else-if conditions that evaluate a variable inside a range among known values?

本文关键字:评估 范围内 变量 条件 else-if 何改进 一堆      更新时间:2023-10-16

有没有办法将下面的代码转换为更具可扩展性的代码?我已经简化了它,但我真正的必须检查几个不同的值,并且它要求重构。

if (x < 0) foo1();
else if (x < 3) foo2();
else if (x < 8) foo3();
else            foo4();

我尝试了以下方法:

struct Ptr2foo {
void (*foo_x)();
}
Ptr2foo ptr2foo_x[4] {
foo1,
foo2,
foo3,
foo4
}
ptr2foo_x[someMagicWithMy_X_AndMyKnownValues].foo_x();

这些值在编译之前是已知的,循环内的条件数量正在降低性能。

这是解决此问题的最佳方法吗?高度赞赏任何带有其解释的替代解决方案

在一般情况下,你有一些区间[a1, a2), [a2, a3), ..., [an, infty)并且想要找到x所在的区间,你可以使用最坏情况log n比较(相对于具有最坏情况n比较的if-else链(。您可以通过对间隔进行二叉搜索来做到这一点。因此,您将首先检查x是否小于a(n/2),然后进一步检查if情况下较小的间隔和else情况下较大的间隔。对于上面的示例,转换

if (x < 0) foo1();
else if (x < 3) foo2();
else if (x < 8) foo3();
else            foo4();

在它的最长

路径上有 4 个比较,在最短路径上有 1 个比较
if( x < 3 ) {
if( x < 0 ) foo1();
else        foo2();
} else {
if( x < 8 ) foo3();
else        foo4();
}

这在其所有路径上都有 2 个比较。

请注意,在最坏的情况下,较少的比较不一定更快。如果x大致均匀分布,则速度更快。如果x在 90% 的情况下为负数,您的第一个版本会更快,因为它大多只使用一个比较,而我的版本始终使用 2。

这就是为什么您还应该考虑通过此代码的热路径(即最常见的路径(是什么。如果在大多数情况下x至少是 8,您绝对应该先检查它,依此类推。

您可以使用interval_map.这里有一个示例实现 简单地说,它包含设定范围内任何内容的引用。 您需要填充案例的边缘情况,例如:

m_map.insert(std::make_pair(0, foo1));
m_map.insert(std::make_pair(3, foo2));
m_map.insert(std::make_pair(8, foo3));

然后你可以简单地得到你想要的函数m_map[1]. 这将返回映射中的第一个函数。

注意:我给出链接作为示例。实施可能存在问题。您最好在使用前对其进行测试。