我想创建一个非常大的数组,我在其上写'0'和'1'。我试图模拟一个称为随机顺序吸附的物理过程,其中长度为2的单位二聚体在随机位置沉积在n维晶格上,彼此不重叠。当晶格上没有剩余空间用于沉积更多二聚体(晶格被卡住)时,该过程停止。
最初我从一个零点开始,二聚体用一对'1'表示。当每个二聚体沉积时,二聚体左侧的位点被阻断,这是因为二聚体不能重叠。因此,我通过在晶格上存储三个'1'来模拟这个过程。我需要多次重复整个模拟,然后计算出平均覆盖率%。
我已经使用1D和2D格子的字符数组完成了这项工作。目前,我正在尝试使代码尽可能高效,然后再处理3D问题和更复杂的概括。
这基本上是1D中代码的样子,简化:
int main()
{
/* Define lattice */
array = (char*)malloc(N * sizeof(char));
total_c = 0;
/* Carry out RSA multiple times */
for (i = 0; i < 1000; i++)
rand_seq_ads();
/* Calculate average coverage efficiency at jamming */
printf("coverage efficiency = %lf", total_c/1000);
return 0;
}
void rand_seq_ads()
{
/* Initialise array, initial conditions */
memset(a, 0, N * sizeof(char));
available_sites = N;
count = 0;
/* While the lattice still has enough room... */
while(available_sites != 0)
{
/* Generate random site location */
x = rand();
/* Deposit dimer (if site is available) */
if(array[x] == 0)
{
array[x] = 1;
array[x+1] = 1;
count += 1;
available_sites += -2;
}
/* Mark site left of dimer as unavailable (if its empty) */
if(array[x-1] == 0)
{
array[x-1] = 1;
available_sites += -1;
}
}
/* Calculate coverage %, and add to total */
c = count/N
total_c += c;
}
对于我正在做的实际项目,它不仅涉及二聚体,还涉及三聚体,四聚体和各种形状和尺寸(用于2D和3D)。
我希望我能够使用单个位而不是字节,但我一直在阅读,据我所知,你一次只能改变1个字节,所以要么我需要做一些复杂的索引还是有一种更简单的方法呢?
感谢您的回答
答案 0 :(得分:42)
如果我还不太晚,this页面会给出一些很好的解释。
int
数组可用于处理bits
数组。假设int
的大小为4 bytes
,当我们谈论int
时,我们正在处理32 bits
。假设我们有int A[10]
,意味着我们正在研究10*4*8 = 320 bits
,下图显示了它:(数组的每个元素都有4个大块,每个块代表一个byte
,每个小块代表一个bit
块代表k
)
因此,要设置数组A
中的void SetBit( int A[], int k )
{
int i = k/32; //gives the corresponding index in the array A
int pos = k%32; //gives the corresponding bit position in A[i]
unsigned int flag = 1; // flag = 0000.....00001
flag = flag << pos; // flag = 0000...010...000 (shifted k positions)
A[i] = A[i] | flag; // Set the bit at the k-th position in A[i]
}
位:
void SetBit( int A[], int k )
{
A[k/32] |= 1 << (k%32); // Set the bit at the k-th position in A[i]
}
或缩短版
k
类似于清除void ClearBit( int A[], int k )
{
A[k/32] &= ~(1 << (k%32));
}
位:
k
并测试int TestBit( int A[], int k )
{
return ( (A[k/32] & (1 << (k%32) )) != 0 ) ;
}
位:
#define SetBit(A,k) ( A[(k/32)] |= (1 << (k%32)) )
#define ClearBit(A,k) ( A[(k/32)] &= ~(1 << (k%32)) )
#define TestBit(A,k) ( A[(k/32)] & (1 << (k%32)) )
如上所述,这些操作也可以写成宏:
GET buyer_requests/vehicle_requests/_search
{
"query": {
"filtered": {
"filter": {
"and": [
{
"terms": {
"vehicle.make.raw": [
"Audi",
"BMW",
"Chevrolet"
]
}
},
{
"range": {
"style.price": {
"gte": 15000,
"lte": 20000
}
}
},
{
"geo_distance": {
"distance": "20000km",
"info.pin": {
"lat": 42,
"lon": 21
}
}
}
]
}
}
},
"aggs": {
"makes": {
"filter": {
"range": {
"style.price": {
"gte": 5000,
"lte": 40000
}
}
},
"aggs": {
"makes": {
"terms": {
"field": "vehicle.make.raw",
"order": {
"_term": "asc"
}
}
}
}
},
"model": {
"filter": {
"and": [
{
"terms": {
"vehicle.make.raw": [
"Audi",
"BMW",
"Chevrolet"
]
}
}
]
},
"aggs": {
"models": {
"terms": {
"field": "vehicle.model.raw",
"size": 10,
"order": {
"_term": "asc"
}
}
}
}
}
}
}
答案 1 :(得分:9)
typedef unsigned long bfield_t[ size_needed/sizeof(long) ];
// long because that's probably what your cpu is best at
// The size_needed should be evenly divisable by sizeof(long) or
// you could (sizeof(long)-1+size_needed)/sizeof(long) to force it to round up
现在,bfield_t中的每个long都可以保存sizeof(long)* 8位。
您可以通过以下方式计算所需大的索引:
bindex = index / (8 * sizeof(long) );
和你的位号
b = index % (8 * sizeof(long) );
然后,您可以查找所需的长度,然后从中屏蔽掉您需要的位。
result = my_field[bindex] & (1<<b);
或
result = 1 & (my_field[bindex]>>b); // if you prefer them to be in bit0
第一个可能会更快一些cpus或者可以节省你的需要转移 在多个位阵列中的相同位之间执行操作。它也反映了 在场中设置和清除比第二个实现更紧密的位。 设置:
my_field[bindex] |= 1<<b;
明确:
my_field[bindex] &= ~(1<<b);
您应该记住,您可以对包含字段的长整数使用按位运算 这与各个位的操作相同。
您可能还想查看ffs,fls,ffc和flc函数(如果可用)。 ffs应始终在strings.h
中可用。它只是为了这个目的 - 一串比特。
无论如何,它是第一组,基本上是:
int ffs(int x) {
int c = 0;
while (!(x&1) ) {
c++;
x>>=1;
}
return c; // except that it handles x = 0 differently
}
这是处理器有一个指令的常见操作,您的编译器可能会生成该指令而不是像我编写的那样调用函数。顺便说一句,x86有一个指令。哦,ffsl和ffsll是相同的函数,除了分别取long和long long。
答案 2 :(得分:6)
你可以使用&amp; (按位和)和&lt;&lt; (左移)。
例如,(1 <&lt; 3)以二进制形式产生“00001000”。所以你的代码看起来像:
char eightBits = 0;
//Set the 5th and 6th bits from the right to 1
eightBits &= (1 << 4);
eightBits &= (1 << 5);
//eightBits now looks like "00110000".
然后用一个字符数组进行缩放,找出要修改的相应字节。
为了提高效率,您可以提前定义一个位域列表并将它们放在一个数组中:
#define BIT8 0x01
#define BIT7 0x02
#define BIT6 0x04
#define BIT5 0x08
#define BIT4 0x10
#define BIT3 0x20
#define BIT2 0x40
#define BIT1 0x80
char bits[8] = {BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7, BIT8};
然后,您可以避免位移的开销,并且可以索引您的位,将前面的代码转换为:
eightBits &= (bits[3] & bits[4]);
或者,如果你可以使用C ++,你可以使用一个std::vector<bool>
,它在内部定义为一个位向量,并带有直接索引。
答案 3 :(得分:5)
bitarray.h :
#include <inttypes.h> // defines uint32_t
//typedef unsigned int bitarray_t; // if you know that int is 32 bits
typedef uint32_t bitarray_t;
#define RESERVE_BITS(n) (((n)+0x1f)>>5)
#define DW_INDEX(x) ((x)>>5)
#define BIT_INDEX(x) ((x)&0x1f)
#define getbit(array,index) (((array)[DW_INDEX(index)]>>BIT_INDEX(index))&1)
#define putbit(array, index, bit) \
((bit)&1 ? ((array)[DW_INDEX(index)] |= 1<<BIT_INDEX(index)) \
: ((array)[DW_INDEX(index)] &= ~(1<<BIT_INDEX(index))) \
, 0 \
)
使用:
bitarray_t arr[RESERVE_BITS(130)] = {0, 0x12345678,0xabcdef0,0xffff0000,0};
int i = getbit(arr,5);
putbit(arr,6,1);
int x=2; // the least significant bit is 0
putbit(arr,6,x); // sets bit 6 to 0 because 2&1 is 0
putbit(arr,6,!!x); // sets bit 6 to 1 because !!2 is 1
编辑文档:
&#34; DWORD&#34; =&#34;双字&#34; = 32位值(无符号,但这并不重要)
RESERVE_BITS: number_of_bits --> number_of_dwords
RESERVE_BITS(n) is the number of 32-bit integers enough to store n bits
DW_INDEX: bit_index_in_array --> dword_index_in_array
DW_INDEX(i) is the index of dword where the i-th bit is stored.
Both bit and dword indexes start from 0.
BIT_INDEX: bit_index_in_array --> bit_index_in_dword
If i is the number of some bit in the array, BIT_INDEX(i) is the number
of that bit in the dword where the bit is stored.
And the dword is known via DW_INDEX().
getbit: bit_array, bit_index_in_array --> bit_value
putbit: bit_array, bit_index_in_array, bit_value --> 0
getbit(array,i)
获取包含位i的dword并且移位 dword right ,以便位i成为最低位。然后,按位和,1清除所有其他位。
putbit(array, i, v)
首先检查v的最低有效位;如果它是0,我们必须清除该位,如果它是1,我们必须设置它
要设置该位,我们执行包含该位的dword的按位或,并且通过bit_index_in_dword将1 的值向左移位:该位已设置,其他位执行不要改变
要清除该位,我们执行包含该位的dword的按位和,并通过bit_index_in_dword执行1 左移的按位补码:除了我们要清除的位置中的唯一零位之外,value的所有位都设置为1
宏以, 0
结束,否则它将返回存储位i的dword值,并且该值没有意义。也可以使用((void)0)
。
答案 4 :(得分:2)
这是一个权衡:
(1)每2位值使用1个字节 - 简单,快速,但使用4x内存
(2)将比特打包成字节 - 更复杂,一些性能开销,使用最小内存
如果你有足够的可用内存,那就去(1),否则考虑(2)。