设置最高有效位
Set the most significant bit
我正在尝试根据 bool
标志切换 unsigned int
的最高有效位。这是我的假设代码 K = unit64_t
:
这是Item
class:
template<typename K>
class Item {
public:
K first;
Item() = default;
explicit Item(const K &elem, const bool flag = false) {
first = elem & 0x3FFFFFFFFFFFFFFF;
first |= (flag * 0x8000000000000000);
}
};
有没有办法做到这一点完全通用?它适用于所有类型的数字 K
?
我试过 8 * sizeof(K)
但它不起作用。
您可以为此利用 std::bitset
。不确定这优化得有多好,但它应该优化得很好并且它可以正常工作并且不需要按位运算知识。
template <typename T>
void toggle_msb(T& val)
{
constexpr auto bit_width = sizeof(T) * CHAR_BIT;
std::bitset<bit_width> temp(val);
val = temp.flip(bit_width - 1).to_ullong();
}
仅使用位操作的选项:
template<typename T>
void Item(T& elem, bool flag = false) {
T mask = (T)1 << (sizeof(T) * 8 - 1);
elem = (elem & ~mask) | (flag ? mask : 0);
}
使用按位运算,但不显式依赖T
的大小:
template<typename T>
T set_top_bit(T value, bool state) {
constexpr T mask = T(~T(0)) >> 1;
value &= mask;
if (state) value |= ~mask;
return value;
}
T(~T(0))
得到一个 T
,所有位设置 1; >> 1
抛出底部位从顶部得到 0,因此在 mask
中我们有一个 T
设置了所有位,但最高位除外。请注意,所有这些舞蹈都是纯粹正式的——this is all evaluated at compile time.
其余部分与您的代码非常相似:屏蔽掉 value
的最高位,然后根据 state
或将其返回(~mask
将是 T
只设置了最高位)。
- Plain
~0
会导致 int
设置为 -1,~0U
在 unsigned int
中设置所有位;要获得所有位都已设置的 T
,我们需要翻转 T(0)
的位(因此,我们的 T 类型为 0),稍后还要转换回 T
,因为,如果 T
小于 int
,~T(0)
实际上等于 ~int(T(0))
,所以 ~0
,由于整数提升规则。
从这个很棒的post,How do you set, clear, and toggle a single bit?,你可以使用这个无分支版本:
#include <climits>
template<typename T>
constexpr T set_top_bit_v2(T value, bool state) {
constexpr auto msb = (sizeof(T) * CHAR_BIT) - 1;
return (value & ~(T{1} << msb)) | (T{state} << msb);
}
将输出与 on Godbolt (here 进行比较),尽管存在差异 Clang 似乎生成相同的代码,而 GCC 和 MSVC 在使用此版本时似乎发出的指令较少。
我正在尝试根据 bool
标志切换 unsigned int
的最高有效位。这是我的假设代码 K = unit64_t
:
这是Item
class:
template<typename K>
class Item {
public:
K first;
Item() = default;
explicit Item(const K &elem, const bool flag = false) {
first = elem & 0x3FFFFFFFFFFFFFFF;
first |= (flag * 0x8000000000000000);
}
};
有没有办法做到这一点完全通用?它适用于所有类型的数字 K
?
我试过 8 * sizeof(K)
但它不起作用。
您可以为此利用 std::bitset
。不确定这优化得有多好,但它应该优化得很好并且它可以正常工作并且不需要按位运算知识。
template <typename T>
void toggle_msb(T& val)
{
constexpr auto bit_width = sizeof(T) * CHAR_BIT;
std::bitset<bit_width> temp(val);
val = temp.flip(bit_width - 1).to_ullong();
}
仅使用位操作的选项:
template<typename T>
void Item(T& elem, bool flag = false) {
T mask = (T)1 << (sizeof(T) * 8 - 1);
elem = (elem & ~mask) | (flag ? mask : 0);
}
使用按位运算,但不显式依赖T
的大小:
template<typename T>
T set_top_bit(T value, bool state) {
constexpr T mask = T(~T(0)) >> 1;
value &= mask;
if (state) value |= ~mask;
return value;
}
T(~T(0))
得到一个 T
,所有位设置 1; >> 1
抛出底部位从顶部得到 0,因此在 mask
中我们有一个 T
设置了所有位,但最高位除外。请注意,所有这些舞蹈都是纯粹正式的——this is all evaluated at compile time.
其余部分与您的代码非常相似:屏蔽掉 value
的最高位,然后根据 state
或将其返回(~mask
将是 T
只设置了最高位)。
- Plain
~0
会导致int
设置为 -1,~0U
在unsigned int
中设置所有位;要获得所有位都已设置的T
,我们需要翻转T(0)
的位(因此,我们的 T 类型为 0),稍后还要转换回T
,因为,如果T
小于int
,~T(0)
实际上等于~int(T(0))
,所以~0
,由于整数提升规则。
从这个很棒的post,How do you set, clear, and toggle a single bit?,你可以使用这个无分支版本:
#include <climits>
template<typename T>
constexpr T set_top_bit_v2(T value, bool state) {
constexpr auto msb = (sizeof(T) * CHAR_BIT) - 1;
return (value & ~(T{1} << msb)) | (T{state} << msb);
}
将输出与