⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 randtest.c

📁 随机数算法
💻 C
字号:
/* randtest.c : Defines the entry point for the console application.
//
//
//	RANDTEST is a command-line program.  It is designed so that it can be executed
//	from a batch file.  It requires the name of an input file and the word size
//	(in bits) to be used during the analysis.  If the input file is supplied on the
//	command line, it must be the first argument.  If not, it will be requested.
//	The word size may be specified on the command line using the -wNN option.
//	If it is not specified, it will be requested.
/*
	This file originally written by John Hadstate  
	Modified by Mike Rosing on and after October 19, 2001
		added fixed ram for data block and a subroutine to 
		access it as binary.
		added -x option for binary input file (for rank test)

		added -r option for binary matrix rank test (Nov 10, 2001)
		added -m option for monobits frequency test (Nov 14, 2001)
                added -l option for longest run of ones test (Jan 2, 2002)
                      This includes bigfloat package for computing probability
		      tables to high accuracy for low runs.
*/
#include "randtest.h"
#include "bigfloat.h"

#define MAXRAMSIZE 16*1024*1024

int nByteMask[BITS_PER_BYTE] =
{
	0x00000001, 0x00000002, 0x00000004, 0x00000008,
	0x00000010, 0x00000020, 0x00000040, 0x00000080
};

unsigned char rawbits[MAXRAMSIZE];

