热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

如何定义和处理C中的位数组?-HowtodefineandworkwithanarrayofbitsinC?

IwanttocreateaverylargearrayonwhichIwrite0sand1s.Imtryingtosimulateaphysica

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 个解决方案

#1


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个大块,每个大块代表一个字节,每个小块代表一个比特)

enter image description here

So, to set the kth 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 kth bit:

类似于清除第k位:

void  ClearBit( int A[],  int k )                
   {
      A[k/32] &= ~(1 <<(k%32));
   }

and to test if the kth 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)) )

#2


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的功能是一样的,除了长和长。

#3


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 ,它在内部被定义为位向量,完成直接索引。

#4


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。

#5


2  

It's a trade-off:

这是一种权衡:

(1) use 1 byte for each 2 bit value - simple, fast, but uses 4x memory

(1)对每个2位值使用1个字节——简单、快速,但是使用4x内存

(2) pack bits into bytes - more complex, some performance overhead, uses minimum memory

(2)将比特打包成字节——更复杂的、一些性能开销,使用最小的内存

If you have enough memory available then go for (1), otherwise consider (2).

如果你有足够的可用内存,那么选择(1),否则考虑(2)。


推荐阅读
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Java SE从入门到放弃(三)的逻辑运算符详解
    本文详细介绍了Java SE中的逻辑运算符,包括逻辑运算符的操作和运算结果,以及与运算符的不同之处。通过代码演示,展示了逻辑运算符的使用方法和注意事项。文章以Java SE从入门到放弃(三)为背景,对逻辑运算符进行了深入的解析。 ... [详细]
  • 生成式对抗网络模型综述摘要生成式对抗网络模型(GAN)是基于深度学习的一种强大的生成模型,可以应用于计算机视觉、自然语言处理、半监督学习等重要领域。生成式对抗网络 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • SpringMVC接收请求参数的方式总结
    本文总结了在SpringMVC开发中处理控制器参数的各种方式,包括处理使用@RequestParam注解的参数、MultipartFile类型参数和Simple类型参数的RequestParamMethodArgumentResolver,处理@RequestBody注解的参数的RequestResponseBodyMethodProcessor,以及PathVariableMapMethodArgumentResol等子类。 ... [详细]
  • 使用C++编写程序实现增加或删除桌面的右键列表项
    本文介绍了使用C++编写程序实现增加或删除桌面的右键列表项的方法。首先通过操作注册表来实现增加或删除右键列表项的目的,然后使用管理注册表的函数来编写程序。文章详细介绍了使用的五种函数:RegCreateKey、RegSetValueEx、RegOpenKeyEx、RegDeleteKey和RegCloseKey,并给出了增加一项的函数写法。通过本文的方法,可以方便地自定义桌面的右键列表项。 ... [详细]
  • 流数据流和IO流的使用及应用
    本文介绍了流数据流和IO流的基本概念和用法,包括输入流、输出流、字节流、字符流、缓冲区等。同时还介绍了异常处理和常用的流类,如FileReader、FileWriter、FileInputStream、FileOutputStream、OutputStreamWriter、InputStreamReader、BufferedReader、BufferedWriter等。此外,还介绍了系统流和标准流的使用。 ... [详细]
  • 本文介绍了使用C++Builder实现获取USB优盘序列号的方法,包括相关的代码和说明。通过该方法,可以获取指定盘符的USB优盘序列号,并将其存放在缓冲中。该方法可以在Windows系统中有效地获取USB优盘序列号,并且适用于C++Builder开发环境。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 图像因存在错误而无法显示 ... [详细]
  • Android自定义控件绘图篇之Paint函数大汇总
    本文介绍了Android自定义控件绘图篇中的Paint函数大汇总,包括重置画笔、设置颜色、设置透明度、设置样式、设置宽度、设置抗锯齿等功能。通过学习这些函数,可以更好地掌握Paint的用法。 ... [详细]
  • 开源Keras Faster RCNN模型介绍及代码结构解析
    本文介绍了开源Keras Faster RCNN模型的环境需求和代码结构,包括FasterRCNN源码解析、RPN与classifier定义、data_generators.py文件的功能以及损失计算。同时提供了该模型的开源地址和安装所需的库。 ... [详细]
author-avatar
手机用户2602900871
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有