C++ if statements - only last one is ever true

R

root

Hi group,

Apologies in advance if this has been asked somewhere before, but I haven't
managed to get anything from the Google archives - I've been getting
introductory guides to C++ all day long.

I am writing a program in Visual C++ 6 SP5.
My code has a lot of "if" statements - 19 to be exact.
If the if statements are true (technically, there should only be one that is
ever true), the program needs to continue on after the if statements.
Each if statement assigns a particular string value to a character/string
array if the if statement is true.

Unfortunately, I have the problem whereby only my 19th if statement is ever
true. The rest never become true no matter what changes I make to my
variables.

I know using one big "switch" would be appropriate here, but is it possible
to use switch with a float as its condition? My Visual C++ compiler didn't
like it when I used that.

Apologies for so many questions... any help would be appreciated.

Thanks!
 
C

Clark Cox

root said:
Hi group,

Apologies in advance if this has been asked somewhere before, but I haven't
managed to get anything from the Google archives - I've been getting
introductory guides to C++ all day long.

I am writing a program in Visual C++ 6 SP5.
My code has a lot of "if" statements - 19 to be exact.
If the if statements are true (technically, there should only be one that is
ever true), the program needs to continue on after the if statements.
Each if statement assigns a particular string value to a character/string
array if the if statement is true.

Unfortunately, I have the problem whereby only my 19th if statement is ever
true. The rest never become true no matter what changes I make to my
variables.

I know using one big "switch" would be appropriate here, but is it possible
to use switch with a float as its condition? My Visual C++ compiler didn't
like it when I used that.

Apologies for so many questions... any help would be appreciated.

Thanks!

Although I can't be sure, as your were rather vague about what the
conditions these if statements are checking for are, it sounds to me
like you're trying to test floating point values for equality, which is
a big no-no. Check out:

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.17
 
J

John Carson

root said:
Hi group,

Apologies in advance if this has been asked somewhere before, but I
haven't managed to get anything from the Google archives - I've been
getting introductory guides to C++ all day long.

I am writing a program in Visual C++ 6 SP5.
My code has a lot of "if" statements - 19 to be exact.
If the if statements are true (technically, there should only be one
that is ever true), the program needs to continue on after the if
statements.
Each if statement assigns a particular string value to a
character/string array if the if statement is true.

Unfortunately, I have the problem whereby only my 19th if statement
is ever true. The rest never become true no matter what changes I
make to my variables.

You obviously have a bug in your code.
I know using one big "switch" would be appropriate here, but is it
possible to use switch with a float as its condition?

No it isn't.

Post your code (in compileable form) and people here will

1. Find the bug.
2. Possibly suggest a more elegant solution.
 
C

Christof

root said:
Hi group,

Apologies in advance if this has been asked somewhere before, but I haven't
managed to get anything from the Google archives - I've been getting
introductory guides to C++ all day long.

I am writing a program in Visual C++ 6 SP5.
My code has a lot of "if" statements - 19 to be exact.
If the if statements are true (technically, there should only be one that is
ever true), the program needs to continue on after the if statements.
Each if statement assigns a particular string value to a character/string
array if the if statement is true.

Unfortunately, I have the problem whereby only my 19th if statement is ever
true. The rest never become true no matter what changes I make to my
variables.

I know using one big "switch" would be appropriate here, but is it possible
to use switch with a float as its condition? My Visual C++ compiler didn't
like it when I used that.

Apologies for so many questions... any help would be appreciated.

Thanks!
Hello nameless poster,

we can't help you without seeing your code, so please try to minimize
the problem and post your code here.
 
R

root

Thanks for all your replies so far.

I can't post the entire block of code here for commercial reasons, but a
selection of the if statements are:

if(difference == 0.000) {
strcpy(PFM_Date,"A5"); }

if(difference == 0.052 || 0.053) {
strcpy(PFM_Date,"M25"); }

if(difference == 0.894 || 0.895) {
strcpy(PFM_Date,"M29"); }

if(difference == 0.947 || 0.948) {
strcpy(PFM_Date,"A17"); }

where:

difference is of type float
and PFM_Date[4] of type char.

I am trying to set PFM_Date to a three-letter code if the conditions I've
posted have been met. Only one of these many if statements will ever be
true. My source file is of type .cpp in VC++ 6, SP5.

TIA.
 
C

Christof Krueger

root said:
Thanks for all your replies so far.

I can't post the entire block of code here for commercial reasons, but a
selection of the if statements are:

