LinuxQuestions.org
Review your favorite Linux distribution.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 06-26-2022, 02:47 AM   #1
mq15
Member
 
Registered: Apr 2009
Location: Pakistan
Distribution: Linux Mint Cinnamon
Posts: 224

Rep: Reputation: 31
Question simple if-else with output beyond wits!!


Hello there.

Please consider this simple C program;

Code:
#include <stdio.h>
int main() {
    float a = .5, b = .7;
    if (b < .7)
       if (a < .5)
          printf("TELO");
       else
          printf("LTTE");
    else
       printf("JKLF");
    return 0;
}
Here is the output:
Quote:
LTTE
The output that I expect is JKLF as the condition b < .7 is false; therefore, the control should not enter the inner if and should reach its own or else printing JKLF.

QUESTION#1: How does the control reach LTTE?


However, if the float data type is changed to int, constants .5 and .7 to 5 and 7 respectively, then the output yields what I expect, i.e., JKLF

QUESTION#2: How does the control reach JKLF after the aforementioned change?

Thanking you in anticipation.
 
Old 06-26-2022, 06:02 AM   #2
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,883
Blog Entries: 13

Rep: Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931
Probably something to do with the fact that their floating point.

I'd look at it in the debugger where (a) you can see the exact values of those variables, need to use -O0, and (b) you can see the disassembly of the compare lines.

I wonder if the constants are treated as ints and rounded up.

I'd try the same experiment with variables in place of the constants.
 
1 members found this post helpful.
Old 06-26-2022, 06:17 AM   #3
EdGr
Senior Member
 
Registered: Dec 2010
Location: California, USA
Distribution: I run my own OS
Posts: 1,003

Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
.5 and .7 are double precision. The "if" statements are comparing float against double.
Ed
 
2 members found this post helpful.
Old 06-26-2022, 07:53 AM   #4
Ser Olmy
Senior Member
 
Registered: Jan 2012
Distribution: Slackware
Posts: 3,347

Rep: Reputation: Disabled
Why don't you change the values to something like .5000001 and .7000001 respectively, and see what that does?

And how about modifying the printf statements to print the values as well? I'm sure that will tell you something.
 
3 members found this post helpful.
Old 06-26-2022, 08:28 AM   #5
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,883
Blog Entries: 13

Rep: Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931Reputation: 4931
Whether or not you've run into this before, this is a detail to remember, that floats and doubles are 'special'. Not that there aren't any conventions, there absolutely are, but one has to learn them. Myself, the few times I work with them, I learn what I need. Certain types of scientific programming sometimes require a lot of this.
 
1 members found this post helpful.
Old 06-26-2022, 08:28 AM   #6
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
As others have said.

test1.c
Code:
#include <stdio.h>

int main() 
{
    double a = .5, b = .7;
    
    if (b < .7)
        if (a < .5)
            printf("TELO");
        else
            printf("LTTE");
    else
        printf("JKLF");
        
    printf("\n");
        
    return 0;
}

//gcc test1.c -o test1
Code:
./test1
JKLF

Last edited by teckk; 06-26-2022 at 08:31 AM.
 
1 members found this post helpful.
Old 06-26-2022, 09:16 AM   #7
mq15
Member
 
Registered: Apr 2009
Location: Pakistan
Distribution: Linux Mint Cinnamon
Posts: 224

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by Ser Olmy View Post
...
And how about modifying the printf statements to print the values as well? I'm sure that will tell you something.
Output with float;
a = 0.500000 b = 0.700000 LTTE


Output with int;
a = 5 b = 7 JKLF
 
Old 06-26-2022, 09:19 AM   #8
mq15
Member
 
Registered: Apr 2009
Location: Pakistan
Distribution: Linux Mint Cinnamon
Posts: 224

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by EdGr View Post
.5 and .7 are double precision. The "if" statements are comparing float against double.
Ed
Would you please elaborate?
 
Old 06-26-2022, 09:45 AM   #9
Ser Olmy
Senior Member
 
Registered: Jan 2012
Distribution: Slackware
Posts: 3,347

Rep: Reputation: Disabled
Quote:
Originally Posted by mq15 View Post
Would you please elaborate?
I'm not EdGr, but I'll give it a shot.

Consider this program:
Code:
#include <stdio.h>
int main() {
    float a = .7;
    double c = .7;
    if (a < c) {
      printf("What the...?\n");
    }
    return 0;
}
Run it, watch the result, and then recompile with both values changed to .5.

What's going on here, is that some decimal values do not map directly to binary, so different approximations are used when such values are stored as double or float respectively. Conversion between types will amplify these inaccuracies.

Constants in if statements are not treated as the type they are being compared to. Instead, they default to double. As a result, the statement if (a < .7) in your original program ends up becoming "if the result of typecasting a to double is less than the double approximation of the decimal number .7", which is probably not what you wanted. Or what anyone would want, really.
 
