htestu-0.1.0.0: cbits/testu/src/ufile.c
/*************************************************************************\
*
* Package: TestU01
* File: ufile.c
* Environment: ANSI C
*
* Copyright (c) 2002 Pierre L'Ecuyer, DIRO, Université de Montréal.
* e-mail: lecuyer@iro.umontreal.ca
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted without a fee for private, research,
* academic, or other non-commercial purposes.
* Any use of this software in a commercial environment requires a
* written licence from the copyright owner.
*
* Any changes made to this package must be clearly identified as such.
*
* In scientific publications which used this software, a reference to it
* would be appreciated.
*
* Redistributions of source code must retain this copyright notice
* and the following disclaimer.
*
* THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
\*************************************************************************/
#include "gdef.h"
#include "util.h"
#include "ufile.h"
#include "unif01.h"
#include <stdio.h>
#include <string.h>
#include <limits.h>
/* Length of strings */
#define LEN 200
#define NORM32 2.3283064365386962E-10 /* 1 / 2^32 */
#define ARRAYDIM 1048576 /* = 2^20 */
/*========================== module variables ============================*/
static char S[LEN + 1];
static FILE *f1, *f2;
static int co1 = 0, co2 = 0; /* Counters */
/* X1 will contain the numbers read from a text input file */
static double *X1 = NULL;
/* X2 will keep the bytes read from a binary input file */
static unsigned char *X2 = NULL;
static unsigned long n1, n2, /* Current index of tables */
MaxBin, MaxText, /* Maximal index in the tables */
Dim1, Dim2; /* Dimension of tables */
static double NBin, NText; /* Number of calls to the generator */
/*========================================================================*/
static void WrReadText (void *junk)
{
printf (" %.0f numbers have been read\n", NText);
}
/*-----------------------------------------------------------------------*/
static void FillTextArray (void)
/*
* Read numbers (double's) until end of file or until Dim1 (dimension of
* array X1) numbers have been read.
*/
/*
* The standard function setvbuf could be used here to increase the
* speed of reading. Right now, we use default system buffering.
*/
{
unsigned long i;
MaxText = Dim1;
i = 0;
while ((i < Dim1) && (fscanf (f1, " %lf", (X1 + i)) == 1))
++i;
if (i < MaxText)
/* The numbers do not fill the whole array: EOF or Error */
MaxText = i;
n1 = 0;
}
/*-----------------------------------------------------------------------*/
static double ReadText_U01 (void *junk1, void *junk2)
/*
* Return the n-th element of the array. If at end of array, call
* FillTextArray to fill the array once again, and then return the
* first element.
*/
{
if (n1 < MaxText) {
NText += 1.0;
return X1[n1++];
} else if (MaxText == Dim1) {
FillTextArray ();
NText += 1.0;
return X1[n1++];
} else {
X1 = util_Free (X1);
util_Fclose (f1);
sprintf (S, "%.0f numbers have been read.\n", NText);
strncat (S, "End-of-file detected.\n", (size_t) 25);
strncat (S, "Not enough numbers in file for these test parameters.",
(size_t) 60);
util_Error (S);
return -1.0;
}
}
/*-----------------------------------------------------------------------*/
static unsigned long ReadText_Bits (void *vpar, void *vsta)
{
return (unsigned long) (ReadText_U01 (vpar, vsta) * unif01_NORM32);
}
/*-----------------------------------------------------------------------*/
unif01_Gen * ufile_CreateReadText (char *A, long dim)
{
unif01_Gen *gen;
size_t leng;
char name[LEN + 1];
util_Assert (dim > 0, "ufile_CreateReadText: nbuf <= 0.");
util_Assert (co1 == 0,
"ufile_CreateReadText: only 1 generator at a time can be in use");
co1++;
gen = util_Malloc (sizeof (unif01_Gen));
strncpy (name, "ufile_CreateReadText: ", (size_t) LEN);
strncat (name, A, (size_t) (LEN - 30));
leng = strlen (name);
gen->name = util_Calloc (leng + 1, sizeof (char));
strncpy (gen->name, name, leng);
f1 = util_Fopen (A, "r");
Dim1 = util_Min (ARRAYDIM, dim);
MaxText = Dim1;
X1 = util_Calloc ((size_t) Dim1, sizeof (double));
gen->GetBits = &ReadText_Bits;
gen->GetU01 = &ReadText_U01;
gen->Write = &WrReadText;
gen->param = NULL;
gen->state = NULL;
FillTextArray ();
NText = 0;
return gen;
}
/*-----------------------------------------------------------------------*/
void ufile_DeleteReadText (unif01_Gen *gen)
{
X1 = util_Free (X1);
util_Fclose (f1);
gen->name = util_Free (gen->name);
util_Free (gen);
co1--;
}
/*-----------------------------------------------------------------------*/
void ufile_InitReadText (void)
{
int j = 0;
util_Assert (NULL != f1, "ufile_InitReadText: unable to read from file");
if (NText > Dim1) {
j = fseek (f1, 0L, SEEK_SET);
util_Assert (0 == j, "ufile_InitReadText: file rewind failed");
FillTextArray ();
}
NText = n1 = 0;
}
/*========================================================================*/
static void FillBinArray (void)
/*
* Read bits, at most Dim2 bytes.
*/
{
MaxBin = fread (X2, (size_t) 1, (size_t) Dim2, f2);
n2 = 0;
}
/*-----------------------------------------------------------------------*/
static unsigned long ReadBin_Bits (void *vpar, void *vsta)
/*
* Return the n-th element of the array. If at end of the array, call
* FillBinArray to fill the array once again, and then return the first
* element. Each number uses 32 bits in big-endian form: the first byte
* makes the most significant bits, and the fourth one makes the least
* significant.
*/
{
unsigned long u;
if (n2 < MaxBin) {
u = (unsigned long) X2[n2++] << 24;
u |= (unsigned long) X2[n2++] << 16;
u |= (unsigned long) X2[n2++] << 8;
u |= (unsigned long) X2[n2++];
NBin += 1.0;
return u;
} else if (MaxBin == Dim2) {
FillBinArray ();
return ReadBin_Bits (vpar, vsta);
} else {
X2 = util_Free (X2);
util_Fclose (f2);
f2 = NULL;
sprintf (S, "%.0f bits have been read.\n", NBin * 32.0);
strncat (S, "End-of-file detected.\n", (size_t) 25);
strncat (S, "Not enough bits in file for these test parameters.",
(size_t) 53);
util_Error (S);
return 0;
}
}
/*-----------------------------------------------------------------------*/
static double ReadBin_U01 (void *vpar, void *vsta)
{
return ReadBin_Bits (vpar, vsta) * NORM32;
}
/*-----------------------------------------------------------------------*/
static void WrReadBin (void *junk)
{
printf (" %.0f bits have been read.\n", NBin * 32.0);
}
/*-----------------------------------------------------------------------*/
unif01_Gen * ufile_CreateReadBin (char *A, long dim)
{
unif01_Gen *gen;
size_t leng;
char name[LEN + 1];
util_Assert (dim > 0, "ufile_CreateReadBin: nbuf <= 0.");
util_Assert (co2 == 0,
"ufile_CreateReadBin: only 1 generator at a time can be in use");
co2++;
gen = util_Malloc (sizeof (unif01_Gen));
strncpy (name, "ufile_CreateReadBin: ", (size_t) LEN);
strncat (name, A, (size_t) LEN - 30);
leng = strlen (name);
gen->name = util_Calloc (leng + 1, sizeof (char));
strncpy (gen->name, name, leng);
f2 = util_Fopen (A, "rb");
/* Each random number will be built of 32 bits = 4 bytes */
Dim2 = util_Min (ARRAYDIM, 4*dim);
X2 = util_Calloc ((size_t) Dim2, sizeof (unsigned char));
FillBinArray ();
NBin = 0;
gen->GetBits = &ReadBin_Bits;
gen->GetU01 = &ReadBin_U01;
gen->Write = &WrReadBin;
gen->param = NULL;
gen->state = NULL;
return gen;
}
/*-----------------------------------------------------------------------*/
void ufile_DeleteReadBin (unif01_Gen *gen)
{
X2 = util_Free (X2);
util_Fclose (f2);
gen->name = util_Free (gen->name);
util_Free (gen);
co2--;
}
/*-----------------------------------------------------------------------*/
void ufile_InitReadBin (void)
{
int j = 0;
util_Assert (NULL != f2, "ufile_InitReadBin: unable to read from file");
if (NBin >= Dim2 / 4) {
j = fseek (f2, 0L, SEEK_SET);
util_Assert (0 == j, "ufile_InitReadBin: file rewind failed");
FillBinArray ();
}
NBin = n2 = 0;
}
/*========================================================================*/
void ufile_Gen2Bin (unif01_Gen *gen, char *fname, double nbits,
int r, int s)
{
unsigned long Z;
unsigned long i, n;
unsigned char buffer[4];
FILE *f;
int k;
const int KMAX = s / 8;
int status;
util_Assert (nbits > 0.0, "ufile_Gen2Bin: nbits <= 0");
util_Assert (r >= 0, "ufile_Gen2Bin: r < 0");
util_Assert (s % 8 == 0,
"ufile_Gen2Bin: s must be in { 8, 16, 24, 32 }");
util_Assert (nbits / s <= ULONG_MAX,
"ufile_Gen2Bin: nbits is too large");
n = 0.5 + nbits / s;
if (n * (double) s < nbits)
n++;
f = util_Fopen (fname, "wb");
for (i = 0; i < n; i++) {
Z = unif01_StripB (gen, r, s);
for (k = KMAX - 1; k >= 0; k--) {
buffer[k] = Z & 0xFF;
Z >>= 8;
}
status = fwrite (buffer, (size_t) 1, (size_t) KMAX, f);
if (status != KMAX) {
perror ("ufile_Gen2Bin: fwrite");
exit (EXIT_FAILURE);
}
}
util_Fclose (f);
}