2013-12-14 11 views
5

Ho molti diversi generatori di numeri pseudo casuali scritti in C che generano un numero arbitrario di coppie di numeri casuali (tramite la CLI) e li memorizzano in un (nuovo) file di testo: una coppia di numeri per colonna. Voglio memorizzare i numeri 400.000.000 in un file di testo, ma quando guardo il numero di linee del file, ha solo 82.595.525 linee. Questo è il codice:Posso memorizzare solo un numero finito di righe in un nuovo file di testo

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include "../Calculos/myfunctions.c" 

void outputDevRandomOpenFile (FILE * from_file, FILE * to_file, unsigned long long how_many_pairs){ 

    unsigned long long i = 0LL; 
    int seed; 

    unsigned long long max_period = 2147483648LL; 

    for (i = 0LL; i < how_many_pairs; i += 1LL){ 

     fread (&seed, sizeof(int), 1, from_file); 
     fprintf (to_file, "%.10lf ", fabs (((double) seed)/((double) max_period))); 

     fread (&seed, sizeof(int), 1, from_file); 
     fprintf (to_file, "%.10lf\n", fabs (((double) seed)/((double) max_period))); 
    } 
} 


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

    char * endptr; 
    unsigned long long how_many_pairs = (unsigned long long) strtoull (argv[1], &endptr, 10); 

    FILE * urandom = fopen ("/dev/urandom", "r"); 
    FILE * to_file = fopen ("generated_numbers_devrandom.txt", "w"); 

    outputDevRandomOpenFile (urandom, to_file, how_many_pairs); 

    fclose (urandom); 

    return 0; 
} 

In un primo momento ho ritenuto sospetto che là dove qualche problema nel codice (ad esempio potrei essere scegliendo il tipo sbagliato di variabili da qualche parte), ma ho provato includendo all'interno del ciclo for un if (i > 165191050) printf ("%llu\n", i); (ricorda che sto usando un array 1-D per memorizzare coppie di numeri, non uno 2-D, quindi nella condizione mi limito a moltiplicare lo 82595525*2) per verificare se il problema era che il codice non era in loop 800.000.000 volte, ma solo 165191050. Quando ho eseguito il test, dopo i = 165191050, ho appena iniziato a stampare i valori i sulla shell, quindi è stato effettivamente eseguito il ciclo di quelle 800.000.000 volte, ma quando ho cercato il numero di righe del file di testo generato, c'erano nuovamente le righe 82595525. Quindi sto scommettendo che il problema non è nel codice (o almeno non nei tipi di variabili che ho usato).

Sto anche ottenere gli stessi risultati con questo algoritmo (questo è solo un altro diverso generatore di numeri pseudo-casuali):

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#define MT_LEN 624 

int mt_index; 
unsigned long mt_buffer[MT_LEN]; 

void mt_init() { 
    int i; 
    for (i = 0; i < MT_LEN; i++) 
     mt_buffer[i] = rand(); 
    mt_index = 0; 
} 

#define MT_IA   397 
#define MT_IB   (MT_LEN - MT_IA) 
#define UPPER_MASK  0x80000000 
#define LOWER_MASK  0x7FFFFFFF 
#define MATRIX_A  0x9908B0DF 
#define TWIST(b,i,j) ((b)[i] & UPPER_MASK) | ((b)[j] & LOWER_MASK) 
#define MAGIC(s)  (((s)&1)*MATRIX_A) 