1 members found this post helpful.
Old 06-26-2022, 09:52 AM   #10
teckk
LQ Guru
 
Registered: Oct 2004
Distribution: Arch
Posts: 5,152
Blog Entries: 6

Rep: Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835Reputation: 1835
https://www.tutorialspoint.com/float-and-double-in-c
https://www.c-programming-simple-steps.com/c-float.html

Did you try this?

test2.c
Code:
#include <stdio.h>

int main() 
{
    float a = 1.5;
    float b = 1.7;
    
    if ( b < 1.7 )
        if ( a < 1.5 )
            printf("TELO");
        else
            printf("LTTE");
    else
        printf("JKLF");
        
    printf("\n");
        
    return 0;
}

//gcc test2.c -o test2
Code:
./test2
JKLF
 
Old 06-26-2022, 12:14 PM   #11
EdGr
Senior Member
 
Registered: Dec 2010
Location: California, USA
Distribution: I run my own OS
Posts: 1,003

Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
Quote:
Originally Posted by mq15 View Post
Would you please elaborate?
The precision is different. You generally don't want to mix float and double.

You can make the compiler see the constants as float by appending an 'F', i.e. .5F and .7F
Ed
 
1 members found this post helpful.
Old 06-26-2022, 11:57 PM   #12
mq15
Member
 
Registered: Apr 2009
Location: Pakistan
Distribution: Linux Mint Cinnamon
Posts: 224

Original Poster
Rep: Reputation: 31
Quote:
Originally Posted by Ser Olmy View Post
I'm not EdGr, but I'll give it a shot.

Consider this program:
Code:
#include <stdio.h>
int main() {
    float a = .7;
    double c = .7;
    if (a < c) {
      printf("What the...?\n");
    }
    return 0;
}
Run it, watch the result, and then recompile with both values changed to .5.

What's going on here, is that some decimal values do not map directly to binary, so different approximations are used when such values are stored as double or float respectively. Conversion between types will amplify these inaccuracies.

Constants in if statements are not treated as the type they are being compared to. Instead, they default to double. As a result, the statement if (a < .7) in your original program ends up becoming "if the result of typecasting a to double is less than the double approximation of the decimal number .7", which is probably not what you wanted. Or what anyone would want, really.
The output of your code is:
Quote:
What the...?
Which clearly means, float a = .7 is considered smaller than double c = .7.

But the output of the code after changing .7 to .5 simply returns. This clearly means that float a = .5 is considered greater than double c = .5

This is strange and unintelligible to me.
 
Old 06-27-2022, 01:55 AM   #13
EdGr
Senior Member
 
Registered: Dec 2010
Location: California, USA
Distribution: I run my own OS
Posts: 1,003

Rep: Reputation: 474Reputation: 474Reputation: 474Reputation: 474Reputation: 474
The different behavior is due to .5 being expressed exactly in binary floating-point while .7 is being expressed as an approximation.
Ed
 
2 members found this post helpful.
Old 06-27-2022, 02:56 AM   #14
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,881
Blog Entries: 1

Rep: Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871Reputation: 1871
When in doubt, just print the difference
Code:
printf("%g-%g=%g\n", b, 0.7, b-0.7);
 
2 members found this post helpful.
Old 06-28-2022, 11:03 PM   #15
mq15
Member
 
Registered: Apr 2009
Location: Pakistan
Distribution: Linux Mint Cinnamon
Posts: 224

Original Poster
Rep: Reputation: 31
Wink

Thanks to everyone who participated. It literally helped. However, EdGr concluded it here;
Quote:
Originally Posted by EdGr View Post
The different behavior is due to .5 being expressed exactly in binary floating-point while .7 is being expressed as an approximation.
Ed
And NevemTeve provided a simple means for the proof;

Quote:
Originally Posted by NevemTeve View Post
When in doubt, just print the difference
Code:
printf("%g-%g=%g\n", b, 0.7, b-0.7);
So, please observe the code and the output;

Code:
#include <stdio.h>
int main() {
    float  b = .7, a = 0.5;
    printf("%g -%g = %g\n", a, 0.5, a-0.5);
    printf("%g -%g = %g\n", b, 0.7, b-0.7);
    return 0;
}
Quote:
0.5 -0.5 = 0
0.7 -0.7 = -1.19209e-08
Happy Coding!
 
1 members found this post helpful.
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
nearing wits end enoch1977 Linux - Networking 19 09-30-2006 07:35 PM
Xorg, mouse side-buttons and xmodmap. At the end of my wits. Nordmann Slackware 3 08-23-2004 02:18 PM
nVidia MX 440--Drivers will not compile. At my wits end. tsw Linux - Hardware 8 08-04-2004 11:18 PM
Sendmail Confit - Wits End bdbourn Linux - Software 4 07-29-2003 08:57 PM
I'm am completely stumped and at my wits end jtX Linux - General 16 06-25-2003 06:35 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 02:02 AM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration