[comp.lang.c] programming puzzle

klier@ucbarpa.Berkeley.EDU (Pete Klier) (03/10/89)

***********************
main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
printf(m?"Answer=%d\n":"error\n",m);}
***********************

with help from Jeff Conroy (jmconroy@ernie.Berkeley.EDU)
 
the expression "m=n>0^n>9" is equivalent to 
"m = (n > 0) && (n <= 9)" (check it out)
so "m" is 1 (initially) iff n is within range, 0 otherwise.
If m is 0 in the body of the loop, then the expression
(n&&m*=n--) is 0, since (m*=n--) is 0.  Otherwise, we
have an ordinary factorial loop, which begins with
m == 1.  
Pete Klier
klier@ernie.Berkeley.EDU

kjell@saturn.ucsc.edu (Kjell Post) (03/10/89)

In article <28336@ucbvax.BERKELEY.EDU> klier@ucbarpa.Berkeley.EDU (Pete Klier) writes:
>
>***********************
>main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
>printf(m?"Answer=%d\n":"error\n",m);}
>***********************
>

But you changed the output.
I also get an error compiling this on an ISI68K.

As someone pointed out, my earlier solution breaks when arguments
are supplied at the command line.  I therefore propose the following
as the shortest version:

main(n,m){for(n=scanf("%d\n",&m);m>1&m<10;n*=m--);
printf(m-1?"error\n":"answer is %d\n",n);}

When written on a single line it should count to 91 characters.
I would also like to add the rule that the program should compile
without warnings from cc and lint (except for "scanf returns value
which is always ignored" which is always ignored).
-- 
      For athletes and programmers,  ! Kjell E. Post
a woman is the end of their career.  ! CIS/CE
                                     ! University of California, Santa Cruz
              -- A.Wickberg          ! Email: kjell@saturn.ucsc.edu

djones@megatest.UUCP (Dave Jones) (03/11/89)

From article <28336@ucbvax.BERKELEY.EDU>, by klier@ucbarpa.Berkeley.EDU (Pete Klier):
> 
> ***********************
> main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
> printf(m?"Answer=%d\n":"error\n",m);}
> ***********************
> 
> with help from Jeff Conroy (jmconroy@ernie.Berkeley.EDU)
>  

Awesome. Truely awesome.

I don't think this entry will be surpassed.

By the way, this looks a little like some of the code in the original
4.2BSD Pascal compiler.

bader+@andrew.cmu.edu (Miles Bader) (03/11/89)

From klier@ucbarpa.Berkeley.EDU (Pete Klier):
> 
> main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
> printf(m?"Answer=%d\n":"error\n",m);}
> 
> with help from Jeff Conroy (jmconroy@ernie.Berkeley.EDU)

The compiler on this machine give the following error; is it wrong?

E "fact.c",L1/C44:	(syntactic)  unexpected symbol:'*='

-Miles

tim@crackle.amd.com (Tim Olson) (03/12/89)

In article <YY6_v5y00UkaI0ZW1_@andrew.cmu.edu> bader+@andrew.cmu.edu (Miles Bader) writes:
| From klier@ucbarpa.Berkeley.EDU (Pete Klier):
| > 
| > main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
| > printf(m?"Answer=%d\n":"error\n",m);}
| > 
| > with help from Jeff Conroy (jmconroy@ernie.Berkeley.EDU)
| 
| The compiler on this machine give the following error; is it wrong?
| 
| E "fact.c",L1/C44:	(syntactic)  unexpected symbol:'*='

Interesting -- the program *is* incorrect, because && has higher
precedence than *= so it is parsed as:

	(n&&m) *= n--

which is illegal because (n&&m) is not an lvalue.  Our MetaWare and
Green Hills compilers catch it, but every pcc-based compiler I tried
compiled it with no warnings.  Looking at the assembly-language
generated, it appears that it compiled as:

	n && (m*=n--)

What do other compilers out there do?


	-- Tim Olson
	Advanced Micro Devices
	(tim@amd.com)

bph@buengc.BU.EDU (Blair P. Houghton) (03/12/89)

In article <24820@amdcad.AMD.COM> tim@amd.com (Tim Olson) writes:
>In article <YY6_v5y00UkaI0ZW1_@andrew.cmu.edu> bader+@andrew.cmu.edu (Miles Bader) writes:
>| From klier@ucbarpa.Berkeley.EDU (Pete Klier):
>| > 
>| > main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
>| > printf(m?"Answer=%d\n":"error\n",m);}
>
>Interesting -- the program *is* incorrect, because && has higher
>precedence than *= so it is parsed as:
>	(n&&m) *= n--
>which is illegal because (n&&m) is not an lvalue.  Our MetaWare and
>Green Hills compilers catch it,
>What do other compilers out there do?

