/* campionamento di un file
* carica il campione su array
* versione "senza reimbussolamento", ovvero un record puo' essere preso piu' volte
* Il caricamento del campione su array giustificato soltanto se:
* 1. il campione che si vuole estrarre non e' troppo grande
* 2. l'elaborazione che si intende svolgere sul campione richiede pi accessi
* a ogni dato
*
* - acquisisce nome e apre file da campionare in modalita lettura binaria
* - acquisisce origine sequenza random
* - si posiziona in coda al file per calcolarne la dimensione N
* - input della frazione da campionare n e verifica di capienza dell'array
* - ripeti volte la generazione di un numero fra 0 e N
* quando genera un numero di record non ancora letto legge
* il record corrispondente nell'array e tiene traccia della lettura
* - elabora il campione
*/
#define dimCAMPIONE 50000
#define DIMBUF 80
#include <stdio.h>
#include <stdlib.h>
#include "random.h" /* procedura esterna per la generazione di numeri random */
typedef long r; /* a titolo di esempio si considera un file di interi lunghi */
void elabora(r *campione,long n);
long cercaLong(long target, long *a, long n);
int main(){
r camp[dimCAMPIONE]; /* array di campioni */
long estratti[dimCAMPIONE]; // array estratti
long N, /* numero di r nel file */
n, /* dimensione campione corrente */
i, /* indice */
seme, /* seme per rand */
t, /* posizione nell'array di estratti */
p; /* posizione di campionamento corrente */
float f; /* frazione da estrarre */
FILE *fd;
char nomeF[64], linea[DIMBUF];
/* intro e' un array di 4 stringhe di 64 caratteri ciascuna, utilizzato per mandare
* all'utente un messaggio introduttivo
*/
char intro[4][64]={"Programma per il campionamento di record da un file\n",
" Richiede il nome del file, il seme della sequenza random e\n",
" la frazione di record da campionare.\n",
" Versione con caricamento del campione in memoria\n"};
for (i=0;i<4;i++) /* visualizza intro */
printf("%s",intro[i]);
/* inizializzazione */
printf("\nNome file da campionare\n");
fgets(linea,DIMBUF,stdin);
sscanf(linea,"%s",nomeF);
if ((fd=fopen(nomeF,"rb"))==NULL){
printf("File %s non trovato\n",nomeF);
return 1;
}
printf("Inserire origine sequenza random \n");
fgets(linea,DIMBUF,stdin);
sscanf(linea,"%ld",&seme);
srand(seme);
fseek(fd,0,SEEK_END);
N=ftell(fd)/sizeof(r);
printf("Inserire frazione da campionare (da 0 a 0.5) \n");
fgets(linea,DIMBUF,stdin);
sscanf(linea,"%f",&f);
n=f*N;
printf("Nel file ci sono %ld records, ne campiono %ld\n",N,n);
if (n>dimCAMPIONE){
printf("Campione troppo grande\n");
return 1;
}
/* fine inizializzazione */
i=0;
while (i<n){ /* ripete n volte il campionamento */
p=randN(N); /* genera la posizione del record da campionare */
t = cercaLong(p,estratti,i);
if (t==i){ // p non era stato estratto -> aggiorno estratti[i]
estratti[i++]=p; // e incremento i
fseek(fd,p*sizeof(r),SEEK_SET); /* si posiziona per la lettura */
fread(&(camp[i]),sizeof(r),1,fd); /* legge il record nell'array */
}
// se p era gi stato estratto non fa nulla e al prossimo giro
// si tenta una nuova estrazione
} // quando si esce il campione e' popolato
fclose(fd);
elabora(camp,n); /* elabora l'array con il campione */
return 0;
} /* fine main */
/*
* elabora: esempio di elaborazione dell'array con il campione
*/
void elabora(r *campione, long n){ /* a titolo di esempio si calcola la media */
float media;
long i;
media=campione[0];
for (i=1;i<n;i++)
media = (media*(i)+campione[i])/(i+1);
printf("valore medio %f\n",media);
} /* fine elabora */
/*
* cercaLong: cerca un target in un array di n long
* se non trovato restituisce n, altrimenti restituisce la posizione trovata
* a partire da 0 fino a n-1
*/
long cercaLong(long target, long *a, long n){
long i=0;
while (i<n)
if (target==a[i])
return i;
else
i++;
return i;
} // cercaLong