C 用rabin-karp算法对文件进行切片

C 用rabin-karp算法对文件进行切片,c,algorithm,rabin-karp,C,Algorithm,Rabin Karp,我已经编写了一个c程序,它应该可以用。这是一个你可以找到的c#程序的改编 这似乎有效,但问题依然存在。平均块大小不是预期的大小 用法如下: 拉宾素数窗口大小边界标记文件 其中: Rabin是可执行文件的名称 素数是一个高素数。例如100007 WindowsSize是滚动窗口的大小。例如48 BoundaryMarker是指纹中设置为0的位数 File是要处理的文件 如果我将BoundaryMarker设置为13,我希望平均块大小为8K。 事实上,它们都不在8K左右 我很难找出我的程序出了什么问

我已经编写了一个c程序,它应该可以用。这是一个你可以找到的c#程序的改编

这似乎有效,但问题依然存在。平均块大小不是预期的大小

用法如下:

拉宾素数窗口大小边界标记文件

其中:

Rabin是可执行文件的名称

素数是一个高素数。例如100007

WindowsSize是滚动窗口的大小。例如48

BoundaryMarker是指纹中设置为0的位数

File是要处理的文件

如果我将BoundaryMarker设置为13,我希望平均块大小为8K。 事实上,它们都不在8K左右

我很难找出我的程序出了什么问题? 你能帮我吗

谢谢

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

unsigned char* buffer;
int windowSize;
int writePointer = 0;
int readPointer = 0;
int dataSize = 0;

unsigned char PushChar(unsigned char c)

{ if (++writePointer >= windowSize) writePointer=0;
  buffer[writePointer]=c;
  dataSize++;
  return(c);
}

unsigned char PopChar(void)

{ if (++readPointer >= windowSize) readPointer=0;
  dataSize--;
  return(buffer[readPointer]);
}


int main(int argc, char *argv[])