if(difference == 0.000) {
strcpy(PFM_Date,"A5"); }

if(difference == 0.052 || 0.053) {
strcpy(PFM_Date,"M25"); }

if(difference == 0.894 || 0.895) {
strcpy(PFM_Date,"M29"); }

if(difference == 0.947 || 0.948) {
strcpy(PFM_Date,"A17"); }
What you are doing here is the following:

if ( (difference == 0.947) || (0.948) ) {
strcpy(PFM_Date,"A17"); }

That means that your if-condition is true when either (difference ==
0.947) is true, or if (0.948) is true. In C++ numeric values that are
not 0 _always_ return true.
In your posted code the last three strcpy-statements are executed, but
you only see the effect of the last one, because it overwrites the
contents of PFM_Date.
What you probably mean is

if ( (difference == 0.947) || (difference == 0.948) ) {
strcpy(PFM_Date,"A17"); }


Another _very_ important point: Never check float values for equality.
There is no exact binary representation for the number 0.01 for example.
So you should rather use if-statements in the following form:

if ( (difference >= 0.947) || (difference < 0.948) ) {
strcpy(PFM_Date,"A17"); }

And even this can lead to wrong results because of rounding.
 
D

david m-

Not convinced that any of the sample given evaluate to true!

However,

if (difference == 0.947 || 0.948)

== has a higher precedence than || so the expression is

(difference == 0.947) || 0.948

the equality operator returns true of false
the boolean OR operator || returns true or false.

What you are presumably trying to type is

(difference == 0.947) || (difference == 0.948)

but I'd be very careful of testing floating point values in this way.

Would something like

(difference >= 0.947) && (difference <= 0.948)

suffice?

davd m.
 
R

root

Christof Krueger said:
That means that your if-condition is true when either (difference ==
0.947) is true, or if (0.948) is true. In C++ numeric values that are
not 0 _always_ return true.
In your posted code the last three strcpy-statements are executed, but
you only see the effect of the last one, because it overwrites the
contents of PFM_Date.
What you probably mean is

if ( (difference == 0.947) || (difference == 0.948) ) {
strcpy(PFM_Date,"A17"); }

Thanks for that. I've tried it and now PFM_Date is coming out as blank
(it's being printed using a printf).
Another _very_ important point: Never check float values for equality.
There is no exact binary representation for the number 0.01 for example.
So you should rather use if-statements in the following form:

if ( (difference >= 0.947) || (difference < 0.948) ) {
strcpy(PFM_Date,"A17"); }

And even this can lead to wrong results because of rounding.

I know this is really bad programming, but I must check for those specific
values. Maybe C++ isn't the best language for this.

Thanks again anyway.
 
C

Christof Krueger

root said:
Thanks for that. I've tried it and now PFM_Date is coming out as blank
(it's being printed using a printf).
It's blank because none of the if-statements ever are true (I assume
because you test float numbers for equality).
Do you really want to test for the *exact* value 0.947 or the *exact*
value 0.948? Should the test fail for 0.9475? Or for 0.94700001? And
what's with 0.94699999?
 
P

Paul

root said:
I know this is really bad programming, but I must check for those specific
values. Maybe C++ isn't the best language for this.
Checking for exact floating point values is not only bad programming in C++,
it's bad programming in most other languages. Try the same thing with
Fortran, C, BASIC, Pascal -- you'll get the same problems.

What you need is to either use a library that gives you more precision
(usually these libraries are used for business calculations, where exact
arithmetic is mandatory), or use a language that has exact representation of
such numbers. Maybe COBOL.

Paul
 
M

Martijn Lievaart

Thanks for all your replies so far.

I can't post the entire block of code here for commercial reasons, but a
selection of the if statements are:

if(difference == 0.000) {
strcpy(PFM_Date,"A5"); }

if(difference == 0.052 || 0.053) {
strcpy(PFM_Date,"M25"); }

if(difference == 0.894 || 0.895) {
strcpy(PFM_Date,"M29"); }

if(difference == 0.947 || 0.948) {
strcpy(PFM_Date,"A17"); }

where:

difference is of type float
and PFM_Date[4] of type char.

I am trying to set PFM_Date to a three-letter code if the conditions I've
posted have been met. Only one of these many if statements will ever be
true. My source file is of type .cpp in VC++ 6, SP5.

Sounds like you need fixed point (exact) arithmetic, not floating point.
The precision of floating point is not exact, you need to compare to some
delta. In your case it seems like a delta of 0.0005 is adequate, but
without the exact requirements, one cannot tell.

Fixed point arithmetic is not directly supported by C, but you my want to
look into counting promilles directly in a long.

HTH,
M4
 
R

root

Christof Krueger said:
It's blank because none of the if-statements ever are true (I assume
because you test float numbers for equality).
Do you really want to test for the *exact* value 0.947 or the *exact*
value 0.948? Should the test fail for 0.9475? Or for 0.94700001? And
what's with 0.94699999?

