热门标签 | 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)。


推荐阅读
  • 本文探讨了在Node.js环境中如何有效地捕获标准输出(stdout)的内容,并将其存储到变量中。通过具体的示例和解决方案,帮助开发者解决常见的输出捕获问题。 ... [详细]
  • Activity跳转动画 无缝衔接
    Activity跳转动画 无缝衔接 ... [详细]
  • Cadence SPB 16.5 安装指南与注意事项
    本文提供了详细的 Cadence SPB 16.5 安装步骤,包括环境配置、安装过程中的关键步骤以及常见问题的解决方案。适合初次安装或遇到问题的技术人员参考。 ... [详细]
  • 本文介绍了JSP的基本概念、常用标签及其功能,并通过示例详细说明了如何在JSP页面中使用Java代码。 ... [详细]
  • 本文详细介绍了Oracle RMAN中的增量备份机制,重点解析了差异增量和累积增量备份的概念及其在不同Oracle版本中的实现。通过对比两种备份方式的特点,帮助读者选择合适的备份策略。 ... [详细]
  • 本文详细介绍了如何在本地环境中安装配置Frida及其服务器组件,以及如何通过Frida进行基本的应用程序动态分析,包括获取应用版本和加载的类信息。 ... [详细]
  • 本文详细介绍了如何通过配置 Chrome 和 VS Code 来实现对 Vue 项目的高效调试。步骤包括启用 Chrome 的远程调试功能、安装 VS Code 插件以及正确配置 launch.json 文件。 ... [详细]
  • 本文探讨了SQLAlchemy ORM框架中如何利用外键和关系(relationship)来建立表间联系,简化复杂的查询操作。通过示例代码详细解释了relationship的定义、使用方法及其与外键的相互作用。 ... [详细]
  • MVC框架下使用DataGrid实现时间筛选与枚举填充
    本文介绍如何在ASP.NET MVC项目中利用DataGrid组件增强搜索功能,具体包括使用jQuery UI的DatePicker插件添加时间筛选条件,并通过枚举数据填充下拉列表。 ... [详细]
  • 深入解析Android Activity生命周期
    本文详细探讨了Android中Activity的生命周期,通过实例代码和详细的步骤说明,帮助开发者更好地理解和掌握Activity各个阶段的行为。 ... [详细]
  • 本文章利用header()函数来实现页面跳,我们介绍到404,302,301等状态跳转哦,下面有很多的状态自定的函数有需要的同学可以测试一下。heade ... [详细]
  • 深入探讨Web服务器与动态语言的交互机制:CGI、FastCGI与PHP-FPM
    本文详细解析了Web服务器(如Apache、Nginx等)与动态语言(如PHP)之间通过CGI、FastCGI及PHP-FPM进行交互的具体过程,旨在帮助开发者更好地理解这些技术背后的原理。 ... [详细]
  • 转自:http:blog.sina.com.cnsblog_67419c420100vmkt.html 1.为什么要使用blocks将一个blocks作为函数或者方法的参数传递,可 ... [详细]
  • 题目描述墨墨购买了一套N支彩色画笔(其中有些颜色可能相同),摆成一排,你需要回答墨墨的提问。墨墨会像你发布如下指令ÿ ... [详细]
  • HDU1085 捕获本·拉登!
    问题描述众所周知,本·拉登是一位臭名昭著的恐怖分子,他已失踪多年。但最近有报道称,他藏匿在中国杭州!虽然他躲在杭州的一个洞穴中不敢外出,但近年来他因无聊而沉迷于数学问题,并声称如果有人能解出他的题目,他就自首。 ... [详细]
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社区 版权所有