1

I have a data set I am trying to go through in order, however fscanf_s() and a function I wrote that uses fgetc() both only read 4 lines that are out of order in my data set. I terminate the loop that is utilizing the values when either 1 of my data sets is empty or when fscanf_s() or my personal function returns EOF.

I tried testing what line it cancels on but its random every time. I looked for some similar problems but most of them just said to use fgets or fgetc and then parse which I am already doing with my personal function.

double update_weights_v2(LOGISTIC_MODEL hModel, FILE* data_input, FILE* data_output) {
    Model* pModel = (Model*)hModel;
    int status1, status2;
    double X, Y, error = 0, prediction, W1_deriv = 0, W2_deriv = 0;
    int n = 0;

    //X = parse_data_double(data_input, &status1);
    //Y = parse_data_double(data_output, &status2);

    status1 = fscanf_s(data_input, "%[^\n]lf", &X);
    status2 = fscanf_s(data_output, "%[^\n]lf", &Y);

    while (status1 != EOF && status2 != EOF) {
        prediction = pModel->activation(X, pModel->W1, pModel->W2);
        error = Y - prediction;

        // df/dW1 = 1/n SUM[1->n](-2*Xi * (error))
        W1_deriv += (X * error * pModel->rate);
        // df/dW2 = 1/n SUM[1->n](-2 * (error))
        W2_deriv += (error*pModel->rate);

        // Read next data entry
        //X = parse_data_double(data_input, &status1);
        //Y = parse_data_double(data_output, &status2);
        status1 = fscanf_s(data_input, "%[^\n]lf", &X);
        status2 = fscanf_s(data_output, "%[^\n]lf", &Y);
        n++;
        printf("Input: %.5lf\nOutput: %.5lf\nGuess: %.5lf\nError: %.5lf\nWeight[1]: %.5lf\nWeight[2]: %.5lf\n*************************************************************\n", X, Y, prediction, error, pModel->W1, pModel->W2);
    }
    rewind(data_input);
    rewind(data_output);
    return error;
}

I expected this code to iterate through the entire data set, then reset the file so that its at the first character after every full run through the data set.

Michael
  • 67
  • 8
  • The format specifier `%[^\n]lf` is incorrect for a `double` variable. Are you reading a string, or a floating point value? Please show a short example of the data you are reading. Please check the warnings given by the compiler. – Weather Vane Nov 04 '19 at 20:12
  • 1
    Warning C4477: 'scanf_s' : format string '%[^\n]' requires an argument of type 'char *', but variadic argument 1 has type 'double *' – Weather Vane Nov 04 '19 at 20:23
  • You will also want to look at [**Why is while ( !feof (file) ) always wrong?**](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong). You are essentially doing the same thing. – David C. Rankin Nov 04 '19 at 23:27
  • sorry I posted code after I was trying %[^\n]lf it still has issues as %lf – Michael Nov 05 '19 at 00:01

2 Answers2

1

While you have not provided a A Minimal, Complete, and Verifiable Example (MCVE), the immediate problem with your code after you fix the "%[^\n]" and make it "%lf", is that you are conditioning the end of your read loop on status1 != EOF && status2 != EOF. Neither will be EOF until after you invoke Undefined Behavior by attempting to printf the X, Y values after EOF is reached.

Further, conditioning your loop on EOF ignores any matching or input failure that may result before EOF is reached. Instead, you always validate whether scanf (f_scanf in you case) succeeds or fails based on the Number Of Successful Conversions, i.e. the numeric value returned. Which is why you were referred to Why is while ( !feof (file) ) always wrong? in the comments.

It is far better to control your read loop based on the numeric returns, e.g.

    while (fscanf_s (data_input, "%lf", &X) == 1 &&
            fscanf_s(data_output, "%lf", &Y) == 1) {

or simply loop continually until either fails, e.g.

while (1) {
    ...
    status1 = fscanf_s (data_input, "%lf", &X);
    if (status1 != 1) {
        if (status1 == EOF) {
            fputs ("status1-EOF\n", stderr);
            break;
        }
        else if (status1 == 0) {
            fputs ("matching or input failure.\n", stderr);
            /* matching or input failure occurred,
             * handle as appropriate (clear to '\n' or break).
             */
        }
    }

Given what it looks like you are trying to accomplish, you can go with something similar to the following:

double update_weights_v2 (LOGISTIC_MODEL hModel, 
                            FILE* data_input, FILE* data_output) 
{
    Model* pModel = (Model*)hModel;
    double X, Y, error = 0, prediction, W1_deriv = 0, W2_deriv = 0;
    int n = 0;

    while (fscanf_s (data_input, "%lf", &X) == 1 &&
            fscanf_s(data_output, "%lf", &Y) == 1) {
        prediction = pModel->activation(X, pModel->W1, pModel->W2);
        error = Y - prediction;

        W1_deriv += (X * error * pModel->rate);
        W2_deriv += (error*pModel->rate);

        n++;

        printf ("Input: %.5lf\nOutput: %.5lf\nGuess: %.5lf\nError: %.5lf\n"
                "Weight[1]: %.5lf\nWeight[2]: %.5lf\n"
                "***********************************************************\n",
                X, Y, prediction, error, pModel->W1, pModel->W2);
    }
    rewind(data_input);
    rewind(data_output);

    return error;
}

(note: your rewind() at the end will mask the stream state set within the function -- that may be what you want, it can also mask a problem in the data file that will just bite you again on your next call to update_weights_v2())

To help further we will need A Minimal, Complete, and Verifiable Example (MCVE).

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
1

While there have been many helpful answers, the fix to this was a problem with a line that wasn't showing in vs code. For whatever reason, I wasn't able to view a line that was supposed to limit the amount of outputs the program could show so that it wouldn't spam the console with every single guess my model made. I reloaded vs code after an update and the line was back. I'm not sure why this happened but it makes sense now.

Thank you.

Michael
  • 67
  • 8