[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: verification of randomness



[email protected] (Andreas Bogk) writes:
> I've built a random number generator based on the noise of a Zener
> diode. Now I'd like to verify it's correct operation. I'd be very
> grateful if someone could point me to existing software for randomness
> tests or additional tests not mentioned in Knuth.

Dear Andreas,

Here are a couple of tests:

1. Maurer's test (very good, published later than Knuth)

/************************************************************

Ueli Maurer's randomness test
(C) 1993 Dimitri Vulis, all rights reserved

For details, see:
Ueli M. Maurer. ``A Universal Statistical Test for Random Bit
Generators.'' {\em Journal of Cryptology,\/} {\bf5} (1992), pp.~89--105.

*************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

void rndinit(void);
unsigned char rndgetbyte(void);

/*

We produce a stream of random bits. We look at them in blocks of L
bits at a time. Maurer uses 8-bit bytes  s_n, recommends 6 <= L <= 16.

*/

#define L 8
/* 2**L */
#define vv 256

int main(void) {
/*
the count of s_n's random bytes
*/
long n=1;
/*
fTU is the average \log_2(a_n),
where a_n is the number of bytes since the previous occurrence of the
same value. a_n = n for first occurrence (hopefully skipped using Q below)
*/
double fTU=0.0;
/*
Every time we obtain a random byte, we save its position n here,
so we can computer a_n, the number of bytes since last occurence
*/
static long lastseen[vv];
/*
the number of bytes to skip before computing
compute the average, hoping that all possible byte values will
occur and lastseen will be non-zero. M recommends Q >= 10 * 2**L.
*/
long Q;
/*
the number of bytes to use to compute fTU.
M recommends K as large as possible >= 1000 * 2**L
*/
long K;
/*
E(L) is the expected value of fTU for a truly random sequence
*/
#define E 7.1836656
/*
V(L) is the variance of a_n for a truly random sequence (from M; table below)
*/
#define V 3.238
/*
If you decide to change L:
L       E               V
6       5.2177052       2.954
7       6.1962507       3.125
8       7.1836656       3.238
9       8.1764248       3.311
10      9.1723243       3.356
11      10.170032       3.384
12      11.168765       3.401
13      12.168070       3.410
14      13.167693       3.416
15      14.167488       3.419
16      15.167379       3.421
*/
/*
c(L,K) from M (13)
*/
double C;
/*
standard deviation of a truly random sequence from M (14)
*/
double sigma;
/*
fTU's distance in sigmas from the expected value
*/
double y;
/*
rho is the rejection rate, the probability that a sequence is bad
*/
double rho;

unsigned char r;

printf("Enter Q>=%-7ld:",10L*vv);   fflush(stdout); scanf("%ld",&Q);
printf("Enter K>=%-7ld:",1000L*vv); fflush(stdout); scanf("%ld",&K);

C=0.7-0.8/L+(1.6+12.8/L)*pow(K,-4.0/L); /* (13) */
/* M: C close to 0.6 for L=8 */
sigma=C*pow(V/K,0.5);           /* (14) */
/* M: grows as 1/\sqrt{K} */

/* initialize lastseen to 0 */
memset((void*)lastseen,0,sizeof(lastseen));

rndinit();

for (; n<Q+K; n++) {
 r=rndgetbyte();
 if (n>Q)
  fTU+=log((double)(n-lastseen[r]));
 lastseen[r]=n;
 }

/* compute the average and convert from natural log to log_2 */
fTU/=K*log(2.0);
y=fabs((fTU-E)/sigma);

rho=erf(-y/sqrt(2.0))+1;

printf("fTU=%lg, %lg*%lg from  e.v. %lg, rho=%lg --- %s\n",
fTU,y,sigma,E,rho,
(rho < 0.0001 ? "unacceptable" :
(rho < 0.001 ?  "marginal" :
"acceptable")));

return(0);
}

/*
Use C library's pseudo-random number generator
*/

void rndinit(void)
{
srand(1);
}

unsigned char rndgetbyte(void) {
static unsigned state=0;
static int rrr;

if (state^=1) {
 rrr=rand();
 return(unsigned char)(rrr & 0xff);
 }
else
 return(unsigned char)((rrr>>8) & 0xff);
}

2. You probably have this one:

/* ***************************************************************
 * chi.c --
 *
 * Copyright 1993 Peter K. Boucher
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies.
 *
 * Usage:  chi [input_file [output_file]]
 *
 * This program counts the occurances of each character in a file
 * and notifies the user when a the distribution is too ragged or
 * too uniform.
 *
 * Because the chance of getting byte B after byte A should be 1:256
 * (for all A's and B's), the program also checks that the successors
 * to each byte are randomly distributed.  This means that for each byte
 * value (0 - 255) that occurs in the text, a count is kept of the
 * byte value that followed in the text, and the frequency distribution
 * of these succeeding bytes is also checked.
 *
 */

#include <stdio.h>

#define NUM_BYTES 256L
#define BUFSIZE 8192
#define min_nps 5.0
#define min_testable (NUM_BYTES*min_nps)

#define V01     (205.33) /*  1% chance it's less */
#define V05     (219.09) /*  5% chance it's less */
#define V25     (239.39) /* 25% chance it's less */
#define V50     (254.33) /* 50% chance it's less */
#define V75     (269.88) /* 75% chance it's less */
#define V95     (293.16) /* 95% chance it's less */
#define V99     (310.57) /* 99% chance it's less */

#define min_chichi5 (20.0*min_nps) /* min prob. 5% */
#define min_chichi3 (4.0*min_nps) /* min prob. 25% */

#ifdef DEBUG
#define CFNAME "chi.dat"
#define min_chichi7 (100.0*min_nps) /* min prob. 1% */
#endif

#define AB(X)  (((X) >= 0.0) ? (X) : -(X))

double cnt[NUM_BYTES] = {0.0}; /* should be all zeros. */
double successors[NUM_BYTES][NUM_BYTES] = {{0.0}}; /* should be all zeros. */

static unsigned char buf[BUFSIZE];
static FILE *ifp, *ofp;

FILE *
my_fopen(file, type)
char *file, *type;
{
  FILE *fp;

  if ((fp = fopen(file, type)) == NULL) {
      (void)fprintf(stderr, "Can't open '%s' for '%s'\n", file, type);
      exit(1);
  }
  return(fp);
}

double
get_V(n,Y)
double n;
double *Y;
{
#define k (256)
#define p (1.0/256.0)
    double sum = 0.0;
    double divider = (n*p);
    double tmp;
    long i;

    for (i=0; i<k; i++) {
        tmp = Y[i]/divider;
        sum += (tmp*Y[i]);
    }
    return( sum - n );
}

double
chichi3(n,cgt_75,c50_75,c25_50,clt_25)
double  n,cgt_75,c50_75,c25_50,clt_25;
{
    double sum = (cgt_75*cgt_75)/(0.25*n);
    sum += (c50_75*c50_75)/(0.25*n);
    sum += (c25_50*c25_50)/(0.25*n);
    sum += (clt_25*clt_25)/(0.25*n);
    return( sum - n );
}

int
check_chichi3(n,cgt_75,c50_75,c25_50,clt_25)
double        n,cgt_75,c50_75,c25_50,clt_25;
{
#define C3_01 0.1148
#define C3_05 0.3518
#define C3_25 1.213
#define C3_75 4.108
#define C3_95 7.815
#define C3_99 11.34
    double V3;
    int check = 0;

    if (n < min_chichi3) {
        return( 0 );
    }
    if ((V3 = chichi3(n,cgt_75,c50_75,c25_50,clt_25)) > C3_75) {
        check++;
        if (V3 > C3_95) {
            check++;
            if (V3 > C3_99) {
                check++;
            }
        }
    } else if (V3 < C3_25) {
        check--;
        if (V3 < C3_05) {
            check--;
            if (V3 < C3_01) {
                check--;
            }
        }
    }
    return(check);
}

double
chichi5(n,cgt_95,c75_95,c50_75,c25_50,c05_25,clt_05)
double  n,cgt_95,c75_95,c50_75,c25_50,c05_25,clt_05;
{
    double sum = (cgt_95*cgt_95)/(0.05*n);
    sum += (c75_95*c75_95)/(0.20*n);
    sum += (c50_75*c50_75)/(0.25*n);
    sum += (c25_50*c25_50)/(0.25*n);
    sum += (c05_25*c05_25)/(0.20*n);
    sum += (clt_05*clt_05)/(0.05*n);
    return( sum - n );
}

int
check_chichi5(n,cgt_95,c75_95,c50_75,c25_50,c05_25,clt_05)
double        n,cgt_95,c75_95,c50_75,c25_50,c05_25,clt_05;
{
#define C5_01 0.5543
#define C5_05 1.1455
#define C5_25 2.675
#define C5_75 6.626
#define C5_95 11.07
#define C5_99 15.09
    double V5;
    int check = 0;

    if (n < min_chichi5) {
        return( check_chichi3(n,cgt_95+c75_95,c50_75,c25_50,c05_25+clt_05) );
    }
    if ((V5 = chichi5(n,cgt_95,c75_95,c50_75,c25_50,c05_25,clt_05)) > C5_75) {
        check++;
        if (V5 > C5_95) {
            check++;
            if (V5 > C5_99) {
                check++;
            }
        }
    } else if (V5 < C5_25) {
        check--;
        if (V5 < C5_05) {
            check--;
            if (V5 < C5_01) {
                check--;
            }
        }
    }
    return(check);
}

#ifdef DEBUG
double
chichi7(n,cgt_99,c95_99,c75_95,c50_75,c25_50,c05_25,c01_05,clt_01)
double        n,cgt_99,c95_99,c75_95,c50_75,c25_50,c05_25,c01_05,clt_01;
{
    double sum = (cgt_99*cgt_99)/(0.01*n);

    sum += (c95_99*c95_99)/(0.04*n);
    sum += (c75_95*c75_95)/(0.20*n);
    sum += (c50_75*c50_75)/(0.25*n);
    sum += (c25_50*c25_50)/(0.25*n);
    sum += (c05_25*c05_25)/(0.20*n);
    sum += (c01_05*c01_05)/(0.04*n);
    sum += (clt_01*clt_01)/(0.01*n);
    return( sum - n );
}

int
check_chichi7(n,cgt_99,c95_99,c75_95,c50_75,c25_50,c05_25,c01_05,clt_01)
double        n,cgt_99,c95_99,c75_95,c50_75,c25_50,c05_25,c01_05,clt_01;
{
#define C7_01 1.239
#define C7_05 2.167
#define C7_25 4.255
#define C7_75 9.037
#define C7_95 14.07
#define C7_99 18.48
    double V7;
    int check = 0;

    if (n < min_chichi7) {
        return( check_chichi5(n,cgt_99+c95_99,c75_95,c50_75,
                                c25_50,c05_25,c01_05+clt_01) );
    }
    if ((V7=chichi7(n,cgt_99,c95_99,c75_95,c50_75,
                      c25_50,c05_25,c01_05,clt_01)) > C7_75) {
        check++;
        if (V7 > C7_95) {
            check++;
            if (V7 > C7_99) {
                check++;
            }
        }
    } else if (V7 < C7_25) {
        check--;
        if (V7 < C7_05) {
            check--;
            if (V7 < C7_01) {
                check--;
            }
        }
    }
    return(check);
}
#endif

double
fill_arrays()
{
   double size=0.0;
   long ch,next,l,i;

   if ((ch = getc(ifp)) != EOF) { /* prime the pump */
       cnt[ch] = size = 1.0;
       while ((l = fread(buf, 1, BUFSIZE, ifp)) > 0) {
           for (i=0; i<l; i++) {
               size++;
               next = buf[i];
               cnt[next]++;
               successors[ch][next]++;
               ch = next;
           }
       }
   }
   fclose(ifp);
   return( size );
}

void
chi_2_test()
{
   long         i;
   double       suc_tests = 0.0;
   double       suc_highest = -1.0;
   double       suc_lowest = 1000000000.0;
   double       suc_gt_99 = 0.0;
   double       suc_95_99 = 0.0;
   double       suc_75_95 = 0.0;
   double       suc_50_75 = 0.0;
   double       suc_25_50 = 0.0;
   double       suc_05_25 = 0.0;
   double       suc_01_05 = 0.0;
   double       suc_lt_01 = 0.0;
   double       V;
   double       size;
   char         *desc = NULL;
#ifdef DEBUG
   double       tocc_tests = 0.0;
   double       tocc_highest = -1.0;
   double       tocc_lowest = 1000000000.0;
   double       tocc_gt_99 = 0.0;
   double       tocc_95_99 = 0.0;
   double       tocc_75_95 = 0.0;
   double       tocc_50_75 = 0.0;
   double       tocc_25_50 = 0.0;
   double       tocc_05_25 = 0.0;
   double       tocc_01_05 = 0.0;
   double       tocc_lt_01 = 0.0;
   double       tsuc_tests = 0.0;
   double       tsuc_highest = -1.0;
   double       tsuc_lowest = 1000000000.0;
   double       tsuc_gt_99 = 0.0;
   double       tsuc_95_99 = 0.0;
   double       tsuc_75_95 = 0.0;
   double       tsuc_50_75 = 0.0;
   double       tsuc_25_50 = 0.0;
   double       tsuc_05_25 = 0.0;
   double       tsuc_01_05 = 0.0;
   double       tsuc_lt_01 = 0.0;
   FILE *chi_dat=fopen(CFNAME, "r");
#endif

   if ((size = fill_arrays()) < min_testable) {
       fprintf(ofp, "File too small (%.0f) to meaningfully analyze\n",
               size);
       exit(0);
   }

#ifdef DEBUG
   if (chi_dat != NULL) {
       char dummy[128];
       fscanf(chi_dat, "%lf", &tocc_tests);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_highest);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_lowest);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_gt_99);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_95_99);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_75_95);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_50_75);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_25_50);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_05_25);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_01_05);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tocc_lt_01);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_tests);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_highest);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_lowest);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_gt_99);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_95_99);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_75_95);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_50_75);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_25_50);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_05_25);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_01_05);
       fgets(dummy, 128, chi_dat);
       fscanf(chi_dat, "%lf", &tsuc_lt_01);
       fgets(dummy, 128, chi_dat);
       fclose(chi_dat);
   }