I'm basically comparing the result of a calculation (a division to be exact)
against a table of alphanumeric codes. 0.9475 needs to be taken as 0.947
with regards to what I need, as I only need the first three digits.

Would it be a better idea, if I managed to do the division, get the decimal
values, and convert them to integers, thus losing the remaining decimal
values and not having to worry about if statements and float variables? As
another poster pointed out, the OR part in the if statement is there to
cover me for rounding errors (not really full-proof).

For example, if after the division I end up with 158.947123456780.......,
would it be a better idea (perhaps more robust?) to get 0.947 by taking the
difference of the above number and the division using integer division (as I
am currently doing), then multiplying 0.947 by, say 100, to get 947 and
putting it in another, integer type variable?

Thanks again to you all for your replies. Apologies for the slightly
complicated post!
 
R

root

Paul said:
Checking for exact floating point values is not only bad programming in C++,
it's bad programming in most other languages. Try the same thing with
Fortran, C, BASIC, Pascal -- you'll get the same problems.

Perl perhaps?
What you need is to either use a library that gives you more precision
(usually these libraries are used for business calculations, where exact
arithmetic is mandatory), or use a language that has exact representation of
such numbers. Maybe COBOL.

What, you mean the Complete and Obsolete Business Orientated Business
Language? ;-)
 
C

Christof Krueger

root said:
I'm basically comparing the result of a calculation (a division to be exact)
against a table of alphanumeric codes. 0.9475 needs to be taken as 0.947
with regards to what I need, as I only need the first three digits.

Would it be a better idea, if I managed to do the division, get the decimal
values, and convert them to integers, thus losing the remaining decimal
values and not having to worry about if statements and float variables? As
another poster pointed out, the OR part in the if statement is there to
cover me for rounding errors (not really full-proof).

For example, if after the division I end up with 158.947123456780.......,
would it be a better idea (perhaps more robust?) to get 0.947 by taking the
difference of the above number and the division using integer division (as I
am currently doing), then multiplying 0.947 by, say 100, to get 947 and
putting it in another, integer type variable?
I'm sure 100 was a typo and you mean 1000. But that is what I would have
suggested. You could cast it to int (I think that always truncates
towards zero, but correct me if I am wrong) and then check against your
hard-coded values to do whatever you want to do.
Because rounding errors can occur with FP arithmetics very easily, you
probably still should check for ranges rather than for fixed numbers.

What you would do at the moment is

float a = <whatever>;
float b = <whatever>;
float c = a / b; // rounding errors!
c -= (int)c // works well assuming you don't have negative numbers
int d = (int)(c * 1000)
with d containing numbers from 0 to 999

If a and b are integral values, you could even do the following which is
equivalent:

int a = <whatever>;
int b = <whatever>;
int c = a % b; // modulo
int d = (c * 1000) / b; // integer division rounds down (truncates)

This code should be faster on common architectures (no, i can't prove
it), and should be more predictible concerning rounding errors because
no architecture dependent FP errors can occur. The only assumption made
here is that integer division rounds towards zero.

If you can rewrite your code like this depends on the nature of your
calculation. With integer arithmetic you do not have rounding errors,
but you should be very careful not to let your variables overflow. (e.g.
the operation 70000*65000 already overflows an unsigned 32bit integer!)
 
R

root

I'm sure 100 was a typo and you mean 1000. But that is what I would have
suggested. You could cast it to int (I think that always truncates
towards zero, but correct me if I am wrong) and then check against your
hard-coded values to do whatever you want to do.
Because rounding errors can occur with FP arithmetics very easily, you
probably still should check for ranges rather than for fixed numbers.

Hi again.
Yes, it was a typo! tried it with 1,000 yesterday and it worked a treat. I
did something similar to what you recommended below, though not in as few
lines as you did.
All's well that ends well.
My thanks to the group, especially to you, Christof. You've been a great
help.

Hapy 2004 to you all!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top