-1

When using the variable from float grade that is equal to sometimes the start of the range or the end of the range, skips to else statement. Also when scanning a negative number, discards the unary sign and acts as a positive.

Sample input 1: 3.8 expected result: Excellent outcome: Average

Sample input 2: 1.3 expected result: Passing outcome: Invalid input...

Grade Description
3.8 - 4.0 Excellent
3.3 - 3.7 Superior
2.8 - 3.2 Good
1.8 - 2.7 Average
1.3 - 1.7 Below Average
1.0 - 1.2 Passing
below 1.0 Failure
not within 0.0 - 4.0 Invalid
#include<stdio.h>

int main (void){
    
    float grade;
    
    printf("\t\tWhat is your grade?\t\t");
    scanf("%f",&grade);
    
    if ((grade<=4.0) && (grade>=3.8)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tExcellent");
    }
    else if ((grade<=3.7) && (grade>=3.3)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tSuperior");
    }
    else if ((grade<=3.2) && (grade>=2.8)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tGood");
    }
    else if ((grade<=3.7) && (grade>=1.8)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tAverage");
    }
    else if ((grade<=1.7) && (grade>=1.3)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tBelow Average");
    }
    else if ((grade<=1.2) && (grade>=1.0)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tPassing");
    }
    else if ((grade<=1.0) && (grade>=0)){
        printf("\n\t\tInput grade: %.1f",grade);
        printf("\n\t\tFailure");
    }
    else{
        printf("\n\t\tInvalid input...");
    }
    return 0;
}
  • 5
    What should this do if a grade is, say, 3.75? – Scott Hunter Oct 04 '22 at 13:09
  • Please [edit] your question and add some example input you use to reproduce the problem, and the corresponding actual output and the expected output. – Bodo Oct 04 '22 at 13:10
  • 6
    Note that equality comparisons with floating-point numbers can yield unexpected results. See, for example: https://stackoverflow.com/q/8364189/10871073 – Adrian Mole Oct 04 '22 at 13:11
  • The range `>= 0.0` and `< 1.0 is also not defined in your specification. – Bodo Oct 04 '22 at 13:13
  • @ScottHunter prints average. This is one of the the statements that work – Jude Joseph Agustino Oct 04 '22 at 13:20
  • @Bodo Added samples also I think it was already defined "else if ((grade<=1.0) && (grade>=0))" – Jude Joseph Agustino Oct 04 '22 at 13:21
  • @AdrianMole how can I avoid this problem? What should I be using instead of float? – Jude Joseph Agustino Oct 04 '22 at 13:24
  • 3
    @ScottHunter Your table specifies e.g. 3.8 - 4.0 and 3.3 - 3.7. It does not tell what should happen between 3.7 and 3.8, e.g. 3.75. Why do you expect "Average" for 3.75? The table has more similar gaps. The implementation `else if ((grade<=1.0) && (grade>=0))` is not specified in your table. Your code has a case "Good" which is not mentioned in the table. Please make sure the specification does not obviously differ from the code. – Bodo Oct 04 '22 at 13:25
  • grade=3.75 yields Inavlid Input. – Scott Hunter Oct 04 '22 at 13:30
  • 2
    There appears to be a typo here: `(grade<=3.7) && (grade>=1.8))`. On the other hand, the typo is probably *serendipitously* better than the intended code. – John Bollinger Oct 04 '22 at 13:30
  • You can convert/round the most significant digits to `int` or even `string` before comparing them. By this way you avoid those pesky problems with `float` representation issues. At any rate better do it in a second step, first fix the ranges and make it work for simpler cases (values that are exactly equal to the range limit). – Jardel Lucca Oct 04 '22 at 13:31
  • @ScottHunter my bad I didn't see the 5 – Jude Joseph Agustino Oct 04 '22 at 13:34
  • 1
    Multiply the float entered by 10.00001, then convert to integer and compare against integer ranges (that are 10x the numbers you show)... That will remedy one problem. The intervals are, as already pointed out, not contiguous in floating point, but would be as (10x) integers... – Fe2O3 Oct 04 '22 at 13:36

1 Answers1

2

equal to sometimes the start of the range or the end of the range, skips...

Floating point numbers are rarely exactly the value you see. Try to imagine adding the fractions 1/2 + 1/4 + 1/8 + 1/16... to see that floating point values can only be approximately equal to the rounded base-10 values they represent; sometimes a tiny, tiny fraction more, sometimes a tiny fraction less. To test for equality is likely to disappoint.

Below, the user can comfortably enter a familiar 2 digit grade point. The value is immediately scaled up by 10 (with a smidgen more to 'push' reluctant values above the cut-off thresholds), then converted to a reliable binary value, albeit 10x larger.

This makes "integer comparison" a breeze.

Rather than clutter the code with if/else ladders, this code is a tiny bit less efficient, but is easy to visually scan to confirm values. (These values come from your code.) A "text evaluation" is decided, and a single printf serves. (Don't waste time mucking with tabs and "layout" until the code is working.) And, negatives are handled as if they were positive values.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    float grade;
    
    printf( "What is your grade? " );
    scanf( "%f",&grade );
    /* omitting test for success */
    
    int x = abs(grade * 10.0001); // to ensure not "slipping under"
    char *eval = NULL;

    if( eval == NULL && x >  40 ) eval = "Invalid input";
    if( eval == NULL && x >= 38 ) eval = "Excellent";
    if( eval == NULL && x >= 33 ) eval = "Superior";
    if( eval == NULL && x >= 28 ) eval = "Good";
    if( eval == NULL && x >= 18 ) eval = "Average";
    if( eval == NULL && x >= 13 ) eval = "Below Average";
    if( eval == NULL && x >= 10 ) eval = "Passing";
    if( eval == NULL            ) eval = "Failure";

    printf( "Input grade: %.1f - %s\n", grade, eval );

    return 0;
}

EDIT:
Some will hate it, but some appreciate the clarity of this version. The processor makes a number of assignments that are likely to immediately be overwritten, but the code is minimal and machine cycles are cheap.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    float grade;
    
    printf( "What is your grade? " );
    scanf( "%f", &grade );
    /* omitting test for success */
    
    int x = abs(grade * 10.0001); // to ensure not "slipping under"

            char *eval = "Failure";
    if( x >= 10 ) eval = "Passing";
    if( x >= 13 ) eval = "Below Average";
    if( x >= 18 ) eval = "Average";
    if( x >= 28 ) eval = "Good";
    if( x >= 33 ) eval = "Superior";
    if( x >= 38 ) eval = "Excellent";
    if( x >  40 ) eval = "Invalid input";

    printf( "Input grade: %.1f - %s\n", grade, eval );

    return 0;
}
Fe2O3
  • 6,077
  • 2
  • 4
  • 20
  • 1
    I think it would be more understandable if you skipped the `eval == NULL &&` and just have `else if`, but good approach. – Neil Oct 04 '22 at 14:42