#endif

   if ((V = get_V(size,cnt)) > V99) {
       desc = ": *******Non-random (hi)\n";
#ifdef DEBUG
       tocc_gt_99++;
#endif
   } else if (V > V95) {
       desc = ": Suspect (hi)\n";
#ifdef DEBUG
       tocc_95_99++;
#endif
   } else if (V > V75) {
       desc = ": Acceptible (hi)\n";
#ifdef DEBUG
       tocc_75_95++;
#endif
   } else if (V > V50) {
       desc = ": Excellent (hi) !!!!!!!\n";
#ifdef DEBUG
       tocc_50_75++;
#endif
   } else if (V > V25) {
       desc = ": Excellent (lo) !!!!!!!\n";
#ifdef DEBUG
       tocc_25_50++;
#endif
   } else if (V > V05) {
       desc = ": Acceptible (lo)\n";
#ifdef DEBUG
       tocc_05_25++;
#endif
   } else if (V > V01) {
       desc = ": Suspect (lo)\n";
#ifdef DEBUG
       tocc_01_05++;
#endif
   } else {
       desc = ": *******Non-random (lo)\n";
#ifdef DEBUG
       tocc_lt_01++;
#endif
   }

   fprintf(ofp, "Occurance  V = %.2f (n = %.0f)%s", V, size, desc);


