作者:手机用户2602900871 | 来源:互联网 | 2023-10-10 22:39
I want to create a very large array on which I write '0's and '1's. I'm trying to simulate a physical process called random sequential adsorption, where units of length 2, dimers, are deposited onto an n-dimensional lattice at a random location, without overlapping each other. The process stops when there is no more room left on the lattice for depositing more dimers (lattice is jammed).
我想要创建一个非常大的数组,我在上面写上0和1。我在尝试模拟一个物理过程,叫做随机顺序吸附,在这个过程中,长度为2的单位二聚体,被随机地沉积在一个n维的格子上,而不会互相重叠。当网格上没有剩余的空间存放更多的二聚物(晶格被堵塞)时,这个过程就停止了。
Initially I start with a lattice of zeroes, and the dimers are represented by a pair of '1's. As each dimer is deposited, the site on the left of the dimer is blocked, due to the fact that the dimers cannot overlap. So I simulate this process by depositing a triple of '1's on the lattice. I need to repeat the entire simulation a large number of times and then work out the average coverage %.
一开始是0的晶格,二聚体由一对'1'表示。当每个二聚体被沉积时,二聚体左边的位置被阻塞,因为二聚体不能重叠。我通过在晶格上沉积1的3倍来模拟这个过程。我需要大量重复整个模拟,然后计算出平均覆盖率%。
I've already done this using an array of chars for 1D and 2D lattices. At the moment I'm trying to make the code as efficient as possible, before working on the 3D problem and more complicated generalisations.
我已经用一个一维和二维格的chars数组做过了。目前,我正在努力使代码尽可能高效,然后再处理3D问题和更复杂的一般化。
This is basically what the code looks like in 1D, simplified:
这就是简化后的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;
}
For the actual project I'm doing, it involves not just dimers but trimers, quadrimers, and all sorts of shapes and sizes (for 2D and 3D).
在我正在做的实际项目中,它不仅包括二聚体,还包括三聚体、四聚体,以及各种形状和大小(用于2D和3D)。
I was hoping that I would be able to work with individual bits instead of bytes, but I've been reading around and as far as I can tell you can only change 1 byte at a time, so either I need to do some complicated indexing or there is a simpler way to do it?
我希望我能够与单个比特而不是字节,但我已经阅读,我可以告诉你只能改变一次1个字节,所以我需要做一些复杂的索引或有一个更简单的方法?
Thanks for your answers
谢谢你的回答
5 个解决方案
31
If I am not too late, this page gives awesome explanation with examples.
如果我还不晚的话,这一页给出了很棒的例子解释。
An array of int
can be used to deal with array of bits
. Assuming size of int
to be 4 bytes
, when we talk about an int
, we are dealing with 32 bits
. Say we have int A[10]
, means we are working on 10*4*8 = 320 bits
and following figure shows it: (each element of array has 4 big blocks, each of which represent a byte
and each of the smaller blocks represent a bit
)
整数数组可以用来处理位数组。假设int的大小是4字节,当我们讨论int时,我们处理的是32位。假设我们有int A[10],这意味着我们要处理10*4*8 = 320位,如下图所示:(数组的每个元素都有4个大块,每个大块代表一个字节,每个小块代表一个比特)
So, to set the k
th bit in array A
:
因此,要在数组A中设置第k位:
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 <
or in the shortened version
或者缩短版
void SetBit( int A[], int k )
{
A[k/32] |= 1 <<(k%32); // Set the bit at the k-th position in A[i]
}
similarly to clear k
th bit:
类似于清除第k位:
void ClearBit( int A[], int k )
{
A[k/32] &= ~(1 <<(k%32));
}
and to test if the k
th bit:
测试第k位:
int TestBit( int A[], int k )
{
return ( (A[k/32] & (1 <<(k%32) )) != 0 ) ;
}
As said above, these manipulations can be written as macros too:
如上所述,这些操作也可以写成宏:
#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)) )
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
Now, each long in a bfield_t can hold sizeof(long)*8 bits.
现在,bfield_t中的每个long都可以保存sizeof(long)*8位。
You can calculate the index of a needed big by:
你可以计算所需的a的指数。
bindex = index / (8 * sizeof(long) );
and your bit number by
还有你的位号
b = index % (8 * sizeof(long) );
You can then look up the long you need and then mask out the bit you need from it.
然后你可以查找你需要的时间,然后用它来掩盖你需要的东西。
result = my_field[bindex] & (1<
or
或
result = 1 & (my_field[bindex]>>b); // if you prefer them to be in bit0
The first one may be faster on some cpus or may save you shifting back up of you need to perform operations between the same bit in multiple bit arrays. It also mirrors the setting and clearing of a bit in the field more closely than the second implemention. set:
第一个可能在某些cpu上运行得更快,或者可以节省您在多个位数组中执行相同位之间的操作所需的向上移动。它也反映了比第二个实现更紧密地在字段中进行的设置和清除。设置:
my_field[bindex] |= 1<
clear:
明确:
my_field[bindex] &= ~(1<
You should remember that you can use bitwise operations on the longs that hold the fields and that's the same as the operations on the individual bits.
您应该记住,您可以对保存字段的长字符使用位操作,这与对单个位的操作相同。
You'll probably also want to look into the ffs, fls, ffc, and flc functions if available. ffs should always be avaiable in strings.h
. It's there just for this purpose -- a string of bits. Anyway, it is find first set and essentially:
如果可用,您可能还需要研究ffs、fls、ffc和flc函数。ffs也应该是有实力的。就是为了这个目的——一串比特。无论如何,它是第一个集合,本质上:
int ffs(int x) {
int c = 0;
while (!(x&1) ) {
c++;
x>>=1;
}
return c; // except that it handles x = 0 differently
}
This is a common operation for processors to have an instruction for and your compiler will probably generate that instruction rather than calling a function like the one I wrote. x86 has an instruction for this, by the way. Oh, and ffsl and ffsll are the same function except take long and long long, respectively.
这是处理器有指令的常见操作,编译器可能会生成指令,而不是像我编写的那样调用函数。顺便说一下,x86对此有一个指令。哦,ffsl和ffsll的功能是一样的,除了长和长。
5
You can use & (bitwise and) and <<(left shift).
您可以使用&(位和)和<(左移)。
For example, (1 <<3) results in "00001000" in binary. So your code could look like:
例如,(1 <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".
Then just scale it up with an array of chars and figure out the appropriate byte to modify first.
然后用一个chars数组对它进行扩展,并首先找出要修改的合适字节。
For more efficiency, you could define a list of bitfields in advance and put them in an array:
为了提高效率,您可以预先定义一个位域列表,并将它们放在一个数组中:
#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};
Then you avoid the overhead of the bit shifting and you can index your bits, turning the previous code into:
然后您就可以避免位移位的开销,并且可以索引您的位,将以前的代码转换为:
eightBits &= (bits[3] & bits[4]);
Alternatively, if you can use C++, you could just use an std::vector
which is internally defined as a vector of bits, complete with direct indexing.
或者,如果您可以使用c++,您可以使用std::vector
,它在内部被定义为位向量,完成直接索引。
3
bitarray.h:
bitarray.h:
#include // 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<
Use:
使用:
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
EDIT the docs:
编辑文档:
"dword" = "double word" = 32-bit value (unsigned, but that's not really important)
"dword" = "double word" = 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)
fetches the dword containing the bit i and shifts the dword right, so that the bit i becomes the least significant bit. Then, a bitwise and with 1 clears all other bits.
getbit(数组,i)获取包含第i位的dword,并将dword右移,以便第i位成为最不重要的位。然后,按位和1清除所有其他的位。
putbit(array, i, v)
first of all checks the least significant bit of v; if it is 0, we have to clear the bit, and if it is 1, we have to set it.
To set the bit, we do a bitwise or of the dword that contains the bit and the value of 1 shifted left by bit_index_in_dword: that bit is set, and other bits do not change.
To clear the bit, we do a bitwise and of the dword that contains the bit and the bitwise complement of 1 shifted left by bit_index_in_dword: that value has all bits set to one except the only zero bit in the position that we want to clear.
The macro ends with , 0
because otherwise it would return the value of dword where the bit i is stored, and that value is not meaningful. One could also use ((void)0)
.
putbit(数组,i, v)首先检查v的最小有效位;如果它是0,我们需要清除位,如果它是1,我们需要设置它。要设置位,我们按位或dword进行设置,dword包含位和bit_index_in_dword左移的1的值:该位已设置,其他位不会更改。为了清除位,我们按位和dword来做,dword包含位和位补1的位补,位补由位_index_in_dword左移:该值将所有位都设置为1,除了我们要清除的位置上唯一的零位。宏以0结尾,否则它会返回dword的值,也就是i被存储的地方,这个值没有意义。也可以使用(void)0。