int main(int argc, char* argv[])
{
	FILE		*fpInput = NULL;

	int			nBitNumber = (-1),
				nWordSize = (-1);
	int 		i;
	char		*pc = NULL;
	char		strOptions[1024];
	char		strInputFile[1024];

	bool		bAnalyzeAllBits = false;
	bool		bNumericAnalysis = false;
	bool            dorank = false;
	bool            domono = false;
	bool            dofreq = false;
	bool            doruns = false;
	bool            dolongs = false;

	int		nBytes;
	SRCPTR	        bitBlockltl, bitBlockbig;
	int		rankvalue, ii, rankstart;
	int             error;
	double          chi, pvalue;
	int             monowidth;
	int             numPs, numBlocks;
	int             longRunBlocks, tblsz;

	CHIENTRY       ctbl[21];
	FLOAT          test;

/*  initialize floating point package  */

	init_float();

/*	BuildChiTable( 8, ctbl);
	printf("M = 8\n");
	for( i=0; i<8; i++)
	  printf("ctbl[%d].class = %d  .prob = %e\n",i, ctbl[i].class, ctbl[i].prob);
	printf("\n");

	printf("M = 128\n");
	BuildChiTable( 128, ctbl);
	i = 0;
	for( i=0; i<21; i++)
	  printf("ctbl[%d].class = %d  .prob = %e\n",i, ctbl[i].class, ctbl[i].prob);
	printf("\n");
/*
	BuildChiTable( 512, ctbl);
	for( i=0; i<21; i++)
	  printf("ctbl[%d].class = %d  .prob = %e\n",i, ctbl[i].class, ctbl[i].prob);

	exit(0);       
/*
	First, concatenate all the command-line options that are
	prefixed with a '-' and convert them to lower case.
	We are pretty sure these cannot be the Input File name
	and, in any case, the Input File name may not start with
	a '-' (our restriction).
*/
	strOptions[0] = NUL;

	for (i = 1; i < argc; i++)
	{
		if (*argv[i] == '-') SAFECAT(strOptions, argv[i]);
	}

	for (i = 0; strOptions[i] != 0; i++) strOptions[i] = tolower(strOptions[i]);
/*
	Now go find the first command-line option that does not begin with
	a '-'.  Accept this as the Input File name.
*/
	strInputFile[0] = NUL;

	for (i = 1; i < argc; i++)
	{
		if (*argv[i] != '-')
		{
//			SAFECOPY(strInputFile, argv[1]);  I think this is a bug!! (MGR)
			SAFECOPY(strInputFile, argv[i]);
			break;
		}
	}
/*
	If the Input File name has not been specified, we've got to
	prompt for it interactively.  We're going to read from stdin
	to allow one last bit of hacking: stdin could be redirected to
	a file containing the Input File name and other required
	parameters.
*/

	if (strInputFile[0] == NUL)
	{
		fputs("\nName of input file: ", stdout);
		fscanf(stdin, " %1023s", strInputFile);
	}
/*
	If the word size of the random number stream has not been specified,
	we've got to prompt for it interactively.
*/
	if ((pc = strstr(strOptions, "-w")) == NULL)
	{
		fputs("\nWord size (in bits): ", stdout);
		fscanf(stdin, " %d", &nWordSize);
	}
	else
	{
		if (sscanf(pc, " -w%d", &nWordSize) != 1)
		{
			fprintf(stdout, "\n-w Option Specification Invalid: %s\n", pc);

			return (1);
		}
	}
/*
	If there are no command line options specified,
	we need to prompt for numeric or bitwise analysis.
*/
	if (strOptions[0] == NUL)
	{
		char		cTemp;

		fputs("\nNumeric (n) or Bitwise (b) analysis? ", stdout);
		fscanf(stdin, " %c", &cTemp);
		cTemp = tolower(cTemp);

		if (cTemp == 'n')
		{
			SAFECOPY(strOptions, "-n");
		}
		else if (cTemp == 'b')
		{

			fputs("\nWhich bit (-1 for ALL): ", stdout);
			fscanf(stdin, " %d", &nBitNumber);

			if (nBitNumber >= 0)
			{
				sprintf(strOptions, "-b%d", nBitNumber);
			}
		}
	}
/*
	If the -n option is specified, we don't need the -b option.  If the
	-b option is needed but not specified, it means run the analysis once
	on each bit in the word.
*/
	if ((pc = strstr(strOptions, "-n")) != NULL)
	{
		if ((pc = strstr(strOptions, "-b")) != NULL)
		{
			fprintf(stdout, "\n-n Option conflicts with -b Option: %s\n", strOptions);

			return (1);
		}

		bNumericAnalysis = true;
	}
	else
	{
		bNumericAnalysis = false;
	/*
		If the bit number in the words of the random number stream has not been specified,
		we assume that they want to analyze all bits.
	*/
		if ((pc = strstr(strOptions, "-b")) != NULL)
		{
			if (sscanf(pc, " -b%d", &nBitNumber) != 1)
			{
				fprintf(stdout, "\n-b Option Specification Invalid: %s\n", pc);

				return (1);
			}

			bAnalyzeAllBits = false;
		}
		else
		{
			bAnalyzeAllBits = true;
		}
	}
/*
	Word Size must be greater than 0 bits.  For numeric analysis, word size
	must be less than or equal to 32 bits.
*/
	if ((nWordSize <= 0) || (bNumericAnalysis && (32 < nWordSize)))
	{
		fprintf(stdout, "\n-w Option Size Invalid: %d\n", nWordSize);

		return (1);
	}
/*
	If Bit Number is required, it must be between 0 and (N-1) where N
	is the number of bits in a word.
*/
	if (!bNumericAnalysis && !bAnalyzeAllBits)
	{
		if ((nBitNumber < 0) || (nWordSize <= nBitNumber))
		{
			fprintf(stdout, "\n-b Option Bit Number Invalid: %d\n", nBitNumber);

			return (1);
		}
	}

	if ((fpInput = fopen(strInputFile, "r")) == NULL)
	{
		char	strErrorMessage[1024];

		sprintf(strErrorMessage, "\nUnable to open %s", strInputFile);
		perror(strErrorMessage);

		return (2);
	}

/*  Read up to max buffer size of data.  We can loop on this if file is
	bigger, or increase buffer size.  Ram is cheap nowadays!!
*/
	if( ( pc = strstr( strOptions, "-x") ) != NULL)
	{
		nBytes = fread( rawbits, 1, MAXRAMSIZE, fpInput);
		bitBlockltl.byteptr = rawbits;
		bitBlockltl.bitpos = 0;  // little endian, least significant bit
		bitBlockbig.byteptr = rawbits;
		bitBlockbig.bitpos = 7;  // big endian, most significant bit
	}

/*  if rank test specified, get starting matrix dimension.
    Test loops over data block going from starting dimension up to
    maximum word size.
*/
	if( (pc = strstr( strOptions, "-r") ) != NULL)
	{
	  if (sscanf(pc, " -r%d", &rankstart) != 1) 
	  {
	    fprintf(stdout, "\ninvalid parameter for rank matrix probabilities\n");
	    return(3);
	  }
	  dorank = true;
	}

/*  if monobits test specified, get number of bits in block to test.
    does as many blocks as possible with raw data.
*/
	if( (pc = strstr( strOptions, "-m") ) != NULL)
	{
	  if (sscanf(pc, " -m%d", &monowidth) != 1) 
	  {
	    fprintf(stdout, "\ninvalid parameter for monobits frequency test\n");
	    return(4);
	  }
	  domono = true;
	}

/*  if frequency test specified, get number of p-values to generate.
    does as many blocks as possible with raw data, assuming that nWordSize
    is bits per block.  Number of bits is assumed to be 8*nBytes, so number
    of bits to work with is 8*nBytes/(number of p-values)(=N in NIST docs)
    and number of trials within that is determined by nWordSize (=M in 
    NIST docs).
*/
	if( (pc = strstr( strOptions, "-f") ) != NULL)
	{
	  if (sscanf(pc, " -f%d", &numPs) != 1) 
	  {
	    fprintf(stdout, "\ninvalid parameter for frequency test within a block\n");
	    return(4);
	  }
	  dofreq = true;
	}

/*  if runs test specified, get number of p-values to generate.
    Does as many blocks as possible assuming number of bits is 8*nBytes.
*/
	if( (pc = strstr( strOptions, "-u") ) != NULL)
	{
	  if (sscanf(pc, " -u%d", &numPs) != 1) 
	  {
	    fprintf(stdout, "\ninvalid parameter for frequency test within a block\n");
	    return(4);
	  }
	  doruns = true;
	}

/*  if longest runs test specified, get number of p-values to generate.
    Does as many blocks as possible assuming number of bits is 8*nBytes.
*/
	if( (pc = strstr( strOptions, "-l") ) != NULL)
	{
	  if (sscanf(pc, " -l%d", &longRunBlocks) != 1) 
	  {
	    fprintf(stdout, "\ninvalid parameter for frequency test within a block\n");
	    return(5);
	  }
	  dolongs = true;
	}

// need to merge both methods.  Rank test assumes binary data already
// internal.  compare running times and simplicity, but merge both methods.		

	if (bNumericAnalysis)
	{
	//	AnalyzeNumeric(fpInput, nWordSize);
	}
	else
	{
	  if (bAnalyzeAllBits)
	  {
	    if (dorank)
	    {
	      for (ii = rankstart; ii <= nWordSize; ii++)
	      {
		
/*  test matrix rank code  */

		printf("\ndimension = %d\n", ii);
		error = ranktest( bitBlockltl, LITTLENDIAN, ii, 8*nBytes/ii/ii,
				  &chi, &pvalue);
		if( error < 0) printf("Error computing little endian binary rank test.\n");
		else printf("Little endian chi^2 = %f,  p-value = %f\n", chi, pvalue);
		error = ranktest( bitBlockbig, BIGENDIAN, ii, 8*nBytes/ii/ii,
				  &chi, &pvalue);
		if( error < 0) printf("Error computing big endian binary rank test.\n");
		else printf("Big endian chi^2 = %f,  p-value = %f\n", chi, pvalue);
	      }
	    }
	    if (domono)
	    {
	      ii = nBytes*8/monowidth;
	      for( i=0; i<ii; i++)
	      {
		chi = monobits( &bitBlockltl, monowidth);
		printf("block %d gives p-value %f\n", i, chi);
	      }
	    }
	    if (dofreq)
	    {
      /* reset source pointers */

	      bitBlockltl.byteptr = rawbits;
	      bitBlockltl.bitpos = 0;  // little endian, least significant bit
	      bitBlockbig.byteptr = rawbits;
	      bitBlockbig.bitpos = 7;  // big endian, most significant bit
	      numBlocks = 8*nBytes/numPs/nWordSize;
	      printf("numblocks = %d\n", numBlocks);
	      for( i=0; i<numPs; i++)
	      {
		chi = freqtest( &bitBlockltl, LITTLENDIAN, nWordSize, numBlocks);
		pvalue = chisqr( chi, numBlocks);
		printf("frequency test little endian chi^2 = %f, p-value = %f\n", 
		       chi, pvalue);
		chi = freqtest( &bitBlockbig, BIGENDIAN, nWordSize, numBlocks);
		pvalue = chisqr( chi, numBlocks);
		printf("frequency test big endian chi^2 = %f, p-value = %f\n", 
		       chi, pvalue);
	      }
	    }
	    if( doruns)
	    {
	      bitBlockltl.byteptr = rawbits;
	      bitBlockltl.bitpos = 0;  // little endian, least significant bit
	      bitBlockbig.byteptr = rawbits;
	      bitBlockbig.bitpos = 7;  // big endian, most significant bit
	      numBlocks = 8*nBytes/numPs;
	      printf("number of bits = %d\n", numBlocks);
	      for( i=0; i<numPs; i++)
	      {
		pvalue = runs( &bitBlockltl, LITTLENDIAN, numBlocks );
		printf("runs test little endian p-value = %f\n",  pvalue);
		pvalue = runs( &bitBlockbig, BIGENDIAN, numBlocks);
		printf("runs test big endian p-value = %f\n", pvalue);
	      }
	    }
	    if( dolongs)
	    {
	      bitBlockltl.byteptr = rawbits;
	      bitBlockltl.bitpos = 0;  // little endian, least significant bit
	      bitBlockbig.byteptr = rawbits;
	      bitBlockbig.bitpos = 7;  // big endian, most significant bit
	      printf("WARNING: large block sizes may take a very long time to simply\n");
	      printf("         compute the probability table!\n");
	      printf("  Building table for %d blocksize... ", nWordSize);
	      BuildChiTable( nWordSize, ctbl );
	      printf("\n");
	      if( nWordSize < 21) tblsz = nWordSize;
	      else tblsz = 21;
	      pvalue = longrun( &bitBlockltl, LITTLENDIAN, nWordSize, longRunBlocks, 
		ctbl, tblsz);
	      printf("Little endian p-value = %f\n", pvalue);
	      pvalue = longrun( &bitBlockbig, BIGENDIAN, nWordSize, longRunBlocks,
				ctbl, tblsz);
	      printf("Big endian p-value = %f\n", pvalue);
	    }
	    else
	    {
//		AnalyzeBitStream(fpInput, nWordSize, ii);
	    }
	  }
	  else
	  {
	    //	AnalyzeBitStream(fpInput, nWordSize, nBitNumber);
	  }
	}

	fclose(fpInput);
	
	return 0;
}
/*

  int FillBitStreamBuffer(BITSTREAM *bp)

  This function reads a pair of hex digits from the input data stream
  into a byte buffer.

  Function Returns:

  0 == Success.
  Anything else, some kind of I/O or data error

*/
int	FillBitStreamBuffer(BITSTREAM *bp)
{
	if (bp->nError == 0)
	{
		int		nFileChar;

		if (fscanf(bp->fp, " %2x", &nFileChar) == 1)
		{
			bp->ucByteBuf = (unsigned char) nFileChar;
		}
		else if ((bp->nError = ferror(bp->fp)) == 0)
		{
			bp->nError = (-1);
		}
	}

	return bp->nError;
}
/*

  int ResetBitStream(BITSTREAM *bp)

  This function resets the file pointer to the beginning
  of the file, reads the first byte into a buffer and

  Function returns:

  0 == Success
  Anything else, some kind of I/O error.

*/