#ifdef DEBUG
   tocc_tests++;
   if (V < tocc_lowest) tocc_lowest = V;
   if (V > tocc_highest) tocc_highest = V;
#endif

   for (i=0; i<NUM_BYTES; i++) {
       if (cnt[i] >= min_testable) {
           if ((V = get_V(cnt[i],successors[i])) > V99) {
               suc_gt_99++;
           } else if (V > V95) {
               suc_95_99++;
           } else if (V > V75) {
               suc_75_95++;
           } else if (V > V50) {
               suc_50_75++;
           } else if (V > V25) {
               suc_25_50++;
           } else if (V > V05) {
               suc_05_25++;
           } else if (V > V01) {
               suc_01_05++;
           } else {
               suc_lt_01++;
           }
           suc_tests++;
           if (V < suc_lowest) suc_lowest = V;
           if (V > suc_highest) suc_highest = V;
       }
   }
   if (suc_tests > 0.0) {
       fprintf(ofp,
               "Successor Vd = %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f\n",
                suc_gt_99*100.0/suc_tests,
                suc_95_99*100.0/suc_tests,
                suc_75_95*100.0/suc_tests,
                suc_50_75*100.0/suc_tests,
                suc_25_50*100.0/suc_tests,
                suc_05_25*100.0/suc_tests,
                suc_01_05*100.0/suc_tests,
                suc_lt_01*100.0/suc_tests);
       fprintf(ofp,
               "               deviation %d, (lowest = %.2f, highest = %.2f)\n",
               check_chichi5(suc_tests,
                             suc_gt_99+suc_95_99,suc_75_95,suc_50_75,
                             suc_25_50,suc_05_25,suc_01_05+suc_lt_01),
               suc_lowest, suc_highest);
   }

