关于c ++:如果使用较小的数字,切换案例会更快吗?

Is switch case faster if using smaller numbers?

我想知道,如果我在switch-case语句中通过一些偏移量(或类似的东西)改变"巨大"的数字,我是否可以优化一些东西。所以我做了一个测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include <iostream>
#include <iomanip>
#include <chrono>

int main() {

    uint32_t f = 0x12345688;
    std::chrono::time_point<std::chrono::system_clock> start, end;

    int i = -1;

    start = std::chrono::system_clock::now();
    switch (f)
    {
        case 0x1234500 : i = 0; break;
        case 0x1234522 : i = 2; break;
        case 0x1234555 : i = 5; break;
        case 0x1234588 : i = 8; break;
        default : break;
    }
    end = std::chrono::system_clock::now();
    std::chrono::duration<double> elapsed_seconds = end-start;
    std::cout <<"elapsed time:" << elapsed_seconds.count() <<"s
"
;

    int j = -1;
    start = std::chrono::system_clock::now();
    switch (f & 0xf)
    {
        case (0x1234500 & 0xf) : j = 0; break;
        case (0x1234522 & 0xf) : j = 2; break;
        case (0x1234555 & 0xf) : j = 5; break;
        case (0x1234588 & 0xf) : j = 8; break;
        default : break;
    }
    end = std::chrono::system_clock::now();
    elapsed_seconds = end-start;
    std::cout <<"elapsed time:" << elapsed_seconds.count() <<"s
"
;

    return 0;
}

第二个开关箱似乎总是更快。

案例中的小数字使陈述更快(案例之间的"差距"是相同的)有什么原因吗?


这种基准测试方法毫无意义,因为编译器可以静态地确定两种情况之间的i的值。您的实际代码可能会以如下方式结束:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
start = std::chrono::system_clock::now();
switch (f)
{
    case 0x1234500 : i = 0; break;
    case 0x1234522 : i = 2; break;
    case 0x1234555 : i = 5; break;
    case 0x1234588 : i = 8; break;
    default : break;
}
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout <<"elapsed time:" << elapsed_seconds.count() <<"s
"
;

// i = -1;  this line isn't needed, the value isn't used, lets optimize it away

start = std::chrono::system_clock::now();
// Oh great, we already know the value of i
// Because nothing in the previos code could have affected f
// i will get the same value as it did above, and we removed i = -1
// So lets optimize away this pointless code here
end = std::chrono::system_clock::now();
elapsed_seconds = end-start;

您可以尝试将i声明为volatile,但这可能会阻止编译器进行其他优化,因此也可能不会进行有效的基准测试。

测试之间的i = -1;是没有意义的,因为编译器可以推断出没有使用这个值。所以代码也会被删除。

最好的方法可能是从文件或用户输入中读取常量0x12345688,这样编译器就不能对其进行任何假设。对于这两个测试用例,您需要这样做两次。

一般情况下:在这样做基准测试时,一定要分解代码,以验证您的测试不是胡说八道。


对于性能来说,最重要的是数字是连续的。这是因为编译器可以使用该值来索引内存地址,该地址指定开关应跳转到何处来处理有问题的情况。大的空白使得索引不可能,因为它会跳得很远,编译器必须插入大量的空代码来填充未使用的空间。

小数字可以使它稍微快一点-您可能只保存一条指令,因为编译器可以减去然后仍然可以使用索引。

以上所有内容都依赖于编译器。一个愚蠢的编译器可能根本不会使用索引。