2013-12-14 12 views
5

Ich habe viele verschiedene Pseudozufallszahlengeneratoren in C geschrieben, die eine beliebige Anzahl von Paaren von Zufallszahlen generieren (über die CLI) und speichern sie in einem (neue) Textdatei: ein Paar Zahlen pro Spalte. Ich möchte 400.000.000 Zahlen in einer Textdatei speichern, aber wenn ich mir die Anzahl der Zeilen der Datei anschaue, hat sie nur 82.595.525 Zeilen. Dies ist der Code:Ich kann nur eine endliche Anzahl von Zeilen in einer neuen Textdatei speichern

#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; 
} 

Zuerst ich, dass es im Verdacht, wo einige Problem im Code (dh ich die falschen Arten von Variablen irgendwo entschieden werden könnte), aber ich es getestet, indem in der for-Schleife ein, einschließlich if (i > 165191050) printf ("%llu\n", i); (daran erinnern, dass ich ein 1-D-Array für die Speicherung von Paaren von Zahlen, nicht ein 2D-verwenden, so in der Bedingung multipliziere ich einfach 82595525*2), um zu testen, ob das Problem war, dass der Code nicht 800.000.000 mal looping war, aber nur 165191050. Als ich den Test nach i = 165191050 durchführte, fing es gerade an, i Werte auf der Schale auszudrucken, so dass es diese 800.000.000 Mal wirklich schlingerte, aber als ich die Anzahl der Zeilen der erzeugten Textdatei sah, gab es wieder 82595525 Zeilen. Also ich wette, das Problem ist nicht im Code (oder zumindest nicht in den Arten von Variablen, die ich verwendet habe).

ich auch die gleichen Ergebnisse mit diesem Algorithmus erhalten (dies ist nur eine andere unterschiedliche Pseudozufallszahlengenerator):

#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; 
} 

Wieder Schleifen es 800.000.000 mal, aber es speichert nur 165191050 Zahlen.

$ ./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 

Was geht hier vor?

Vielen Dank im Voraus.

+0

Sollte nicht '2147483648LL' wirklich' 2147483648ULL' sein? (Es ist nicht notwendig, 'LL' zu' 0' und '1' auf der anderen Seite hinzuzufügen.) –

+2

Sie sollten an diesem Punkt sehr nahe der 2G-Ausgabegröße sein. FS oder ulimit Einschränkungen? – Mat

+0

Überprüfen Sie das Ergebnis von 'fprintf' und vergewissern Sie sich, dass es nicht negativ ist. –

Antwort

6

Jede Zeile ist 26 Zeichen lang, x 82.595.525 Zeilen 26 = 2147483650 Bytes

Wenn Sie die Datei erstellt aussehen näher, ich bin ziemlich sicher, dass die letzte Zeile abgeschnitten und die Dateigröße ist genau 2147483647, dh 2^31-1.

Der Grund, warum Sie keine größere Datei schreiben können, liegt entweder an einer Dateisystembeschränkung, aber eher daran, dass Sie eine (nicht große Datei) 32-Bit-Binärdatei kompilieren, mit der eine Datei nicht kompatibel ist mehr als 2147483647 sein, da es die größte vorzeichenbehaftete ganze Zahl ist, die verwendet werden kann.

Wenn das der Fall ist und wenn Ihr Betriebssystem 64 Bit ist, ist die einfachste Lösung, die richtigen Compiler-Flags zu erstellen, um eine 64-Bit-Binärdatei zu erstellen, die diese Einschränkung nicht aufweist.

Sonst, schauen Sie sich in abasterfield Workaround.

+1

oder #define_FILE_OFFSET_BITS 64 Benutzer konnten Dateien größer als 2^31 Byte vor 64 Bit verwenden Prozessoren kamen mit! – abasterfield

+0

@abasterfield In der Tat, vielen Dank für das Zeigen. – jlliagre

+0

Ich konnte mir nicht vorstellen, dass dieses Problem mit dem Dateisystem zusammenhängen könnte ... jeden Tag lernen wir etwas Neues. Vielen Dank für Ihre Erklärung :) –

3

Compile mit CFLAGS -D_FILE_OFFSET_BITS=64 oder

#define _FILE_OFFSET_BITS 64 

in Ihrem Code setzen, bevor Sie libc-Header enthalten

+0

Vielen Dank, deine Lösung hat perfekt funktioniert :) –