c - 在 C 中使用按位运算的 2 位映射
问题描述
这是我的第一个问题,所以我希望能做对。
我有一个问题,我必须映射一个可以在 (0, 1, 2) 范围内的键以从同一范围 (0, 1, 2) 中选择一个值。我必须重复这一点数百万次,我试图通过在 C 中使用按位运算来实现这一点,但没有成功。
因此,假设我在 (0, 1, 2) 范围内有 16 个键,我想使用以下规则将它们映射到同一范围内的 16 个值:
0 -> 2
1 -> 1
2 -> 1
我可以将 16 个键的数组表示为 32 位无符号整数中的 16 个 2 位对。例如:
0, 1, 2, 1, 2, 0, ... //Original array of keys
00 01 10 01 10 00 ... //2-bit pairs representation of keys in a 32bit int
我有兴趣按照上述规则转换无符号整数(即必须按照规则转换 2 位对:00->10、01->01 和 10->01),这样我就结束了加上一个 32 位无符号整数,如:
10 01 01 01 01 10 ... //2-bit pairs transformed using the given rule.
它会是一个相对快速的按位过程,可以让我有效地应用这种转换(假设转换规则可以改变)?
我希望我清楚地提出了我的问题。谢谢你的帮助。
编辑:我纠正了一些错误,并在评论后澄清了一些观点。
EDIT2:根据一些建议,我添加了我希望的代码示例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
unsigned int keys[16];
unsigned int bitKeys = 0;
unsigned int mapping[3];
unsigned int result[16];
unsigned int bitResults = 0;
//Initialize random keys and mapping dict
for(i = 0; i<16; i++)
keys[i] = rand() % 3;
bitKeys |= keys[i] << (2*i);
for(i = 0; i<3; i++)
mapping[i] = rand() % 3;
//Get results without using bitwise opperations.
for(i = 0; i<16; i++)
result[i] = mapping[ keys[i] ];
bitResults |= result[i] << (2*i);
//Would it be possible to get bitResults directly from bitKeys efficiently by using bitwise operations?
return 0;
}
解决方案
经过思考,并使用其他答案的一些想法,我想我找到了一个通用的解决方案。它基于首先估计值,假设只有键 10 和 01(即一对中的一个位确定另一个),然后通过键 00 进行更正。解决方案的示例代码:
#include <stdio.h>
#include <stdlib.h>
void printBits(size_t const size, void const * const ptr)
{
unsigned char *b = (unsigned char*) ptr;
unsigned char byte;
int i, j;
for (i=size-1;i>=0;i--)
{
for (j=7;j>=0;j--)
{
byte = (b[i] >> j) & 1;
printf("%u", byte);
if(j%2 == 0) printf("|");
}
}
puts("");
}
int test2BitMapping(unsigned int * mapping)
{
int i;
unsigned int keys[16];
unsigned int bitKeys = 0;
unsigned int b = 0;
unsigned int c = 0;
unsigned int d = 0;
unsigned int expand[4] = {0x00000000u, 0x55555555u, 0xAAAAAAAAu, 0xFFFFFFFFu};
unsigned int v12 = 0;
unsigned int v0mask = 0;
unsigned int result[16];
unsigned int bitResults = 0;
unsigned int bitResultsTest = 0;
//Create mapping masks
b = ((1 & mapping[1]) | (2 & mapping[2]));
c = (2 & mapping[1]) | (1 & mapping[2]);
d = mapping[0];
b = expand[b];
c = expand[c];
d = expand[d];
//Initialize random keys
for(i = 0; i<16; i++) {
if(0) { //Test random keys
keys[i] = rand() % 3;
}
else { //Check all keys are generated
keys[i] = i % 3;
}
bitKeys |= keys[i] << (2*i);
}
//Get results without using bitwise opperations.
for(i = 0; i<16; i++) {
result[i] = mapping[ keys[i] ];
bitResultsTest |= result[i] << (2*i);
}
//Get results by using bitwise opperations.
v12 = ( bitKeys & b ) | ( (~bitKeys) & c );
v0mask = bitKeys | (((bitKeys & 0xAAAAAAAAu) >> 1) | ((bitKeys & 0x55555555u) << 1));
bitResults = ( d & (~v0mask) ) | ( v12 & v0mask );
//Check results
if(0) {
for(i = 0; i<3; i++) {
printf("%d -> %d, ", i, mapping[i]);
}
printf("\n");
printBits(sizeof(unsigned int), &bitKeys);
printBits(sizeof(unsigned int), &bitResults);
printBits(sizeof(unsigned int), &bitResultsTest);
printf("-------\n");
}
if(bitResults != bitResultsTest) {
printf("*********\nDifferent\n*********\n");
}
else {
printf("OK\n");
}
}
int main(void)
{
int i, j, k;
unsigned int mapping[3];
//Test using random mapping
for(k = 0; k < 1000; k++) {
for(i = 0; i<3; i++) {
mapping[i] = rand() % 3;
}
test2BitMapping(mapping);
}
//Test all possible mappings
for(i = 0; i<3; i++) {
for(j = 0; j<3; j++) {
for(k = 0; k<3; k++) {
mapping[0] = i;
mapping[1] = j;
mapping[2] = k;
test2BitMapping(mapping);
}
}
}
return 0;
}
推荐阅读
- sql - 基于另一个分组的条件分组
- .net - 是否可以为一种特定方法覆盖 SOAP 操作名称空间?
- download - 文件在 Chrome 中下载,但不在 Safari 中,但 console.log(response) 和 Network 选项卡显示从服务器发送的文件
- javascript - 如何停止绑定每个处理程序并声明变量“那个”
- multithreading - 防止同时运行功能
- c++ - 使用模板时出现 C++ 分段错误 11
- android - 找不到将数据库数据加载到其中的变量
- ruby - 使用带有参数的 proc 速记
- vba - 删除空白单元格 - 146,459 行
- java - Java中有保留的包名吗?