如何从位移中获得"lost"位?
How do I get the "lost" bit from a bit shift?
我想对变量进行位移位,并将移位后的位存储在布尔值中。
类似于:
unsigned int i = 1;
bool b = rshift(&i); // i now equals 0 and b is set to true
如何才能做到这一点?
您必须在移位前捕获位:
bool rshift(unsigned int* p) {
bool ret = (*p) & 1;
*p >>= 1;
return ret;
}
您没有。你必须在换班前测试一下:
bool
rshift( unsigned& i )
{
bool results = (i & 0x01) != 0;
i >>= 1;
return results;
}
(这对于右移来说很简单。对于左移,你必须知道字中的位数。)
要对任何移位和任何类型执行此操作,请反转操作(检查是否丢失了什么)。
template <typename T> bool rshift(T& val) {
T const original = val;
return ((val >>= 1) << 1) != original;
}
template <typename T> bool lshift(T& val) {
T const original = val;
return ((val <<= 1) >> 1) != original;
}
如果您正在寻找一个旋转函数,您可以尝试以下操作。
首先,有一个元函数来获取要旋转的值的位数(注意:8*sizeof(T)
不可移植;标准只规定至少8位):
#include <climits>
template <typename T>
struct bits { enum { value = CHAR_BIT * sizeof(T) }; };
接下来,定义一个向右旋转的函数。它通过按预期向右移动,向左移动来向上移动否则会被取消的东西:
template <unsigned int N, typename T>
T rotate_right (T value)
{
enum { left = bits<T>::value - N };
return (value>>N) | (value<<left);
}
具有测试诊断功能,并测试:
#include <iostream>
template <typename T>
void print_bits (std::ostream &os, T value)
{
for (unsigned int i=bits<T>::value; i!=0; --i)
os << ((value>>(i-1))&1);
}
int main () {
char c = 1,
c_ = rotate_right<1>(c);
unsigned long long ull = 0xF0F0C0C050503030,
ull_ = rotate_right<63>(ull);
std::cout << "c ="; print_bits(std::cout, c); std::cout << 'n';
std::cout << "c'="; print_bits(std::cout, c_); std::cout << 'n';
std::cout << "ull ="; print_bits(std::cout, ull); std::cout << 'n';
std::cout << "ull'="; print_bits(std::cout, ull_); std::cout << 'n';
}
输出:
c =00000001
c'=10000000
ull =1111000011110000110000001100000001010000010100000011000000110000
ull'=1110000111100001100000011000000010100000101000000110000001100001
左旋转可以类似地实现,或者根据右旋转来实现。
至于性能,g++检测到习惯用法,并在x86和amd64上使用旋转指令。
g++ -std=c++0x -S main.cc
cat main.s
...
sarl %eax
...
以下是迄今为止提出的建议的替代方案:
bool rshift(int32_t &i) {
long long i2 = (static_cast<int64_t>(i) << 31);
i = (i2 >> 32);
return static_cast<int32_t>(i2);
}
这假设int
是int
现在通常的意思,即int32_t
。它将其复制到int64_t
中,然后执行移位,将较高的32位复制到i
中,然后将较低的32位(包含移位的1
)作为布尔返回。
我不知道这是否比其他方法更快。这种通用方法的附加优点是,它可以用于检索多个比特,例如,如果您偏移了2个或更多比特。
这里有一个用于位抓取的小型c#演示:
using System;
class BitToBoolArray {
static void Main() {
ushort guiMask = 0b1100_1100_0011_0011;
bool[] boxEnabled = new bool[16];
for (int i=0;i<16;guiMask>>=1,++i)
{
bool bit = (guiMask & 0x0001) == 1 ;
boxEnabled[i] = bit;
Console.WriteLine("rnBit position: {0} , Bit: {1}",i,bit);
}
}
}
右移是从变量中获取位的最常见方法,问题是结果是向后的,这有点无聊。有一种方法可以获得变量中的二进制值,即:
该策略是屏蔽一部分比特,就像在右移中一样,但现在针对最重要的比特,二进制常数很好地满足了这一要求。
unsigned int number = 2863311530;
unsigned int mostSignificantBit = 0b10000000000000000000000000000000;
// Masking a number by a binary that only has the
// most significant bit set will result in the
// same binary if the most significant bit of the
// variable was 1.
if((number & mostSignificantBit) == mostSignificantBit){
printf("1");
}else{
printf("0");
}
转储变量的整个二进制内容如下所示:
// The good part of using bitwise operations is that
// signed and unsigned values really don't matter,
// the only thing that bitwise operations care about is binary.
int number = -123456;
unsigned int mostSignificantBit = 0b10000000000000000000000000000000;
for(int i = 0; i < 32; i++){
if((number & mostSignificantBit) == mostSignificantBit){
printf("1");
}else{
printf("0");
}
number = number << 1;
}
printf("n");
// Result: 11111111111111100001110111000000
// this binary is really the 2's complement of
// the number -123456
一些警报
前面的例子效果很好!然而,不同的体系结构/平台甚至编译器可以定义int可以容纳的不同大小的总比特数。好消息是,这并不难处理。标题<stdint.h>实现保持固定位数的数据类型,例如:
#include <stdint.h>
int main(void){
int16_t sixteenBitsInt;
uint16_t unsignedSixteenBitsInt;
int32_t thirtyTwoBitsInt;
uint32_t unsignedThirtyTwoBitsInt;
// ...
// ...
// ...
return 0;
}
但是,如果出于任何原因你不想使用固定的数据长度,那么即使在跨平台环境中存在不同大小的整数,你也可以使用更多的数据长度来实现这一点。
这里的策略是得到一个只有最高有效位集的二进制,而不管变量的大小。按照二进制逻辑,如果你得到一个变量的最大无符号值,除以2,再加上值1,你就会得到这个必要的二进制,例如:
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#define MOST_SIGNIFICANT_BIT UINT_MAX / 2 + 1
#define TRUE 1
#define FALSE 0
typedef unsigned char bool;
int main(void){
int number = -123456;
unsigned int mostSignificantBit = MOST_SIGNIFICANT_BIT;
bool stopFlag = FALSE;
// By the reason of the numbers of bits may be variable,
// we need divide a UINT_MAX until reach 0 to be sure that
// there's no more bits to be shifted.
unsigned int max = UINT_MAX;
while(stopFlag == FALSE){
if((number & mostSignificantBit) == mostSignificantBit){
printf("1");
}else{
printf("0");
}
// Updating the max here allows the
// algorithm to run more one time after
// reaching the "0". Doing this calculation
// inside the while would make the program
// let one bit behind inside the number.
max /= 2;
if(max == 0){
stopFlag = TRUE;
}
number = number << 1;
}
printf("n");
// Result: 11111111111111100001110111000000
// This binary is the 2's complement of the
// number -123456, and is the same of the previous
// example of variable dumping.
return 0;
}
宏UINT_MAX及其同级将跨平台保持不同的值,目的是指定给定数据类型的最大值,从而允许跨平台实现。使用固定长度的数据类型确实更容易,但这也是一个有用的解决方案。
- 为什么'wait with predicate'求解条件变量的'lost wakeup'?
- MySQL 异常"connection lost during query"、"MySQL server has gone away"和"command out of sync"
- 堆栈对象"lost"会发生什么情况?
- 获取"possibly lost"内存泄漏
- 捕获"NVIDIA OpenGL driver lost connection"错误
- igraph_neighborhood "Valgrind output: blocks are indirectly lost in loss record "
- 数组数据在将数组传递给另一个对象后'lost'
- 继承的模板类成员在链构造函数中测试良好,但此后"lost"
- 如何从位移中获得"lost"位?