[comp.lang.c] Problem with

vanpetegem@liszt.kulesat.uucp (05/24/89)

  Hello every C programmer there,

I have a problem with VAX C V2.4-026 under VMS V5.0-2.

The code with which I am in trouble, goes as follows:

	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
           {
             ..... (in some expressions k is changed, depending on n)
	   }

What I want to do is simply perform the test (k > 2) as ending test for the
"for-loop", except in the cases where n is dividable by 10. In the latter
situation the test (n < 100) has to be done. But... When n becomes equal to
10 the "for-loop" is stopped already. So I think neither the first nor the
second test is evaluated and only (n % 10) is taken into account (the first
test (k > 2) is only important for n taking values from 50 on).

Is the above syntax not allowed (I doubt: the compiler gives no error
messages) ? Or what is wrong with it ? Any suggestions to overcome this
problem ?


Thanks in advance for every answer that can help me.


                                   Wim VP.


===============================================================================

  Wim Van Petegem                     Phone: + 32 16 / 22 09 31 (1083)
  Katholieke Universiteit Leuven      Telex: 25941 elekul
  Departement Elektrotechniek         Fax:   + 32 16 / 22 18 55 
  Afdeling ESAT-MICAS                 BITNET: vanpetegem%kulesat.uucp@blekul60
  Kardinaal Mercierlaan 94            UUCP:   vanpetegem@kulesat.uucp
  3030 Heverlee
  BELGIUM

===============================================================================

chris@mimsy.UUCP (Chris Torek) (05/24/89)

In article <1200@liszt.kulesat.uucp> vanpetegem@liszt.kulesat.uucp writes:
>I have a problem with VAX C V2.4-026 under VMS V5.0-2.

>	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)

>... When n becomes equal to 10 the "for-loop" is stopped already.
>So I think neither the first nor the second test is evaluated and only
>(n % 10) is taken into account (the first test (k > 2) is only important
>for n taking values from 50 on).

It sounds as though you have found a bug in the compiler.  The large
`for' expression should evaluate to either 1 or 0: if (n % 10) is
nonzero, the result is 1 iff k > 2; otherwise, the result is 1 iff n <
100.  You should look at the assembly produced by the compiler to see
whether the compiler simply `forgot' to generate parts of the
expression---for instance, it may have produced

	n % 10 && k > 2

instead.  If so, rewriting the test as

	((n % 10) != 0 && k > 2) || n < 100

will probably get around the bug.  (Any valid `logical' [true/false]
e1?e2:e3 expression can always be transformed this way into (e1&&e2)||e3,
provided e3 has no side effects.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

barmar@think.COM (Barry Margolin) (05/25/89)

In article <1200@liszt.kulesat.uucp> vanpetegem@liszt.kulesat.uucp writes:
>The code with which I am in trouble, goes as follows:
>
>	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)
>                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>           {
>             ..... (in some expressions k is changed, depending on n)
>	   }
>
>What I want to do is simply perform the test (k > 2) as ending test for the
>"for-loop", except in the cases where n is dividable by 10. In the latter
>situation the test (n < 100) has to be done.

The sense of the test clause of your :? expression is wrong.  When n
is divisible by 10, (n % 10) is 0, and 0 represents "false" in C.  I
would write your end test as

	((n % 10) == 0) ? (k > 2) : (n < 100)

although "real C programmers" would probably write it as

	(n % 10) ? (n < 100) : (k > 2)

i.e. they would just interchange the true and false clauses, taking
advantage of the fact that the result of the % can be used as a
boolean.

Barry Margolin
Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

bengsig@oracle.nl (Bjorn Engsig) (05/25/89)

In article <17722@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>  (Any valid `logical' [true/false]
>e1?e2:e3 expression can always be transformed this way into (e1&&e2)||e3,
>provided e3 has no side effects.)
No Chris, this was a bit too fast.  If e1!=0 and e2==0, (e1&&e2)||e3 evaluates
e3 and returns it's truth value, whereas (e1?e2:e3) returns 0 and does not
evaluate e3.
-- 
Bjorn Engsig, ORACLE Europe         \ /    "Hofstadter's Law:  It always takes
Path:   mcvax!orcenl!bengsig         X      longer than you expect, even if you
Domain: bengsig@oracle.nl           / \     take into account Hofstadter's Law"

randolph@ektools.UUCP (Gary L. Randolph) (05/25/89)

In article <20658@news.Think.COM> barmar@kulla.think.com.UUCP (Barry Margolin) writes:
>In article <1200@liszt.kulesat.uucp> vanpetegem@liszt.kulesat.uucp writes:
>>The code with which I am in trouble, goes as follows:
>>
>>	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)
>>                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>           {
>>             ..... (in some expressions k is changed, depending on n)
>>	   }
>>What I want to do is simply perform the test (k > 2) as ending test for the
>>"for-loop", except in the cases where n is dividable by 10. In the latter
>>situation the test (n < 100) has to be done.