unsigned long mt_random() { 
    unsigned long * b = mt_buffer; 
    int idx = mt_index; 
    unsigned long s; 
    int i; 

    if (idx == MT_LEN*sizeof(unsigned long)) 
    { 
     idx = 0; 
     i = 0; 
     for (; i < MT_IB; i++) { 
      s = TWIST(b, i, i+1); 
      b[i] = b[i + MT_IA]^(s >> 1)^MAGIC(s); 
     } 
     for (; i < MT_LEN-1; i++) { 
      s = TWIST(b, i, i+1); 
      b[i] = b[i - MT_IB]^(s >> 1)^MAGIC(s); 
     } 

     s = TWIST(b, MT_LEN-1, 0); 
     b[MT_LEN-1] = b[MT_IA-1]^(s >> 1)^MAGIC(s); 
    } 
    mt_index = idx + sizeof(unsigned long); 
    return *(unsigned long *)((unsigned char *)b + idx); 
    /* Here there is a commented out block in MB's original program */ 
} 

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

    char * endptr; 
    const unsigned long long how_many_pairs = (unsigned long long) strtoll (argv[1], &endptr, 10); 

    unsigned long long i = 0; 

    FILE * file = fopen ("generated_numbers_mt.txt", "w"); 

    mt_init(); 

    for (i = 0LL; i < how_many_pairs; i++){ 
     fprintf (file, "%.10lf ", ((double) mt_random()/(double) 4294967295)); 
     fprintf (file, "%.10lf\n", ((double) mt_random()/(double) 4294967295)); 
    } 

    fclose (file); 

    return 0; 
} 

Ancora una volta, loop 800.000.000 volte, ma solo negozi 165191050 numeri.

$ ./devrandom 400000000 
$ nl generated_numbers_devrandom.txt | tail # Here I'm just asking the shell to number the lines of the text file and to print out the 10 last ones. 
82595516 0.8182168589 0.0370640513 
82595517 0.1133005517 0.8237414290 
82595518 0.9035788113 0.6030153367 
82595519 0.9192735264 0.0945496135 
82595520 0.0542484536 0.7224835437 
82595521 0.1827865853 0.9254508596 
82595522 0.0249044443 0.1234162976 
82595523 0.0371284033 0.8898798078 
82595524 0.5977596357 0.9672102989 
82595525 0.5523654688 0.29032228 

Cosa sta succedendo qui?

Grazie in anticipo.

+0

Non dovrebbe '2147483648LL' davvero essere' 2147483648ULL'? (Non c'è bisogno di aggiungere 'LL' a' 0' e '1', d'altra parte.) –

+2

Dovresti essere molto vicino alla dimensione dell'uscita 2G in quel punto. Limiti di FS o ulimit? – Mat

+0

Controlla il risultato di 'fprintf' e assicurati che non sia negativo. –

risposta

6

Ogni riga è di 26 caratteri, 82595525 linee x 26 = 2.147.483,65 mille byte

Se si guarda più vicino al file creato, sono abbastanza sicuro l'ultima riga viene troncato e la dimensione del file è proprio 2147483647, vale a dire 2^31-1.

Il motivo per cui non è possibile scrivere un file più grande è dovuto a una limitazione del file system ma più probabilmente a causa del fatto che si compila un file binario a 32 bit (non di grandi dimensioni) con cui un file non può essere superiore a 2147483647 in quanto è il numero intero con segno più grande che può essere utilizzato.

Se questo è il caso e se il sistema operativo è a 64 bit, la soluzione più semplice è impostare i flag del compilatore appropriati per creare un binario a 64 bit che non avrà questa limitazione.

Altrimenti, dare un'occhiata alla soluzione alternativa.

+1

o #define _FILE_OFFSET_BITS 64 persone erano in grado di utilizzare i file superiore a 2^31 byte prima di 64 bit i processori sono arrivati! – abasterfield

+0

@abasterfield Anzi, grazie per averlo indicato. – jlliagre

+0

Non potevo immaginare che questo problema potesse essere collegato al filesystem ... ogni giorno impariamo qualcosa di nuovo. Grazie per la spiegazione :) –

3

Compila con CFLAGS -D_FILE_OFFSET_BITS=64 o mettere

#define _FILE_OFFSET_BITS 64 

nel codice prima di includere qualsiasi intestazione libc

+0

Grazie mille, la tua soluzione ha funzionato perfettamente :) –

Problemi correlati