[net.bugs.4bsd] i = i * f vs. i *= f

ado@elsie.UUCP (04/12/84)

I compiled the following program with the 4.1bsd C compiler:
	main()
	{
		int	i;

		i = 100;
		i = i * .2;
		printf("%d\n", i);
		i = 100;
		i *= .2;
		printf("%d\n", i);
	}

I got this output:
	20
	0

Is this a bug?
-- 
UUCP:	decvax!harpo!seismo!rlgvax!cvl!elsie!ado
DDD:	(301) 496-5688

peters@cubsvax.UUCP (04/15/84)

Looks like you found a real bug!  on the 4.1bsd compiler, the following
program -- which compares i = i / f with i /= f -- gives the results indicated.

Obviously, the problem is that when the compiler encounters
"int op= float;" it casts the float to an int before doing the evaluation,
instead of promoting the int to a float, then casting the result.

According to K&R, p191, the two expressions "may be taken as equivalent"
(slight paraphrase), which is *very* misleading if this isn't a bug.  They
then say, "... however, [for "op=" ] E1 [left-hand side] is evaluated only
once."  This is opaque to me.  Can someone explain it?  I. e., does that
mean it's not a bug?  It's egregious [look it up!] in any case.

	main()
	{
		int	i;

		i = 100;
		i = i / 3.3;
		printf("i = i/3.3 gives: %d\n", i); /* gives 30, as expected */
		i = 100;
		i /= 3.3;
		printf("i /= 3.3 gives: %d\n", i);  /* gives 33!!!!   */
	}

{philabs,cmcl2!rocky2}!cubsvax!peters            Peter S. Shenkin 
Dept of Biol. Sci.;  Columbia Univ.;  New York, N. Y.  10027;  212-280-5517
"In accordance with the recent proclivity for clever mottos, this is mine."

smq@hlhop.UUCP (Steven M. Queriolo) (04/16/84)

I tried both i=100; i *= .2; and i=100; i /= 3.3; on
our Unix System V (Release 2.0) and both of these 'bugs'
produced the correct answers.

-- 
			Steven M. Queriolo
			AT&T Bell Laboratories
			..........hlhop!smq

hansen@pegasus.UUCP (04/16/84)

I waited a couple of days before following up on this question to see if
anyone else posted a reply. None has so far that I've seen, so here goes.

The reported problem:

    integer *= float	is not the same as	integer = integer * float

This is indeed a definite bug which has been around for many a moon. (It has
been fixed in the System V compiler.) Dennis Ritchie himself commented on
this very same problem in this very same forum last fall, acknowledging that
it was a bug. Fix those compilers!

					Tony Hansen
					pegasus!hansen

crp@ccivax.UUCP (Chuck Privitera) (04/18/84)

The bug was reported (and fixed) back in January by randvax!edhall.
I have installed the fix here and have not had any problems since.
The fix follows:


>From ritcv!rochester!seismo!hao!hplabs!sdcrdcf!randvax!edhall Wed Jan 11 03:13:26 1984
Subject: integer op= floating evaluated incorrectly by C compiler
Newsgroups: net.bugs.4bsd,net.bugs.usg

------------------------------------
This bug may affect all pre-5.0USG C compilers, and perhaps earlier
5.0USG compilers as well.  The below fix only works for PCC-derived
compilers (such as the BSD VAX C compiler).

Index:  usr.lib/ccom 4.2BSD 4.1BSD 3.0USG

Description:
	When assignement operators such as *= are used with an integer
	Left-Hand Side and a floating-point expression on the Right-
	Hand Side, results are incorrect.  For example:

		int i = 6;
		i *= .5;

	leaves a value of 0 in i, rather than 3.  The +=, -=, and /=
	operators are similarly affected.

Caused by:
	Conversion of RHS of assignment to type of LHS before application
	of the operator.

Fixed by:
	The fix is in two parts.  First, the automatic forcing of type
	conversion to the LHS of an assignment op must be shut off in
	appropriate circumstances.  This requires a change to tymatch()
	in mip/trees.c:

1031c1031,1035
< 	if( t != t2 || o==CAST ) p->in.right = makety( p->in.right, tu, 0, (int)tu );
---
> 	if( o==CAST || (t != t2
> 	  && ( (dope[o]&(FLOFLG|ASGOPFLG)) != (FLOFLG|ASGOPFLG)
> 	  || t != INT || (t2 != DOUBLE && t2 != FLOAT) )) ) {
> 		p->in.right = makety( p->in.right, tu, 0, (int)tu );
> 		}

	This causes certain assignment ops (+=, -=, *=, /=, i.e. the ones
	appropriate in floating-point) to remain in the parse tree without
	`balanced' operand types.  When these get to code-generation the
	compiler would break unless the template table had the proper pieces
	added to it.  Thus, in pcc/table.c:

712a713,729
>
> /* begin new stuff */
>
> ASG OPFLOAT,    INAREG|FOREFF|FORCC,
>       SAREG|AWD,      TWORD|TCHAR|TSHORT,
>       SAREG|AWD,      TDOUBLE,
>               NAREG,  RLEFT|RESCC,
>               "       cvtZLd  AL,A1\n OD2     AR,A1\n cvtdZL  A1,AL\n",
>
> ASG OPFLOAT,    INAREG|FOREFF|FORCC,
>       SAREG|AWD,      TWORD|TCHAR|TSHORT,
>       SAREG|AWD,      TFLOAT,
>               NAREG,  RLEFT|RESCC,
>               "       cvtZLf  AL,A1\n OF2     AR,A1\n cvtfZL  A1,AL\n",
>
> /* end new stuff */
>

	-Ed Hall
	Rand Corporation
	Santa Monica, CA
	decvax!randvax!edhall   (UUCP)
	edhall@rand-unix        (ARPA)

There are plenty of parenthesis to miss there. Be careful!

				Chuck

allan@qtlon.UUCP (04/24/84)

<no, no, no. Please don't eat me>
This is the same on 4.2bsd also. I Thought I would try it on our C compiler
on our Prime and the results were
19
19
So it is sort of better, with floats the result was 19.999996 so it was
almost 20.
-- 
UUCP:               {decvax,cbosgd,vax135}!qusavx!qtlon!allan
                    ukc!qtlon!allan
Phone:              +44 1 637 7061

chris@basser.SUN (Chris Maltby) (04/26/84)

>This is the same on 4.2bsd also.  I Thought I would try it on our C
>compiler on our Prime and the results were 
>19
>19
>So it is sort of better, with floats the result was 19.999996 so it was
>almost 20.

Everyone knows that floating point units on PR1ME machines are up the sh*t.
If anyone would like proof of this, I can send you a nice program to run.

Chris Maltby
University of Sydney