int ResetBitStream(BITSTREAM *bp)
{
	if (bp->fp != NULL)
	{
		bp->nError = fseek(bp->fp, 0L, SEEK_SET);

		if (bp->nError == 0)
		{
			FillBitStreamBuffer(bp);
		}

		bp->nPrevBit = bp->nBitNumber - bp->nWordSize;
	}
	else
	{
		bp->nError = (-1);
	}

	return bp->nError;
}

/*

  int InitBitStream(BITSTREAM *bp, FILE *fp, int nWordSize)

  This function initializes a BITSTREAM object.

  Function returns:

  0 == Success
  Anything else, some kind of I/O error.

*/

int	InitBitStream(BITSTREAM *bp, FILE *fp, int nWordSize, int nBitNumber)
{
	bp->fp = fp;
	bp->nBitNumber = nBitNumber;
	bp->nWordSize = nWordSize;

	return ResetBitStream(bp);
}

/*

  int GetNextBit(BITSTREAM *bp)

  The function returns the next bit in a stream of bits
  from the specified input file.

  Function Returns:

  0  == The bit is zero
  1  == The bit is one
  -1 == Some kind of I/O or data error

*/

int GetNextBit(BITSTREAM *bp)
{
	int		nRet = (-1);

	if (bp->fp != NULL)
	{
		if (bp->nError == 0)
		{
			int		nBitNum = bp->nPrevBit + bp->nWordSize;
			int		nSkipBytes = nBitNum / BITS_PER_BYTE;
			int		nNextBit = nBitNum % BITS_PER_BYTE;

			while ((nSkipBytes > 0) && (bp->nError == 0))
			{
				if (FillBitStreamBuffer(bp) == 0)
				{
					nSkipBytes -= 1;
				}
			}

			if (bp->nError == 0)
			{
				nRet = (((int) bp->ucByteBuf & nByteMask[nNextBit]) == 0) ? 0 : 1;
				bp->nPrevBit = nNextBit;
			}
		}
	}

	return nRet;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -