Mat*_*cci 1 c math bit-manipulation packing uint64
我收到了一个数据集合,我需要将它打包成一个uint64_t值,在下面的示例中采用"weatherlog_t"类型的形式
我不允许使用算术运算符(+,++, - , - ,*,%,/,...),但我可以使用按位运算符(&,|,^,<<,>> ,〜)和逻辑运算符(!,=, - ,!=,&&和||)
但是我确实有预定义的add()和sub()函数来处理按位加法和减法,它们在下面的例子中使用.这些已经过测试,我很确定它们的工作达到了这里所需的程度.
根据说明,64位值必须按如下方式排列:
/* - year :: 6 bits -- stored as the number of years since the year 2000.
- month :: 4 bits
- day :: 5 bits
- zip_code :: 16 bits
- high_temp :: in degrees Fahrenheit, stored as an 8-bit signed integer
- low_temp :: in degrees Fahrenheit, stored as 8-bit signed integer
- precipitation :: in mm. stored as a 10-bit unsigned integer.
- average_wind_speed :: 7 bits. unsigned int km/hr.
All of these are packed into a 64 bit unsigned integer in the above order.
We'd store:
- year :: 2015, which is 15 years from 2000, so 001111
- month :: September, which is the 9th month, so 1001.
- day :: 16, which is 1 0000
- zip_code :: 19122 which is 0100 1010 1011 0010
- high_temp :: 85F, so 0101 0101
- low_temp :: 65F, so 0100 0001
- precipitation :: 35 mm so 00 0010 0011
- average wind speed :: 5 km/h, so 000 0101
And all would be packed into a single 64-bit unsigned integer:
00 1111 1001 10000 0100 1010 1011 0010 0101 0101 0100 0001 00 0010 0011 000 0101
OR
0011 1110 0110 0000 1001 0101 0110 0100 1010 1010 1000 0010 0001 0001 1000 0101 */
Run Code Online (Sandbox Code Playgroud)
到目前为止,我所拥有的是:
weatherlog_t pack_log_entry(unsigned int year, unsigned int month, unsigned int day,
unsigned int zip, int high_temp, int low_temp,
unsigned int precip, unsigned int avg_wind_speed) {
weatherlog_t ret = 0;
unsigned int newYear = sub(year, 2000);
ret = (ret << 6);
ret = add(ret, newYear);
ret = (ret << 4);
ret = add(ret, month);
ret = (ret << 5);
ret = add(ret, day);
ret = (ret << 16);
ret = add(ret, zip);
ret = (ret << 8);
ret = add(ret, high_temp);
ret = (ret << 8);
ret = add(ret, low_temp);
ret = (ret << 10);
ret = add(ret, precip);
ret = (ret << 6);
ret = add(ret, avg_wind_speed);
return ret;
}
Run Code Online (Sandbox Code Playgroud)
但是,当我进入并测试它时,检查ret的二进制值,它似乎停止在32位,并且在此点之后向左移位导致第32个最左位的任何位丢失.我正在努力理解我做错了什么,虽然我是按位算术的新手,并且还没有完全理解它与C语言的交互方式.
编辑:根据要求,add()和subtract()的代码
unsigned int add(unsigned int i, unsigned int j) {
/* can be done in a total of 7 lines, including one to declare an unsigned int, */
/* two for a while loop, and one for the return
You're not required to do it in 7 lines though . */
while(j != 0){
unsigned int carry = i & j;
i = i ^ j;
j = carry << 1;
}
return i;
}
unsigned int sub(unsigned int i, unsigned int j) {
/* Similar 7 lines, although there is a shorter way */
while (j != 0){
unsigned int borrow = (~i) & j;
i = i ^ j;
j = borrow << 1;
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
我不知道你需要那些add/sub函数; 看起来像混淆.特定位的打包数据更直接:
#define YEAR_POS 58
#define MONTH_POS 48
ret = (uint64_t)year << YEAR_POS |
(uint64_t)month << MONTH_POS |
...
Run Code Online (Sandbox Code Playgroud)
这具有以下优点:1)快速,2)与端无关=完全可移植.
如果您怀疑它们包含超出指定大小的垃圾,则可能必须提前屏蔽每个变量:
#define YEAR_SIZE 6
year &= (1u << YEAR_SIZE)-1;
Run Code Online (Sandbox Code Playgroud)