Depends on your attitude.

1.  The cc on the uVAXen (Ultrix) passes it unnoticed.

2.  While cc on the Encore (Umax) says
"junk.c", line 1: Operand must be an lvalue

3.  Lint always says
junk.c(8): warning: precedence confusion possible: parenthesize!

I view the uVAX as utilizing a heuristically-extended version of the
"maximal munch" rule, where the syntax has made it obvious that the
lvalue given isn't an lvalue, so it looks for the next obvious
interpretation.  Groovy.  Whatever turns you on, man.

I view the Encore as applying the tokenize-first, interpret-later
version of the "maximal munch" rule.  I'm a bit of a code-fascist
myself, so I'd go with this one.

Lint?  Well, I had to give it a "-h" in order to get it to talk.
Don't you just hate weasely informants?

				--Blair
				  "Don't you just hate computer narcs?"

steve@umigw.MIAMI.EDU (steve emmerson) (03/13/89)

In article <24820@amdcad.AMD.COM> tim@amd.com (Tim Olson) opines that the
expression "n&&m*=n--" is incorrect C:

>Interesting -- the program *is* incorrect, because && has higher
>precedence than *= so it is parsed as:
>
>   (n&&m) *= n--
>
>which is illegal because (n&&m) is not an lvalue.

I belive the correctness of a expression is determined by whether or not
the expression can be *generated from* the grammer's production rules; not
whether or not a given implementation of a compiler can parse it.

The given expression is correct C as it can be generated by the following
rules:

    expresion -> expression1 binop expression2
        expression1 -> identifier -> n
        binop       -> &&
        expression2 -> lvalue asgnop expression
            lvalue      -> identifier -> m
            asgnop      -> *=
            expression  -> lvalue-- -> identifier-- -> n--

Thus,
    expression -> n && m *= n--

Precedence rules are needed only when there is more than one way to 
generate a given expression and (consequently) more than one way to parse 
it.  They appear to be unnecessary for the above expression.
-- 
Steve Emmerson                     Inet: steve@umigw.miami.edu [128.116.10.1]
SPAN: miami::emmerson (host 3074::)      emmerson%miami.span@star.stanford.edu
UUCP: ...!ncar!umigw!steve               emmerson%miami.span@vlsi.jpl.nasa.gov
"Computers are like God in the Old Testament: lots of rules and no mercy"

gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/14/89)

In article <218@umigw.MIAMI.EDU> steve@umigw.miami.edu (steve emmerson) writes:
>In article <24820@amdcad.AMD.COM> tim@amd.com (Tim Olson) opines that the
>expression "n&&m*=n--" is incorrect C:
>I belive the correctness of a expression is determined by whether or not
>the expression can be *generated from* the grammer's production rules; not
>whether or not a given implementation of a compiler can parse it.

Right.

>The given expression is correct C as it can be generated by the following
>rules:

I didn't much like your particular production.  Using the pANS grammar,
the conclusion that the parse is NOT effectively "(n&&m) *= n--" is a
correct deduction; the key point is that "n&&m" cannot possibly be parsed
as anything that is allowed as the left operand of the assignment
expression (called a "unary expression" in the pANS grammar).  However,
the grammar does not support the production you gave, either.  At least
one set of parentheses would have to be added to obtain a valid
expression.  The phrase-structure grammar does not in general allow
arbitrary expressions as operands, only limited classes of expressions.

peter@ficc.uu.net (Peter da Silva) (03/15/89)

From klier@ucbarpa.Berkeley.EDU (Pete Klier):
> main(m,n){scanf("%d",&n);for(m=n>0^n>9;n&&m*=n--;);
> printf(m?"Answer=%d\n":"error\n",m);}

Give up one character and it works:

main(m,n){scanf("%d",&n);for(m=n>0^n>9;n?m*=n--:0;);
printf(m?"Answer=%d\n":"error\n",m);}
-- 
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.

tps@chem.ucsd.edu (Tom Stockfisch) (03/15/89)

In article <218@umigw.MIAMI.EDU> steve@umigw.miami.edu (steve emmerson) writes:
>[argument that "n&&m*=n--" is not equivalent to   (n&&m) *= n--  and thus
>not illegal, because: ]
>Precedence rules are needed only when there is more than one way to 
>generate a given expression and (consequently) more than one way to parse 
>it.  They appear to be unnecessary for the above expression.

This idea seems to me to admit too many wierd constructs.  For instance, why
couldn't you argue that the following expressions are legal?

	EXPRESSION	EQUIVALENT TO
	
	a + 1[0]	(a + 1)[0]

	a + b = c	a + (b = c)

	*a + 5 = 0	*(a + 5) = 0

-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu