Optimization 查找整数最后N位的最快方法是什么?

Optimization 查找整数最后N位的最快方法是什么?,optimization,integer,bit-manipulation,mathematical-optimization,unsigned,Optimization,Integer,Bit Manipulation,Mathematical Optimization,Unsigned,哪种算法返回无符号整数中的最后n位最快 一, return num&1这在很大程度上取决于您使用的编译器、优化设置以及使用的整数的大小 我在本节中的假设是,答案是编译器将足够聪明,能够以一种比您选择编写的任何东西都更好的方式优化所有这些。从某种意义上说,这是正确的。考虑下面三个代码: #include <stdint.h> #include <limits.h> uint32_t lastBitsOf_v1(uint32_t number, uint32_t howMa

哪种算法返回无符号整数中的最后n位最快

一,


return num&1这在很大程度上取决于您使用的编译器、优化设置以及使用的整数的大小

我在本节中的假设是,答案是编译器将足够聪明,能够以一种比您选择编写的任何东西都更好的方式优化所有这些。从某种意义上说,这是正确的。考虑下面三个代码:

#include <stdint.h>
#include <limits.h>

uint32_t lastBitsOf_v1(uint32_t number, uint32_t howManyBits) {
    return number & ((1 << howManyBits) - 1);
}

uint32_t lastBitsOf_v2(uint32_t number, uint32_t howManyBits) {
    return number % (1 << howManyBits);
}

uint32_t lastBitsOf_v3(uint32_t number, uint32_t howManyBits) {
    uint32_t shift = sizeof(number) * CHAR_BIT - howManyBits;
    return (number << shift) >> shift;
}
请注意,编译器识别出您试图对该函数的前两个版本执行的操作,并完全重写代码以使用bzhi x86指令。此指令将一个寄存器的低位复制到另一个寄存器中。换句话说,编译器能够生成一条汇编指令!另一方面,编译器无法识别上一个版本试图执行的操作,因此它实际生成了编写的代码,并实际执行了移位和减法

但这还不是故事的结局。假设要提取的位数是预先知道的。例如,假设我们需要较低的13位。现在,看看这段代码会发生什么:

#include <stdint.h>
#include <limits.h>

uint32_t lastBitsOf_v1(uint32_t number) {
    return number & ((1 << 13) - 1);
}

uint32_t lastBitsOf_v2(uint32_t number) {
    return number % (1 << 13);
}

uint32_t lastBitsOf_v3(uint32_t number) {
    return (number << 19) >> 19;
}
所有三个版本都被编译成完全相同的代码。编译器看到了我们在每种情况下所做的工作,并将其替换为更简单的代码,基本上是第一个版本

看到这一切后,你该怎么办?我的建议如下:

除非这段代码是一个绝对的性能瓶颈——如中所述,您已经测量了代码的运行时,并且您绝对确定提取低位数字的代码实际上是在降低您的速度——否则我根本不会对此太担心。选择您能阅读的最可读的代码。我个人认为选项1最干净,但那只是我自己

如果您必须尽可能地从中获得每一盎司的性能,而不是相信我的话,我建议您修改不同版本的代码,看看每种情况下生成的程序集是什么,并运行一些性能实验。毕竟,如果像这样的事情真的很重要,你应该亲自去看看


希望这有帮助

这在很大程度上取决于您使用的编译器、优化设置以及使用的整数大小

我在本节中的假设是,答案是编译器将足够聪明,能够以一种比您选择编写的任何东西都更好的方式优化所有这些。从某种意义上说,这是正确的。考虑下面三个代码:

#include <stdint.h>
#include <limits.h>

uint32_t lastBitsOf_v1(uint32_t number, uint32_t howManyBits) {
    return number & ((1 << howManyBits) - 1);
}

uint32_t lastBitsOf_v2(uint32_t number, uint32_t howManyBits) {
    return number % (1 << howManyBits);
}

uint32_t lastBitsOf_v3(uint32_t number, uint32_t howManyBits) {
    uint32_t shift = sizeof(number) * CHAR_BIT - howManyBits;
    return (number << shift) >> shift;
}
请注意,编译器识别出您试图对该函数的前两个版本执行的操作,并完全重写代码以使用bzhi x86指令。此指令将一个寄存器的低位复制到另一个寄存器中。换句话说,编译器能够生成一条汇编指令!另一方面,编译器无法识别上一个版本试图执行的操作,因此它实际生成了编写的代码,并实际执行了移位和减法

但这还不是故事的结局。假设要提取的位数是预先知道的。例如,假设我们需要较低的13位。现在,看看这段代码会发生什么:

#include <stdint.h>
#include <limits.h>

uint32_t lastBitsOf_v1(uint32_t number) {
    return number & ((1 << 13) - 1);
}

uint32_t lastBitsOf_v2(uint32_t number) {
    return number % (1 << 13);
}

uint32_t lastBitsOf_v3(uint32_t number) {
    return (number << 19) >> 19;
}
所有三个版本都被编译成完全相同的代码。编译器看到了我们在每种情况下所做的工作,并将其替换为更简单的代码,基本上是第一个版本

看到这一切后,你该怎么办?我的建议如下:

除非这段代码是一个绝对的性能瓶颈——如中所述,您已经测量了代码的运行时,并且您绝对确定提取低位数字的代码实际上是在降低您的速度——否则我根本不会对此太担心。选择您能阅读的最可读的代码。我个人认为选项1最干净,但那只是我自己

如果您必须尽可能地从中获得每一盎司的性能,而不是相信我的话,我建议您修改不同版本的代码,看看每种情况下生成的程序集是什么,并运行一些性能实验。毕竟,如果像这样的事情真的很重要,你应该亲自去看看


希望这有帮助

比特是常数吗?允许的操作集是否包括?@harold位不是常数。只要代码可以用叮当声编译,我就可以。不过,ARM兼容算法也很好。这是专门针对C语言的,还是您在使用其他语言?位是常量吗?允许的操作集是否包括?@harold位不是常数。只要代码可以用叮当声编译,我就可以了
用它。不过,ARM兼容算法也很好,这是专门针对C语言的,还是您在使用其他语言?