C++ 如何改进在已知值范围内计算变量的一系列else if条件?

C++ 如何改进在已知值范围内计算变量的一系列else if条件?,c++,performance,if-statement,function-pointers,C++,Performance,If Statement,Function Pointers,有没有办法将下面的代码转换成更具伸缩性的代码?我已经简化了它,但我真正的一个必须检查几个不同的值,它要求重构 if (x < 0) foo1(); else if (x < 3) foo2(); else if (x < 8) foo3(); else foo4(); 这些值在编译之前是已知的,循环中的大量条件正在破坏性能 这是解决这个问题的最佳方式吗?非常感谢任何带有解释的替代解决方案您可以使用间隔图。这里有一个示例实现 简单地说,它持有设定

有没有办法将下面的代码转换成更具伸缩性的代码?我已经简化了它,但我真正的一个必须检查几个不同的值,它要求重构

     if (x < 0) foo1();
else if (x < 3) foo2();
else if (x < 8) foo3();
else            foo4();
这些值在编译之前是已知的,循环中的大量条件正在破坏性能


这是解决这个问题的最佳方式吗?非常感谢任何带有解释的替代解决方案

您可以使用
间隔图
。这里有一个示例实现 简单地说,它持有设定范围内任何事物的引用。 您需要为您的案例填充边缘案例,如:

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]
即可获得所需的函数。这将返回映射中的第一个函数


注:我将链接作为示例提供。实施可能有问题。你最好在使用前测试它。

在一般情况下,你有一些区间
[a1,a2],[a2,a3],[an,infty)
并且想要找到
x
所在的区间,你可以通过最坏的
日志n
比较(与你的if-else链进行最坏的
n
比较)。您可以通过对间隔进行二进制搜索来实现这一点。因此,您将首先检查
x
是否小于
a(n/2)
,然后进一步检查
if
-案例中较小的间隔,以及
else
-案例中较大的间隔。对于上面的示例,请进行转换

if(x<0)foo1();
如果(x<3)foo2();
如果(x<8)foo3();
else foo4();
其中最长路径上有4个比较,最短路径上有1个比较

if(x<3){
如果(x<0)foo1();
else foo2();
}否则{
如果(x<8)foo3();
else foo4();
}
这在其所有路径上有2个比较

请注意,在最坏的情况下,比较越少并不一定越快。如果
x
的分布大致相等,则比较快。如果
x
在90%的情况下为负值,则您的第一个版本会更快,因为它主要只使用一个比较,而我的版本总是使用2


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

有多少个
x
的可行值?如果你在某种热循环中,
x
是在循环外计算的吗?是否可以在循环外预计算枚举数,然后使用swit它里面的ch?@walnut
x
随着执行的不同而变化,阅读开关盒的概念。但我认为显示的第一段代码是您能做的最好的。@NicolBolas
x
从0到+inf,它在循环内计算。
x
表示两个移动点之间的距离。在该循环内,我计算t距离并根据该距离调用一个或另一个函数不同距离之间是否存在某种关系?即,如果它们是某种线性函数
a*t+b
,则可以将
x
转换为
(x-b)/a
,然后使用开关打开相应的
t
。虽然我总体上喜欢这个想法,但对此应该非常小心。即使实现非常好,并且您只在热路径中执行一次查找,但由于a)开销,这可能会非常缓慢(我希望if语句的计数仍然在开销比渐近运行时重要得多的范围内)和b)编译器无法优化它,因为它的逻辑要复杂得多。对于一般问题,我非常喜欢这种方法(复杂但有用的实现)但在这种情况下,映射会破坏性能,因为所有数据都是线性存储的anyway@Mateo:您可能仍然有一个“平面图”(
std::vector
)。
m_map.insert(std::make_pair(0, foo1));
m_map.insert(std::make_pair(3, foo2));
m_map.insert(std::make_pair(8, foo3));