{ int fd;
  unsigned char c;

  unsigned long Q;
  unsigned long D=256;
  unsigned long pow=1;
  int i,k,boundary,boundaryMarker,index;
  unsigned char s; 

  if (argc != 5) 
  { printf("\nUsage : rabin Prime WindowSize BoundaryMarker File\n\nwhere :\n");
    printf("Prime is a high prime number. For instance 100007\n\n");
    printf("WindowSize is the size of rolling window. For instance 48\n\n");
    printf("BoundaryMarker is the number of bits set to 0 in a fingerprint\n\n");
    printf("File is the file to process\n\n");
    return(1);
  }

  sscanf(argv[1],"%lu",&Q);
  sscanf(argv[2],"%d",&windowSize);
  sscanf(argv[3],"%d",&boundaryMarker);

  for(i=1,boundary=1;i<=boundaryMarker;i++) boundary=boundary*2;
  boundary --;

  //printf("Q = %lu windowSize = %d boundary = %d\n",Q,windowSize,boundary);

  if ((buffer=(unsigned char*) malloc (sizeof(unsigned char)*windowSize))==NULL) return(1);

  for (k=1; k < windowSize; k++) pow=(pow*D)%Q;
  //printf("pow value %lu\n",pow);

  unsigned long sig=0;
  int lastIndex=0;

  if ((fd=open(argv[4],O_RDONLY))<0) exit(1);

  for (i=0; i <windowSize; i++)
  { read(fd,&c,1);
    PushChar(c);
    sig=(sig*D + (unsigned long)c) %Q;
  }

  //printf("sig value = %lu\n",sig);

  index=0; lastIndex=0;

  while (read(fd,&c,1))
  { 
    s=PopChar();
    //printf("sig = ( %lu + %lu - %lu * %lu %% %lu ) %lu",sig,Q,pow,(unsigned long) s,Q,Q);
    sig = (sig + Q - pow*(unsigned long)s%Q)%Q;
    //printf(" = %lu\n",sig);
    s=PushChar(c);
    //printf("sig2 = ( %lu * %lu + %lu ) %% %lu",sig,D,(unsigned long) s,Q);
    sig = (sig*D + (unsigned long)s)%Q;
    //printf(" = %lu\n",sig);
    index++;
    if ((sig & boundary )==0)
       { if (index - lastIndex >= 2048)
         { printf("sig & boundary = %lu & %lu Index=%d chunk size=%d\n",sig,boundary,index,index-lastIndex);
           lastIndex=index;
     }
       }
    else if (index -lastIndex >=65536)
            { printf("sig & boundary = %lu & %lu Index=%d chunk size=%d\n",sig,boundary,index,index-lastIndex);
              lastIndex=index;
            }
  }
  printf("Index=%d chunk size=%d\n",index,index-lastIndex);

  close(fd);
  return 1;
}
#包括
#包括
#包括
#包括
无符号字符*缓冲区;
int窗口大小;
int writepoint=0;
int readPointer=0;
int-dataSize=0;
无符号字符PushChar(无符号字符c)
{如果(++writePointer>=WindowsSize)writePointer=0;
缓冲区[writePointer]=c;
dataSize++;
返回(c);
}
无符号字符PopChar(void)
{如果(++readPointer>=windowSize)readPointer=0;
数据大小--;
返回(缓冲区[readPointer]);
}
int main(int argc,char*argv[])
{int-fd;
无符号字符c;
无符号长Q;
无符号长D=256;
无符号长功率=1;
int i,k,边界,边界标记,索引;
无符号字符;
如果(argc!=5)
{printf(“\n用法:rabin Prime WindowsSize边界标记文件\n\n此处:\n”);
printf(“素数是一个高素数。例如100007\n\n”);
printf(“WindowSize是滚动窗口的大小。例如48\n\n”);
printf(“BoundaryMarker是指纹中设置为0的位数\n\n”);
printf(“文件是要处理的文件\n\n”);
申报表(1);
}
sscanf(argv[1],“%lu”,&Q);
sscanf(argv[2]、“%d”和窗口大小);
sscanf(argv[3]、“%d”、&boundaryMarker);

对于(i=1,boundary=1;i您可以尝试更新BoundaryMarker值,您可以获得不同的长度。我使用RB的方式:。我认为长度实际上取决于内容。

在BoundaryMarker=13的情况下,在一兆字节的随机数据上运行代码,得到了104个块,平均块大小为10082字节。这与t相差不远他预计是8192人

但是,较小的BoundaryMarker值显示出更明显的偏差;例如,将其设置为10,则得到的平均块大小为3049字节,与预期的1024字节相差甚远。而将BoundaryMarker设置为5则得到的平均块大小为2077字节,远未达到预期的32字节

仔细查看您的代码,这种偏差的明显原因在于以下代码(为清晰起见,重新格式化):

if(index-lastIndex>=2048)
抑制距离前一个边界小于2048字节的块边界,有效地将小于2048字节的块与下一个块合并。
else if(index-lastIndex>=65536)
check同时强制使用人工块边界,以防止任何块的长度超过65536字节

如果此行为(强制所有块至少为2048,最多为65536字节)不是您想要的,您可以简单地删除这些检查,将代码简化为:

if ((sig & boundary ) == 0)
{ printf("sig & boundary = %lu & %lu Index=%d chunk size=%d\n",sig,boundary,index,index-lastIndex);
  lastIndex=index;
}
实际上,对于BoundaryMarker=n,进行此更改会产生非常接近2n字节的平均块大小,至少对于n≤ 12个左右

对于n=13,似乎确实存在明显的向下偏差,我怀疑这是由于质数100007仅为边界模213的12.2倍。由于签名值或多或少是随机分布的,模质数,额外的0.2导致它们略微偏向较小的值(包括零)当进一步降低模213时


通过使用较大的素数(如231),可以很容易地固定该偏差−1=2147483647。事实上,切换到此素数会使平均块大小更接近8192。

您可以使用调试器逐步检查代码,并关注变量及其值。这可能会帮助您找到问题。两个程序(c和c#给出相同的结果).我认为这是一个算法问题。这个算法看起来像sedgewick rabin karp的实现。我不知道问题出在哪里。
if ((sig & boundary ) == 0)
{ printf("sig & boundary = %lu & %lu Index=%d chunk size=%d\n",sig,boundary,index,index-lastIndex);
  lastIndex=index;
}