#ifdef DEBUG
   tsuc_tests += suc_tests;
   if (suc_lowest < tsuc_lowest) tsuc_lowest = suc_lowest;
   if (suc_highest > tsuc_highest) tsuc_highest = suc_highest;
   tsuc_gt_99 += suc_gt_99;
   tsuc_95_99 += suc_95_99;
   tsuc_75_95 += suc_75_95;
   tsuc_50_75 += suc_50_75;
   tsuc_25_50 += suc_25_50;
   tsuc_05_25 += suc_05_25;
   tsuc_01_05 += suc_01_05;
   tsuc_lt_01 += suc_lt_01;

   chi_dat = my_fopen(CFNAME, "w");
   fprintf(chi_dat, "%-14.0f - Total number of occurance tests\n",
           tocc_tests);
   fprintf(chi_dat, "%-14.2f - Highest V from an occurance test\n",
           tocc_highest);
   fprintf(chi_dat, "%-14.2f - Lowest V from an occurance test\n",
           tocc_lowest);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests above  %.2f\n",
           tocc_gt_99, V99);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests %.2f - %.2f\n",
           tocc_95_99, V95, V99);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests %.2f - %.2f\n",
           tocc_75_95, V75, V95);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests %.2f - %.2f\n",
           tocc_50_75, V50, V75);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests %.2f - %.2f\n",
           tocc_25_50, V25, V50);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests %.2f - %.2f\n",
           tocc_05_25, V05, V25);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests %.2f - %.2f\n",
           tocc_01_05, V01, V05);
   fprintf(chi_dat, "%-14.0f - Number of occurance tests below  %.2f\n",
           tocc_lt_01, V01);
   fprintf(chi_dat, "%-14.0f - Total number of successor tests\n",
           tsuc_tests);
   fprintf(chi_dat, "%-14.2f - Highest V from an successor test\n",
           tsuc_highest);
   fprintf(chi_dat, "%-14.2f - Lowest V from an successor test\n",
           tsuc_lowest);
   fprintf(chi_dat, "%-14.0f - Number of successor tests above  %.2f\n",
           tsuc_gt_99, V99);
   fprintf(chi_dat, "%-14.0f - Number of successor tests %.2f - %.2f\n",
           tsuc_95_99, V95, V99);
   fprintf(chi_dat, "%-14.0f - Number of successor tests %.2f - %.2f\n",
           tsuc_75_95, V75, V95);
   fprintf(chi_dat, "%-14.0f - Number of successor tests %.2f - %.2f\n",
           tsuc_50_75, V50, V75);
   fprintf(chi_dat, "%-14.0f - Number of successor tests %.2f - %.2f\n",
           tsuc_25_50, V25, V50);
   fprintf(chi_dat, "%-14.0f - Number of successor tests %.2f - %.2f\n",
           tsuc_05_25, V05, V25);
   fprintf(chi_dat, "%-14.0f - Number of successor tests %.2f - %.2f\n",
           tsuc_01_05, V01, V05);
   fprintf(chi_dat, "%-14.0f - Number of successor tests below  %.2f\n",
           tsuc_lt_01, V01);
   fprintf(chi_dat,
           "Occurance Vd = %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f",
            tocc_gt_99*100.0/tocc_tests,
            tocc_95_99*100.0/tocc_tests,
            tocc_75_95*100.0/tocc_tests,
            tocc_50_75*100.0/tocc_tests,
            tocc_25_50*100.0/tocc_tests,
            tocc_05_25*100.0/tocc_tests,
            tocc_01_05*100.0/tocc_tests,
            tocc_lt_01*100.0/tocc_tests);
   fprintf(chi_dat, " (deviation %d)\n",
           check_chichi7(tocc_tests,
                         tocc_gt_99,tocc_95_99,tocc_75_95,tocc_50_75,
                         tocc_25_50,tocc_05_25,tocc_01_05,tocc_lt_01));
   if (tsuc_tests > 0.0) {
       fprintf(chi_dat,
               "Successor Vd = %.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f",
                tsuc_gt_99*100.0/tsuc_tests,
                tsuc_95_99*100.0/tsuc_tests,
                tsuc_75_95*100.0/tsuc_tests,
                tsuc_50_75*100.0/tsuc_tests,
                tsuc_25_50*100.0/tsuc_tests,
                tsuc_05_25*100.0/tsuc_tests,
                tsuc_01_05*100.0/tsuc_tests,
                tsuc_lt_01*100.0/tsuc_tests);
       fprintf(chi_dat, " (deviation %d)\n",
               check_chichi7(tsuc_tests,
                             tsuc_gt_99,tsuc_95_99,tsuc_75_95,tsuc_50_75,
                             tsuc_25_50,tsuc_05_25,tsuc_01_05,tsuc_lt_01));
   }
   fclose(chi_dat);
#endif
}

int
main(argc,argv)
int argc;
char **argv;
{
   ifp = (argc > 1) ? my_fopen(argv[1],"rb") : stdin;
   ofp = (argc > 2) ? my_fopen(argv[2],"w") : stdout;
   chi_2_test();

   return(0);
}


---

<a href="mailto:[email protected]">Dr. Dimitri Vulis</a>
Brighton Beach Boardwalk BBS, Forest Hills, N.Y.: +1-718-261-2013, 14.4Kbps