Pertanyaan Cetak float sebagai NaN, tetapi cetak nilai yang benar segera setelahnya


Saya telah mengalami beberapa masalah aneh dengan pelampung yang dicetak sebagai NaN tergantung di mana di kode saya, saya mencetaknya. Untuk konteksnya, kode tersebut memilah daftar data gempa bumi menggunakan BST, dan kemudian loop melalui data yang diurutkan untuk menemukan kesenjangan terbesar antara dua gempa bumi berturut-turut. Dua gempa tersebut kemudian dicetak di sini:

FILE* output_file = safe_open_file("task_1_bst.csv", "w");
fprintf(output_file, "timestamp,latitude,longitude,magnitude\n");
eq_print(output_file, sorted_arr[longest_index-1]);
fprintf(output_file, "\n");
eq_print(output_file, sorted_arr[longest_index-1]);
fprintf(output_file, "\n");
eq_print(output_file, sorted_arr[longest_index]);
fclose(output_file);

Seperti yang Anda lihat, saya mencetak salah satu gempa bumi dua kali, dan inilah hasilnya:

timestamp,latitude,longitude,magnitude
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T06:02:52.500Z,31.315,-115.392,3.4
2009-06-13T16:04:06.650Z,3.930,126.648,4.4

Untuk beberapa alasan, garis lintang EQ pertama adalah nan ketika pertama kali dicetak, tetapi mencetak dengan benar untuk yang kedua kalinya.

Ada cukup banyak kode jadi saya tidak bisa memasukkan semuanya di sini. Array yang diurutkan_arr penuh dengan pointer ke tipe eq_t.

typedef struct {
    timestamp_t* timestamp;
    float latitude;
    float longitude;
    float magnitude;
    float x;
    float y;
} eq_t;

timestamp_t hanyalah sebuah struct integer (tahun, bulan, hari, jam dll), dan eq_print hanyalah pembungkus di sekitar fprintf yang mencetak setiap bidang eq_t dan timestamp_t.

void eq_print(FILE* fp, eq_t* q)
{
    fprintf(fp, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ,%.3f,%.3f,%.1f",
        q->timestamp->year,
        q->timestamp->month,
        q->timestamp->day,
        q->timestamp->hour,
        q->timestamp->min,
        q->timestamp->sec,
        q->timestamp->msec,
        q->latitude,
        q->longitude,
        q->magnitude);
}

eq_print tidak mengubah eq_t sama sekali, jadi mengapa nilai cetak berbeda ketika tidak ada kode antara dua fprintfs?

Apa yang bisa menjadi penyebab pelampung memiliki nilai NaN, dan kemudian segera setelah memiliki nilai yang benar?

Sunting: Melangkah melalui masing-masing garis tersebut dengan GDB dan mencetak garis lintang di setiap baris mencetak nilai yang benar.

Breakpoint 1, task_1_find_longest_break_after_2k_bst (
    eq_csv_file=0x28cc87 "eq_data.csv") at tasks.c:128
128             FILE* output_file = safe_open_file("task_1_bst.csv", "w");
(gdb) warning: cYgFFFFFFFF 611B75D0 0
warning: cYgstd 0x28cbdf d 3
print sorted_arr[longest_index-1]->latitude
$1 = 31.3150005
(gdb) next
129             fprintf(output_file, "timestamp,latitude,longitude,magnitude\n");
(gdb) print sorted_arr[longest_index-1]->latitude
$2 = 31.3150005
(gdb) next
130             eq_print(output_file, sorted_arr[longest_index-1]);
(gdb) print sorted_arr[longest_index-1]->latitude
$3 = 31.3150005
(gdb) next
131             fprintf(output_file, "\n");
(gdb) print sorted_arr[longest_index-1]->latitude
$4 = 31.3150005
(gdb) next
132             eq_print(output_file, sorted_arr[longest_index-1]);
(gdb) print sorted_arr[longest_index-1]->latitude
$5 = 31.3150005

Ada peringatan bahwa saya tidak yakin cara menafsirkan.

Eq_t q ditugaskan dengan fungsi ini

