-2

I created a C program for a question and I am facing some problem given below. I have used logical and conditional operators in this program.

//Question - c4.d.f
/* 
A certain grade of steel is graded according to the following conditions:
(i)Hardness must be greater than 50 
(ii)Carbon content must be less than 0.7
(iii)Tensile strength must be greater than 5600

The grades are as follows:
Grade is 10 if all three conditions are met 
Grade is 9 if conditions (i) and (ii) are met 
Grade 8 if conditions (ii) and (iii) are met
Grade 7 if conditions (i) and (iii) are met
Grade 6 if only one condition is met
Grade is 5 if none of the conditions are met

Write a program, which will require the user to give values of hardness,
carbon content, and tensile strength of the steel under consideration and
output the grade of the steel.
*/

#include<stdio.h>

int main()
{
    int hrd,tslstr;
    float crbct;
    int con1, con2, con3;
    printf("Please enter the values of the Hardness, Carbon content, Tensile Strength\n");
    scanf("%d%f%d",&hrd,&crbct,&tslstr);

    //conditions
    hrd>50?con1=1:(con1=0);
    crbct<0.7?con2=1:(con2=0);
    tslstr>5600?con3=1:(con3=0);

    //Calculating Grades
    if( con1 && con2 && con3)
        printf("Grade 10\n");
    else if( con1 && con2 )
        printf("Grade 9\n");
    else if( con2 && con3 )
        printf("Grade 8\n");
    else if( con1 && con3 )
        printf("Grade 7\n");
    else if( con1 || con2 || con3 )
        printf("Grade 6\n");
    else 
        printf("Grade 5\n");
    
return 0;
}

I run the program and give the values (given below) , so I get "Grade 5" printed but it's printing "Grade 6". Please help me to find the problem in this code.

Please enter the values of the Hardness, Carbon content, Tensile Strength
50
0.7
5600
Grade 6
Yun
  • 3,056
  • 6
  • 9
  • 28
  • 3
    Please learn how to use a *debugger* to step through your code statement by statement while monitoring variables and theif values. – Some programmer dude Aug 21 '21 at 12:51
  • 2
    And don't do statements like `hrd>50?con1=1:(con1=0);`. Prefer plain `if else` statements as it will make the code much easier to read and understand, but if you absolutely must use ternary expression use it on the right-hand side of an assignment (`con1 = hdr > 50 ? 1 : 0;`, or considering that boolean result are either `1` for true and `0` for false: `con1 = hdr > 50;`) – Some programmer dude Aug 21 '21 at 12:52
  • ... and if you feel that you don't know how to use the debugger, as a first step print the values of con1, con2, and con3. It should give you a clue as to which one has a problem. You may discover for example that con2 is 1. If that happens, you would then print the value of crbct. If you then see that it is for example 0.6999999 you would know that a floating point issue caused your problem. – Gonen I Aug 21 '21 at 12:55

3 Answers3

2

crbct is a float, but you compare it to a double, 0.7. float and double arithmetic approximate real-number arithmetic, and they use different approximations. The float value that is closest to .7 happens to be less than the double value that is closest to .7, so .7f < .7 evaluates as true.

The easiest way to “fix” your program is to compare to a float, 0.7f:

crbct<0.7f ? con2=1 : con2=0;

This will handle the floating-point numbers as accurately as the type float allows. It will still be subject to rounding errors on input (so inputs of “.6999998” and “.7” are both treated as less than .7, even though the latter is clearly not), but there will not be any further errors. (If you want to be completely correct about testing whether the input is less than .7, you must read it as a string and handle the comparison manually, without using floating-point arithmetic.)

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
1

It is due to precision issue. Most modern C++ implementation use IEEE-754 with single precision for float. In this format, the closest to 0.7 in single precision is 0.699999988079071044921875. Therefore it is smaller than 0.7

Usually if you really have to compare floating-point numbers, you need to add an epsilon (i.e. a very small number that will overcome the precision issue while not affecting the result). But as the comments pointed out, this is not a general solution and is just comparing with tolerance. Therefore, you must take it with caution. You need to think about whether it is suitable for your case. However, if you really want to do it with epsilons, your program can be changed as follow:

Just change the relevant code to

float eps = (float)1e-6;
crbct+eps<0.7?con2=1:(con2=0);
TYeung
  • 2,579
  • 2
  • 15
  • 30
  • 1
    Please do not recommend comparing with a tolerance. [There is no general solution for comparing floating-point numbers that contain errors from previous operations.](https://stackoverflow.com/questions/56039679/compare-two-float-variables-in-c/56040270#56040270) The solution you propose will decrease false negatives but increase false positives, so it does not “fix” the program as you say it does; it just changes the type of bug it has. Additionally, the code you show does not actually work in this program; for the input in the question, it still produces the undesired output, “Grade 6”. – Eric Postpischil Aug 21 '21 at 13:14
  • I usually round my values to x decimal places for comparison. – Andrew Truckle Aug 21 '21 at 13:18
  • @AndrewTruckle: That method also introduces errors. Rounding moves many numbers a little closer together (1.234 and 1.233 to 1.23) but moves a few numbers much farther apart (1.23499 and 1.23501 to 1.23 and 1.24). – Eric Postpischil Aug 21 '21 at 13:19
  • @EricPostpischil it has suited the needs for the tools I work with. Rounding to 3 dp usually is before the discrepancies kick in so we get a match. – Andrew Truckle Aug 21 '21 at 13:21
  • @EricPostpischil Yes I always forget about that. Also, I think introducing a way to solve the problem to the OP is not a bad idea, I have added some reminders for the OP. – TYeung Aug 21 '21 at 13:21
  • Good point, @EricPostpischil. Anyway in this case the value compared to 0.7 doesn't come from previos calculations but it is directly stored by `scanf`. So I think that performing `crbct<0.7f` would be enough. – Roberto Caboni Aug 21 '21 at 13:21
  • 1
    @AndrewTruckle: Rounding has known errors, as I demonstrated. The fact you have not observed such errors in your programs does not negate the fact that rounding has known errors when used for this purpose. – Eric Postpischil Aug 21 '21 at 13:29
  • Hi @user381466 if this or any answer has solved your question please consider [accepting it](https://meta.stackexchange.com/q/5234/179419) by clicking the check-mark. This indicates to the wider community that you've found a solution and gives some reputation to both the answerer and yourself. There is no obligation to do this. – TYeung Sep 01 '21 at 15:46
0
#include<stdio.h>

int main()
{
    int hrd,tslstr;
    float crbct;
    int con1, con2, con3;
    printf("Please enter the values of the Hardness, Carbon content, Tensile Strength\n");
    scanf("%d%f%d",&hrd,&crbct,&tslstr);

    //conditions
    con1 = (hrd>50) ? 1: 0;
    con2 = (crbct<0.7) ? 1 : 0;
    con3 = (tslstr>5600) ? 1 : 0;

    //Calculating Grades
    if( con1 && con2 && con3)
        printf("Grade 10\n");
    else if( con1 && con2 )
        printf("Grade 9\n");
    else if( con2 && con3 )
        printf("Grade 8\n");
    else if( con1 && con3 )
        printf("Grade 7\n");
    else if( con1 || con2 || con3 )
        printf("Grade 6\n");
    else 
        printf("Grade 5\n");
    
return 0;
}