=The sense of the test clause of your :? expression is wrong.  When n
=is divisible by 10, (n % 10) is 0, and 0 represents "false" in C.  I
=would write your end test as
=	((n % 10) == 0) ? (k > 2) : (n < 100)
=i.e. they would just interchange the true and false clauses, taking
=advantage of the fact that the result of the % can be used as a
=boolean.

NOOOOO! I do NOT think your logic is wrong.  I am sure it is correct
according to  your explanation of what you want to do.  There *is* a
problem however...

The modulus operator, when used for integer division as in your 
example, truncates the fractional part.  This, of course, makes the
initial check result in a fall out of the for since 1%10 *is* 0 and
therefor the n<100 test is done and, n being 1 bye-bye.

This, I believe is your real problem. Also, you don't mention whether
variable k was initialized before entering the for.  IT SHOULD BE.

I hope this helps...

                           --Gary Randolph

randolph@ektools.UUCP (Gary L. Randolph) (05/25/89)

In article <1917@ektools.UUCP> randolph@ektools.UUCP (Gary L. Randolph) writes:
>In article <20658@news.Think.COM> barmar@kulla.think.com.UUCP (Barry Margolin) writes:
>>In article <1200@liszt.kulesat.uucp> vanpetegem@liszt.kulesat.uucp writes:
>>>The code with which I am in trouble, goes as follows:
>>>
>>>	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)
>>>                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>>           {
>>>             ..... (in some expressions k is changed, depending on n)
>>>	   }
>>>What I want to do is simply perform the test (k > 2) as ending test for the
>>>"for-loop", except in the cases where n is dividable by 10. In the latter
>>>situation the test (n < 100) has to be done.
>
=The sense of the test clause of your :? expression is wrong.  When n
=is divisible by 10, (n % 10) is 0, and 0 represents "false" in C.  I
=would write your end test as
=	((n % 10) == 0) ? (k > 2) : (n < 100)
=i.e. they would just interchange the true and false clauses, taking
=advantage of the fact that the result of the % can be used as a
=boolean.

My original anwer has some problems - PLEASE ignore it...
Here is, I believe, a correct answer.

NOOOOO! I do NOT think your logic is wrong.  I am sure it is correct
according to  your explanation of what you want to do.  There *is* a
problem however...
   ...Stuff here is too wrong (embarrASSing) for me to repeat...
You don't mention whether variable k was initialized before
entering the for.  IT SHOULD BE.

I ran a short test as follows:
main()
{
int n;
float k = 6;
for(n=1;((n % 10) ? (k>2) : (n<100)); n++)
	{
	k -= 2;
	}
printf("n: %d\n k: %f\n",n,k);
}

This produced the expected result:
     n: 3
     k: 2.000000


I hope THIS helps...

                           --Gary Randolph

kens@attila.WEITEK.COM (Ken Stanley) (05/26/89)