eq_t* read_quake(FILE* fp)
{
    char buf[1024];
    float latitude, longitude, magnitude;
    if (fscanf(fp, "%[^,],%f,%f,%f\n", buf, &latitude, &longitude, &magnitude) == 4) {
        eq_t* eq = (eq_t*)safe_malloc(sizeof(eq_t));
        eq->timestamp = parse_time(buf);
        eq->latitude = latitude;
        eq->longitude = longitude;
        eq->magnitude = magnitude;
        map_coordinates(eq);
        return eq;
    }
    return NULL;
}

Tidak ada masalah apa pun di sini. Sepertinya ada masalah dengan pencetakan.


4
2017-08-14 04:10


asal


Jawaban:


Berikut ini replikasi kode Anda sebagai MCVE (Cara membuat contoh Minimal, Lengkap, dan Dapat Diverifikasi).

#include <math.h>       /* NAN */
#include <stdio.h>

/*
timestamp,latitude,longitude,magnitude
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T06:02:52.500Z,31.315,-115.392,3.4
2009-06-13T16:04:06.650Z,3.930,126.648,4.4
*/

typedef struct timestamp_t
{
    int year;
    int month;
    int day;
    int hour;
    int min;
    int sec;
    int msec;
} timestamp_t;

typedef struct
{
    timestamp_t* timestamp;
    float latitude;
    float longitude;
    float magnitude;  // x, y unused so removed
} eq_t;

static timestamp_t times[] =
{
    { 2009, 6, 13,  6,  2, 52, 500 },
    { 2009, 6, 13, 16,  4,  6, 650 },
};

static eq_t quakes[] =
{
    { &times[0],      NAN, -115.392F, 3.4F },
    { &times[1],  +3.930F, +126.648F, 4.4F },
};

static eq_t *sorted_arr[] = { &quakes[0], &quakes[1] };

static void eq_print(FILE* fp, eq_t* q)
{
    fprintf(fp, "%d-%02d-%02dT%02d:%02d:%02d.%03dZ,%.3f,%.3f,%.1f",
            q->timestamp->year,
            q->timestamp->month,
            q->timestamp->day,
            q->timestamp->hour,
            q->timestamp->min,
            q->timestamp->sec,
            q->timestamp->msec,
            q->latitude,
            q->longitude,
            q->magnitude);
}

int main(void)
{
    int longest_index = 1;
    FILE *output_file = stdout;
    fprintf(output_file, "timestamp,latitude,longitude,magnitude\n");
    eq_print(output_file, sorted_arr[longest_index-1]);
    fprintf(output_file, "\n");
    eq_print(output_file, sorted_arr[longest_index-1]);
    fprintf(output_file, "\n");
    eq_print(output_file, sorted_arr[longest_index]);
    fprintf(output_file, "\n");
    fclose(output_file);

    return 0;
}

Saya menyebutnya nan11.c, dan mengkompilasi dengan bersih di bawah GCC 6.1.0 pada Mac OS X 10.11.6, dan menjalankan serta menghasilkan output yang sama dua kali:

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
     -Wold-style-definition nan11.c -o nan11  
$ ./nan11
timestamp,latitude,longitude,magnitude
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T06:02:52.500Z,nan,-115.392,3.4
2009-06-13T16:04:06.650Z,3.930,126.648,4.4
$

Ketika hal-hal berubah secara tidak terduga, itu biasanya berarti ada masalah dengan manajemen memori, dan sering kali berarti bahwa variabel lokal sedang dikembalikan ke suatu tempat. Ini sedikit tidak terduga bahwa kesalahan 'memperbaiki sendiri' pada operasi cetak kedua.

Anda perlu membuat sebuah MCVE analog dengan apa yang saya tunjukkan yang sebenarnya melakukan pembacaan, alokasi memori, dan sebagainya, namun masih mengalami masalah. Anda harus mempertimbangkan menjalankan kode itu di bawah valgrind untuk melihat apakah itu dapat mendeteksi penyalahgunaan memori.


3
2017-08-14 05:37