C++循环位移模板实现

图片来源:https://www.pixiv.net/artworks/81470216

预备知识

算术右移

算术右移会保留符号位(或者填充符号位),这样可以保证左移一位等于除以2 ,算术上符合直觉;但如果只是观察bit位变化,对于负数来说,算术右移看起来就是不断在左边填充“1”,和其他位移操作相比,显得不那么符合直觉(无符号数左移/右移、正数算术左移/右移、负数算术左移都可以理解为填充“0”)。

-105算术右移一位(图来自维基百科)

C++ 20 明确规定了对于有符号数的右移为算术右移,C++ 20 前虽没明确规定,但大多编译器的实现上也是算术右移:

For negative a, the value of a >> b is implementation-defined (in most implementations, this performs arithmetic right shift, so that the result remains negative). (until C++20)

The value of a >> b is a/2b, rounded down (in other words, right shift on signed a is arithmetic right shift). (since C++20)

Arithmetic operators

隐式类型转换

C++ 算术运算符不接受小于“int”的类型,所以位移运算前会把 signed char 转换成 intunsigned char 转换成 unsigned int 。观察bit位变化,对于无符号数和有符号正数来说,转换后额外bit位填充的是“0” ,对于负数来说转换后额外bit位填充的是“1”。

循环位移模板实现(C++ 20)

#ifndef ROTATE_NBIT_
#define ROTATE_NBIT_

#include <concepts>
#include <cstddef>

template <std::integral interger_t>
interger_t RotateLeftNbits(interger_t value, size_t n) {
    // 将有符号数转换为对应类型的无符号数
    std::make_unsigned_t<interger_t> uvalue = value;
    // 计算bit总长度
    size_t bit_num = sizeof(uvalue) * 8;
    // 避免多余的位移
    n %= bit_num;
    return interger_t(uvalue << n | uvalue >> (bit_num - n));
}

template <std::integral interger_t>
interger_t RotateRightNbits(interger_t value, size_t n) {
    std::make_unsigned_t<interger_t> uvalue = value;
    size_t bit_num = sizeof(uvalue) * 8;
    n %= bit_num;
    return interger_t(uvalue >> n | uvalue << (bit_num - n));
}

#endif /* ROTATE_NBIT_ */

参考:

知识共享许可协议
本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注