In article <17722@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> instead.  If so, rewriting the test as
> 
> 	((n % 10) != 0 && k > 2) || n < 100
> 
> will probably get around the bug.  (Any valid `logical' [true/false]
> e1?e2:e3 expression can always be transformed this way into (e1&&e2)||e3,
> provided e3 has no side effects.)

Yes, the specific example works.  But, the generalization to "Any valid
logical ..." is not true.  Here is the truth table for these
two expressions:

                    e1?e2:e3                (e1&&e2)||e3
 e1, e2, e3         true                    true
 e1, e2,~e3         true                    true
 e1,~e2, e3         false                   true        <<  NOTE DIFFERENCE
 e1,~e2,~e3         false                   false
~e1, e2, e3         true                    true
~e1, e2,~e3         false                   false
~e1,~e2, e3         true                    true
~e1,~e2,~e3         false                   false



The logical expression (e1?e2:e3) is the same as ((e1 && e2) || (~e1 && e3))
which is not the same as ((e1 && e2) || e3)

The specific example: "((n % 10) != 0 && k > 2) || n < 100" works because
when n = 100, (n % 10) == 0 and ! (n < 100).  However, if the loop increment
were 3 instead of 1, it would not.  In other words, the following two 
statements are not identical:

for (n = 1; ((n % 10) != 0 && k > 2) || n < 100; n += 3) 
for (n = 1; ((n % 10) ? (k > 2) : (n < 100); n += 3) 

Whereas these two statements are identical:

for (n = 1; ((n % 10) != 0 && k > 2) || n < 100; n++)
for (n = 1; ((n % 10) ? (k > 2) : (n < 100); n++)

Ken Stanley

karzes@mfci.UUCP (Tom Karzes) (05/26/89)

In article <20658@news.Think.COM> barmar@kulla.think.com.UUCP (Barry Margolin) writes:
}In article <1200@liszt.kulesat.uucp>vanpetegem@liszt.kulesat.uucp writes:
}}The code with which I am in trouble, goes as follows:
}}
}}	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)
}}                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}}           {
}}             ..... (in some expressions k is changed, depending on n)
}}	   }
}}
}}What I want to do is simply perform the test (k > 2) as ending test for the
}}"for-loop", except in the cases where n is dividable by 10. In the latter
}}situation the test (n < 100) has to be done.
}
}The sense of the test clause of your :? expression is wrong.  When n
}is divisible by 10, (n % 10) is 0, and 0 represents "false" in C.  I
}would write your end test as
}
}	((n % 10) == 0) ? (k > 2) : (n < 100)
}
}although "real C programmers" would probably write it as
}
}	(n % 10) ? (n < 100) : (k > 2)
}
}i.e. they would just interchange the true and false clauses, taking
}advantage of the fact that the result of the % can be used as a
}boolean.


Rubbish.  His code should do exactly what he said he wanted it to do.
He said he wants to perform the test (k > 2), EXCEPT in the cases where
n is "dividable" by ten, in which case he wants to use (n < 100).  In
other words, he wants (k > 2) when n is NOT divisable by 10, and (n < 100)
when n is divisable by 10.  Now "n is not divisable by 10" is equivalent
to ((n % 10) != 0).  So he wants:

    (((n % 10) != 0) ? (k > 2) : (n < 100))

which is equivalent to:

    ((n % 10) ? (k > 2) : (n < 100))

which is exactly what he wrote.  When n is NOT divisable by 10, (n % 10)
is non-zero (i.e., true) and you get (k > 2).  When n is divisable by 10,
(n % 10) is zero (i.e., false) and you get (n < 100).

Assuming there isn't any wrong with parts of the code that weren't included
in the original article, it appears that he has encountered a compiler bug.

karzes@mfci.UUCP (Tom Karzes) (05/26/89)

In article <17722@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
}In article <1200@liszt.kulesat.uucp> vanpetegem@liszt.kulesat.uucp writes:
}}I have a problem with VAX C V2.4-026 under VMS V5.0-2.
}
}}	 for(n = 1;  ((n % 10) ? (k > 2) : (n < 100));  n++)
}
}}... When n becomes equal to 10 the "for-loop" is stopped already.
}}So I think neither the first nor the second test is evaluated and only
}}(n % 10) is taken into account (the first test (k > 2) is only important
}}for n taking values from 50 on).
}
}It sounds as though you have found a bug in the compiler.  The large
}`for' expression should evaluate to either 1 or 0: if (n % 10) is
}nonzero, the result is 1 iff k > 2; otherwise, the result is 1 iff n <
}100.  You should look at the assembly produced by the compiler to see
}whether the compiler simply `forgot' to generate parts of the
}expression---for instance, it may have produced
}
}	n % 10 && k > 2
}
}instead.  If so, rewriting the test as
}
}	((n % 10) != 0 && k > 2) || n < 100
}
}will probably get around the bug.  (Any valid `logical' [true/false]
}e1?e2:e3 expression can always be transformed this way into (e1&&e2)||e3,
}provided e3 has no side effects.)


Unless there's something wrong in the code that wasn't included in the
original message, I agree that this is probably a compiler bug.

However, as for your suggested rewrite and claims about equivalent forms
for logical-valued ?: expressions, I'm afraid you've made a fundamental
error in logic.  The expression (e1 ? e2 : e3) is 0 when e1, e2, and e3
are 1, 0, and 1.  The expression ((e1 && e2) || e3) is 1 for this same set
of values.  I.e., (1 ? 0 : 1) is 0, and ((1 && 0) || 1) is 1.

What you meant to say was that the truth value of (e1 ? e2 : e3) is the
same as the truth value of ((e1 && e2) || ((! e1) && e3)) (although you
may have to be careful about evaluating e1 more than once).  Whether or
not e3 has any side effects is irrelevant (as is the question of whether
or not e2 has any side effects).  If e1 is a problem, you could assign
it to a temporary:  (t = e1, ((t && e2) || ((! t) && e3))).

As for this specific example, consider the case where n is 11 and k is 1.
Then (n % 10) is 1, (k > 2) is 0, and (n < 100) is 1.  So the original
expression is 0.  Your expression is 1.

A correct alternate form would be:

    ((((n % 10) != 0) && (k > 2)) || (((n % 10) == 0) && (n < 100)))
or  (t = n % 10, ((t && (k > 2)) || ((! t) && (n < 100))))

