如何解决将质数表示为 C 中的连续位数组
我正在尝试创建一个非常大的位数组,其中位在内存中的位置是数字,位的值(0 或 1)是该数字的状态(质数/非质数)。我是这样尝试的:
#define SIZE 2
int* A = calloc(SIZE,4);
//retrieve the state of a number (True if not prime,false if prime)
if(A[0] & (1 << 0)){} //will give me the state for 0
if(A[0] & (1 << 1)){} //will give me the state for 1
if(A[0] & (1 << 2)){} //will give me the state for 2
if(A[0] & (1 << 7)){} //will give me the state for 7
if(A[0] & (1 << 8)){} //will give me the state for 8
if(A[0] & (1 << 31)){} //will give me the state for 31
//Now can I do this??
if(A[0] & (1 << 32)){} //will give me the state for 32
//Instead of doing this??
if(A[1] & (1 << 0)){} //will also give me the state for 32
//Ultimately
if(A[0] & (1 << n)){} //will give me the n-th bit of my continuous block of memory??
我想避免索引,因为这需要我使用除法和取模之类的东西。我的问题是我是否能够使用位移操作访问数组的下一个元素的位?并最终改变它们?
A[0] = A[0] | (1 << n);
这是我的完整代码:
/*
*
* @author Matthew Pecko
* 12/29/2020
*
* Seive of Eratosthenes in C
*
* Define MIN as 0,and MAX to be the upper bound
* of the prime range (in decimal)
*
* Define diff as (max - min) + 1
*
* The number of bytes we will need can be found:
* numberOfBytes = diff/32
* trueNumber = ceil(numberOfBytes)
*
* Calulate the true number of bytes and define it as SIZE
*
* A number's state can be retrieved:
* state[0] & (1 << 0) -- will get state for 0
* state[0] & (1 << 1) -- will get state for 1
* state[0] & (1 << 2) -- will get state for 2
* state[0] & (1 << n) -- will get state for n
*
*
*
* We want to seive the range from [0,sqrt(diff)]
* we will stick with [0,diff] for now
*
*/
#include "stdlib.h"
#include "stdio.h"
#define MIN 2
#define MAX 70
#define SIZE 1
void print(int* a);
int main(){
//int* state = calloc(SIZE,4);
int* state = malloc(sizeof(int)*SIZE);
int i,j,counter;
for(i = 0; i < SIZE; ++i) state[i] = 0;
i = 2;
while(i<=MAX){
//printf("ADEBUG i: %d \n",i);
if(!(state[0] & (1 << i))){
j = i*i;
//printf("DEBUG i: %d \n",i);
//printf("DEBUG j: %d \n",j);
counter = 0;
while(j <= MAX+1){
state[0] = state[0] | (1 << (j));
counter++;
printf("number I am on: %d \n",i);
printf("multiple: %d \n",counter);
printf("number to toggle (j): %d \n",j);
j = (i*i) + counter*i;
}
}
printf("STEP: %d RESULT--------------------------- \n",i);
print(state);
i++;
}
printf("\n\n\n\n\n\n");
printf("RESULT--------------------------- \n");
print(state);
}
void print(int* a){
int i;
i = 2;
do{
if(!(a[0] & (1 << i))){
printf("The state of %d is: \t true \n",i);
}else{
printf("The state of %d is: \t false \n",i);
}
i++;
}while(i <= MAX);
}
我知道 malloc() 和 calloc() 之间存在一些差异,所以我尝试同时使用两者:
int* state = malloc(sizeof(int)*SIZE);
for(i = 0; i < SIZE; ++i) state[i] = 0;
和
int* state = calloc(SIZE,4);
我相信我的问题在于我无法仅使用位移操作访问连续的内存块,或者我使用 gcc 并且它可能使用小端位表示的事实。我真的很想避免使用除法和取模来查找 state[index] 的索引,但是我可以尝试这样做,然后尝试将其更改为 bitshift left 操作,因为我相信我只会除以可以为的数字表示为 2^n。
解决方法
不要害怕使用常量操作数(如x % 8
)进行模运算。
任何现代编译器都会将其优化为按位并使用掩码。
见https://godbolt.org/z/ehjMbo
我建议使用长固定大小的无符号整数类型,例如 uint64_t
中的 stdint.h
。如果您使用 32 位机器,请使用 uint32_t
。
请勿使用 int
,因为它具有特定于实现的大小以及由于 1<<32
甚至 1 << 31
之类的溢出而导致未定义行为的风险。
int limit = ...;
uint64_t *data = calloc((limit + 63) / 64,sizeof *data);
// reading bit X
bool bitX = (data[X / 64u] >> (X % 64u)) & 1;
// setting bit Y
data[Y / 64u] |= (1ull << (Y % 64u));
64u
用于强制将 X
提升为无符号类型,以便使用最佳除法算法。
如果您要操作单个位,那么您应该习惯于使用按位运算来进行移位和屏蔽,而不是使用 /
和 %
。
正如@tstanisl 所指出的,您应该使用固定大小的数据类型而不是 int
,如果您不将符号位视为符号,则使用无符号类型会更清晰一些。>
对于 32=bit 字,例如:
static inline void setBit(uint32_t *data,size_t bitIndex)
{
data[bitIndex>>5] |= ((uint32_t)1) << (bitIndex&31);
}
static inline void clearBit(uint32_t *data,size_t bitIndex)
{
data[bitIndex>>5] &= ~(((uint32_t)1) << (bitIndex&31));
}
static inline bool getBit(uint32_t *data,size_t bitIndex)
{
return (bool)((data[bitIndex>>5] >> (bitIndex&31)) & 1);
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。