Of course, if there are no assignments to n in the loop other than the
increment code in the for statement, you could safely assume that the
first time n reaches or exceeds 100 is when it is exactly 100, i.e.,
that (! (n < 100)) ==> (n == 100) ==> ((n % 10) == 0).  Then you could
write:

    ((((n % 10) == 0) || (k > 2)) && (n < 100))

or perhaps more efficiently (by avoiding the divide unless it is truly
needed) as:

    ((n < 100) && ((k > 2) || ((n % 10) == 0)))

As I said, this test is NOT equivalent when n is greater than 100, but it
should work for (n <= 100).

chris@mimsy.UUCP (Chris Torek) (05/26/89)

>In article <17722@mimsy.UUCP> I claimed that
>>[logical] e1?e2:e3 expression[s] can ... be transformed ... into
>>(e1&&e2)||e3

In article <344.nlhp3@oracle.nl> bengsig@oracle.nl (Bjorn Engsig) writes:
>No Chris, this was a bit too fast.  If e1!=0 and e2==0, (e1&&e2)||e3 evaluates
>e3 and returns it's truth value, whereas (e1?e2:e3) returns 0 and does not
>evaluate e3.

Oops, right.  I think my brain was on fire when I wrote <17722@mimsy.UUCP>.
But e1?e2:e3 *can* be turned into (e1&&e2 || !e1&&e3) [&& has higher
precedence than ||, but you should parenthesise in real code]:

	e1  e2  e3	e1?e2:e3	e1&&e2  !e1&&e3  e1&&e2||!e1&&e3
	--  --  --	--------	------	-------  ---------------
	F   F   F	   F		  F	    F		F
	F   F   T	   T		  F	    T		T
	F   T   F	   F		  F	    F		F
	F   T   T	   T		  F	    T		T
	T   F   F	   F		  F	    F		F
	T   F   T	   F		  F	    F		F
	T   T   F	   T		  T	    F		T
	T   T   T	   T		  T	    F		T

(where F = false = 0, and T = true = nonzero-in 1-out).  The ultimate
test for boolean operations is to draw up a truth table....
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

scjones@sdrc.UUCP (Larry Jones) (05/26/89)

In article <17722@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) writes:
> Any valid `logical' [true/false]
> e1?e2:e3 expression can always be transformed this way into (e1&&e2)||e3,
> provided e3 has no side effects.

Eh?  If e1 and e3 are true while e2 is false, then e1?e2:e3 is
false but (e1&&e2)||e3 is true.  Seems to me you can't avoid
having to do (e1&&e2)||(!e1&&e3).
----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@SDRC.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150-2789             AT&T: (513) 576-2070
"You can't get a body like mine in a bottle --
unless you push REAL HARD." - Judy Tenuta / Dr. Pepper

gwyn@smoke.BRL.MIL (Doug Gwyn) (05/27/89)

In article <17757@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes:
>But e1?e2:e3 *can* be turned into (e1&&e2 || !e1&&e3)

Not always; that may evaluate e1 more than once, which matters if e1
has side effects.

Also, the value of e1?e2:e3 is an appropriately promoted value of e2
or e3, whereas the value of (e1&&e2||!e1&&e3) is either 0 or 1.

Just a warning against taking this discussion too literally..

karzes@mfci.UUCP (Tom Karzes) (05/27/89)

In article <779@attila.WEITEK.COM> kens@attila.WEITEK.COM (Ken Stanley) writes:
}The specific example: "((n % 10) != 0 && k > 2) || n < 100" works because
}when n = 100, (n % 10) == 0 and ! (n < 100).  However, if the loop increment
}were 3 instead of 1, it would not.
}...
}... these two statements are identical:
}
}for (n = 1; ((n % 10) != 0 && k > 2) || n < 100; n++)
}for (n = 1; ((n % 10) ? (k > 2) : (n < 100); n++)

No, these two statements are not identical, even in this context.  Consider
the case where n is 11 and k is 1.  The original ?: expression evaluates
to 0, whereas the incorrect alternate form evaluates to 1.  (By the way,
the second expression shown above has unbalanced parentheses.)

peter@ficc.uu.net (Peter da Silva) (05/27/89)

In ANSI 'C' there's a difference between ()?():() and (()&&())||(~()&&()).
The type of the result differs if one of the resulting expressions is
(void *):

	(()&&(char *))||(~()||(void *))	-- may be char *, will never be void *.
	()?(char *):(void *) -- will be void *

See comp.std.c for exhaustive debate on the subject.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.

Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.
Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.

karl@haddock.ima.isc.com (Karl Heuer) (05/28/89)

In article <4326@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
>	(()&&(char *))||(~()||(void *))	-- may be char *, will never be void *.

No, it will always be of type int (conceptually boolean, but in C that's int).

Note that the original statement of equivalence was explicitly restricted to
boolean expressions.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint