[comp.lang.c] "arithmetic if":: Re: Feature for the next C version

davidra@batcomputer.tn.cornell.edu (David Rabson) (07/29/89)

C does have a generalized "arithmetic if," if you wish, although it is
not functionally equivalent.  Switch...case...case...default
is generally implemented as a table of branching addresses if the cases
are integers fairly close to each other and if there are enough cases
to make it pay.

Both gcc and Sun's cc do this if there are at least four cases with
contiguous integer tests (for instance, -1, 0, 1, and 2).  Neither does
it if the cases are just -1, 0, and 1; I assume someone calculated the
tradeoff and found that the repeated tests were cheaper.

If your variable takes on values other than +/-1 and 0, of course,
you will not want to use switch...case...case to implement the
arithmetic goto.

As for using the results of a single TEST for two branch-if's,
our FORTRAN compiler does not do this; perhaps the trick fails
on a 68000, or maybe the compiler writers were too lazy to save
the extra nanosecond.

I think it's fairly obvious which of these pieces of code looks better.
(This is probably unnecessary, but I rarely get to exercise my 
FORTRAN.  Can anyone explain the error in the code?)


EXHIBITS:

      PROGRAM MAIN
C
C NANOSECOND-WISE (MAYBE ON SOME MACHINES) BUT HOUR-FOOLISH
C

      INTEGER I
      READ(5,200) I
200   FORMAT(I)
      IF (I) 1,2,3

1     WRITE(6,100)
100   FORMAT(20H0IT'S LESS THAN ZERO )
      GOTO 4
2     WRITE(6,101)
101   FORMAT(10H0IT'S ZERO )
      GOTO 4
3     WRITE(6,102)
102   FORMAT(23H0IT'S GREATER THAN ZERO )

4     STOP
      END

C by the way, on my machine this program doesn't even work -- if
C I type in a positive number or zero, it gets it right, but if I
C type any negative number, it says it's zero.



main()
{
	int i;

	scanf("%d",&i);

	if(i<0)
		printf("It's less than zero\n");
	else if(!i)
		printf("It's zero\n");
	else
		printf("It's greater than zero\n");

	/* or alternatively */
	printf("It's%s zero\n", i?(i<0?" less than":" greater than"):"");
}

zdenko@csd4.milw.wisc.edu (Zdenko Tomasic) (07/29/89)

In article <8515@batcomputer.tn.cornell.edu> davidra@tcgould.tn.cornell.edu (David Rabson) writes:
>C does have a generalized "arithmetic if," if you wish, although it is
> .... (switch case , gcc and sun discussion omitted) 
>(This is probably unnecessary, but I rarely get to exercise my 
>FORTRAN.  Can anyone explain the error in the code?)
     yes
>      PROGRAM MAIN
>      INTEGER I
>      READ(5,200) I
>200   FORMAT(I)
              ^ This reserves integer field of only one digit/sign.
		  when you use signed integer, sign is taken, but the
		  magnitude (2nd character and beyond!) is not read!
		  So you program get by fortran conversion -0 which
		  is equivalent to 0. You either have to increase your 
		  integer field length(say I10) and right justify your input
		  (trailing blanks within an integer field are treated as
		  zeros!) or much more conveninetly, use list directed read,
		  i.e. replace the read and format statement above with just
		  READ(5,*) I

>... (the rest of message deleted)
--
___________________________________________________________________
Zdenko Tomasic, UWM, Chem. Dept., P.O. Box 413, Milwaukee, WI 53201
UUCP: uwvax!uwmcsd1!uwmcsd4!zdenko
ARPA: zdenko@csd4.milw.wisc.edu

mcdaniel@uicsrd.csrd.uiuc.edu (Tim McDaniel) (07/30/89)

This article has been crossposted to comp.lang.c (the original
newsgroup) and comp.lang.fortran.  Please send all followups to
comp.lang.fortran.

In article <8515@batcomputer.tn.cornell.edu>
davidra@tcgould.tn.cornell.edu (David Rabson) writes:
>200   FORMAT(I)

In article <3600@csd4.milw.wisc.edu> zdenko@csd4.milw.wisc.edu (Zdenko
Tomasic) writes:
> This reserves integer field of only one digit/sign.

FORTRAN 77, and presumably FORTRAN 66, do not allow the I format
descriptor to appear without a width.  On Alliant computers, an I
without a width is permitted as an extension, and the width is assumed
to be 7 characters for one- and two-byte integers, and 12 for 4-byte
integers.

> when you use signed integer, sign is taken, but the magnitude (2nd
> character and beyond!) is not read!  So you program get by fortran
> conversion -0 which is equivalent to 0.

What if you're on a one's complement machine?  On those, -0 need not
be the same as 0.

VAX BSD 4.3, SUN OS 3.5, and Alliant Concentrix 3.0 all treat a single
"-" in an otherwise blank field as 0.  However, I have found no
statement in my manuals guaranteeing it, and if I were writing a
FORMAT conversion library, I'd consider making it illegal as an
ill-formed number.  (After all, these
        I = -           ! FORTRAN
        i = -;          /* C, C++ */
are not legal -- why not be consistent, if the standard permits it?)

> You either have to increase your integer field length (say I10)
Yes.

> and right justify your input (trailing blanks within an integer
> field are treated as zeros!) 

In FORTRAN 77, you can use the BLANK= attribute on the OPEN statement
to control whether trailing blanks are ignored or treated as zeroes,
by
        BLANK='NULL'
or      BLANK='ZERO'
The default is NULL -- by default trailing blanks are simply ignored.
I don't believe FORTRAN 66 took a stand on the issue, and in its
default, implementors treated trailing blanks as zeroes.

Briefly, trailing blanks *may be* treated as zeroes.

> much more conveninetly, use list directed read, i.e. replace the
> read and format statement above with just READ(5,*) I

Quite true!  It is much better for interactive input.

--
"Let me control a planet's oxygen supply, and I don't care who makes
the laws." - GREAT CTHUHLU'S STARRY WISDOM BAND (via Roger Leroux)
 __
   \         Tim, the Bizarre and Oddly-Dressed Enchanter
    \               mcdaniel@uicsrd.csrd.uiuc.edu
    /\       mcdaniel%uicsrd@{uxc.cso.uiuc.edu,uiuc.csnet}
  _/  \_     {uunet,convex,pur-ee}!uiucuxc!uicsrd!mcdaniel

davidsen@sungod.crd.ge.com (William Davidsen) (08/02/89)

  Thanks to all the people who took the time to write about the lack of
something filling the same function as the FORTRAN arithmetic IF. As
someone pointed out, I'm not looking for arithmetic IF, but a way to do
three separate things based on a value, usually the compare of two
values in a sort or tree search.

  Some interesting ideas:
	ifcase
	  (a < b) code; code;
	  (a == b) more(code);
	  (a > b) still(more);
	endcase;

If I were going to make a really readable program, I could do this (and
did, just to see how it looked and worked).

#define LESS		-1
#define EQUAL		0
#define GREATER		1
float T_tmp;
#define COMPARE(a,b) ((T_tmp=a-b)==0 ? 0 : ((T_tmp>0)<<1)-1)

  For the person who said his FORTRAN didn't uses the flags set on a
single test, that's poor compilation. I ran a program into the SunOS
compiler (v3.5) and her's the program and partial output.

	m = 4
	if (m) 1,2,3
    1	print 5, m
	goto 4
    2	print 10, m
	goto 4
    3	print 15, m
    4	stop

    5	format(2H <, i5)
   10	format(2h =, i5)
   15	format(2H >, i5)
	end
 _______________
|
| Partial generated code, comments are mine
|________________

L11:
	movl	#0x4,a5@(-0x8000)
	movl	a5@(-0x8000),a6@(-0xc)
	tstl	a6@(-0xc)		; one test
	jge	L20			;  first jump
	jra	L16			;  second jump
L20:					; Fall into inline code
	tstl	a6@(-0xc)
	jne	L21
	jra	L17
L21:
	jra	L18
L16:


  Again thanks for all the input, hopefully any new standard will come
up with a reasonable way to write this, to (a) make it easy to read, (b)
make it easy for compilers to generate good code (ie. recognize the
special case). Obviously no one wants to have labels, but perhaps
something like:
	n = (a-b $ -1 : 0 : 1);
- or -
	return (a-ptr->val $ getv(ptr->prev : ptr->val : getv(ptr->next));

where there would be a "quadratic operator." No one could argue that
this isn't in the spirit of the language, and an operator might be more
easily added to the language than a control structure.
	bill davidsen		(davidsen@crdos1.crd.GE.COM)
  {uunet | philabs}!crdgw1!crdos1!davidsen
"Stupidity, like virtue, is its own reward" -me

hascall@atanasoff.cs.iastate.edu (John Hascall) (08/02/89)

In article <1429@crdgw1.crd.ge.com> davidsen@crdos1.UUCP (bill davidsen) writes:
 
>someone pointed out, I'm not looking for arithmetic IF, but a way to do
>three separate things based on a value, usually the compare of two
>values in a sort or tree search.
 
>  Some interesting ideas:
>	ifcase
>	  (a < b) code; code;
>	  (a == b) more(code);
>	  (a > b) still(more);
>	endcase;
 
    This reminds my of an exec language I somtimes program in (no, you
    haven't heard of it), where you use:

    cases begin
	case (expression1) statement1
	case (expression2) statement2
	    :
	    :
    end

    And it evaluates each expression in order and executes the (possibly
    compound) statement of the first one (if any) which is true.
    [and you just use "case (true)" at the end for "default:"].

    Of course, neither of these solve the original problem of how to
    execute a 3-way branch with a single expression evaluation.

    Imagine extending the concept:

       if (expr) s1; [else s2;]

    to:

       negative (expr) s1; [zero s2;] [positive s3;]

 
    I can hear the C-purists screaming in agony :-)

John Hascall

chris@mimsy.UUCP (Chris Torek) (08/03/89)

(Short summary: the arithemtic `if' in the three different languages
FIV, F66, and F77---usually each called `FORTRAN'---is syntactically
ugly; various suggestions suggested and promptly ignored :-) .)

Although I have described it here before, I might as well do it again;
USENET has a short collective memory.  The language Mesa (used at Xerox)
has a construct that is a generalisation of C's `switch', called
SELECT (Mesa keywords are in ALL CAPITALS, a practise I find ugly in
the extreme, but fixable :-) ).  One writes, for instance,

	SELECT TRUE FROM -- `FROM' might be `IN'; my Mesa is rusty
	   a < b => signum _ -1;	-- `_' is a left-arrow
	   a = b => signum _ 0;		-- and used for assignment.
	   a > b => signum _ 1;		-- (_ as arrow is `old ASCII')
	END;	-- actually, I have forgotten the proper syntax
		-- for ending a select, but this will serve.

Each argument to select (including the expression to be selected)
is a regular Mesa expression; the first branch that matches (is equal)
is taken.  A C `switch' is thus simply

	SELECT expr FROM
	   1 => case1[];		-- [] is function call
	   2 => case2[];
	   3 => case3[];
	END;

but by putting `true' in the select argument one can select against
various conditions.  A decent compiler will notice that the select
expression is a constant (particularly for `true' or `false') and
will generate the test(s) as the case expressions go by; it is easy
to retain the condition codes across such tests.  The `signum'
example above should compile into

		cmp	a,b
		jge	not_first_case	| skip if not less than
		mov	#-1,signum
		jmp	end_of_select
	not_first_case:
		jne	not_second_case	| skip if not equal
		mov	#0,signum
		jmp	end_of_select
	not_second_case:
		jle	end_of_select	| impossible, but who knows if
					| the compiler will figure that out.
					| one could write `TRUE' for the
					| last expression and eliminate
					| this.
		mov	#1,signum
	end_of_select:
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

karl@haddock.ima.isc.com (Karl Heuer) (08/03/89)

In article <1429@crdgw1.crd.ge.com> davidsen@crdos1 (bill davidsen) writes:
>...Again thanks for all the input, hopefully any new standard will come
>up with a reasonable way to write this, to (a) make it easy to read, (b)
>make it easy for compilers to generate good code (ie. recognize the
>special case).

I don't expect it'll ever make it into a C standard.  It's useful, but not
sufficiently useful to be worth the "feature pollution".

>Obviously no one wants to have labels, but perhaps something like:
>	n = (a-b $ -1 : 0 : 1);
>where there would be a "quadratic operator."

This brings up something I haven't seen mentioned here yet.  (a < b) is *not*
equivalent to (a-b < 0) if the latter expression might overflow.  (This was
also a major flaw in the original fortran concept.)  What you really want is a
pentadic operator:
	n = (a ?? b -> -1 , 0 , 1);
(Syntax flames to /dev/null; I'm not really proposing this.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(PS: I think the word for 4-adic is "tetradic" or "quadary", not "quadratic".)

news@ism780c.isc.com (News system) (08/04/89)

In article <1287@atanasoff.cs.iastate.edu> hascall@atanasoff.cs.iastate.edu.UUCP (John Hascall) writes:
>>  Some interesting ideas:
>>	ifcase
>>	  (a < b) code; code;
>>	  (a == b) more(code);
>>	  (a > b) still(more);
>>	endcase;

>    Imagine extending the concept:
>
>       if (expr) s1; [else s2;]
>
>    to:
>
>       negative (expr) s1; [zero s2;] [positive s3;]
>
> 
>    I can hear the C-purists screaming in agony :-)
>
>John Hascall

As a language designer, I dislike this idea.  I also dislike the C construct
'if (expr) s1; [ else s2;]' (borrowed from algol) for two reasons.  First it
requires the introduction of begin-end (sometimes spelled, {} ).  This is
required so that s1 and s2 can be more than a single statement.  Second and
more important, it causes the dangling 'else' problem (if s1 is an 'if'
statement, which 'if' does the 'else' go with?).

The proposal exacerbates the dangling 'else' problem.  It gives us dangling
'zero' and 'positive', it introduces additional keywords, and it is less
general than the 'ifcase' construct quoted above.  Also the 'ifcase'
construct eliminates the need for begin-end.

Note that it is not hard (as compiler writing goes) to build a compiler which
when given:

	  if
	   ((expr)<0) <statement-list>
	   ((expr)=0) <statement-list>
	   ((expr)>0) <statement-list>
	  fi

Would produce exact same code as for above proposal; assuming each <expr> is
the same and has no side effects.  And the above construct extends naturally
to cover things like IEEE floating arithmetic e.g.

	  if
	   ((expr) = INFINITY)  <statement-list>
	   ((expr) = -INFINITY) <statement-list>
	   ((expr)<0) <statement-list>
	   ((expr)=0) <statement-list>
	   ((expr)>0) <statement-list>
	   else       <statement-list>
	  fi

The 'else' case would be executed when the evaluation of <expr> producdes
a NAN.

I guess I am a C purist.  I feel that adding warts to a toad will not make
it more beautiful.  Why not just leave C as it is?  At least it is now a
reasonably well defined and well documented language.  And it is quite
useful.

Now lets hear the flames from the C-ophiles :-)

    Marv Rubinstein

john@basser.oz (John Mackin) (08/05/89)

In article <14181@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:

> In article <1429@crdgw1.crd.ge.com> davidsen@crdos1 (bill davidsen) writes:
> >Obviously no one wants to have labels, but perhaps something like:
> >	n = (a-b $ -1 : 0 : 1);
> >where there would be a "quadratic operator."

> (PS: I think the word for 4-adic is "tetradic" or "quadary", not "quadratic".)

Don't think, find out!  I won't bother quoting dictionary definitions
as I am sure any of you who are interested in this can look them up
for yourselves; but briefly:  (1) `quadratic' is clearly incorrect;
this is not one of its senses.  (2) `tetradic' means `like a tetrad'
and a tetrad is a set of four things regarded as a unity (I'm skipping
lots of detail here), so that won't serve either.  (3) `quadary' is,
to my eyes and ears, a horrendously ugly word; futhermore I can't
find it in any dictionary I have easy access to.  Unfortunately,
though, I think it's the best we've got; in technical areas one is
sometimes forced to partake of neologisms, and I can't seem to come
up with a more pleasing one than that.  Suggestions are most welcome --
best by mail, as I think the question of what an operator of four
operands should be called is perhaps of limited interest.

John Mackin, Basser Department of Computer Science,
             University of Sydney, Sydney, Australia

john@basser.oz.AU (john%basser.oz.AU@UUNET.UU.NET)
{uunet,mcvax,ukc,nttlab}!munnari!basser.oz!john

kdb@chinet.chi.il.us (Karl Botts) (08/10/89)

>>someone pointed out, I'm not looking for arithmetic IF, but a way to do
>>three separate things based on a value, usually the compare of two
>>values in a sort or tree search.
> 
>>  Some interesting ideas:
>>	ifcase
>>	  (a < b) code; code;
>>	  (a == b) more(code);
>>	  (a > b) still(more);
>>	endcase;

What you want is to extend the grammar from:

case-label
	constant-expression ':'

to

case-lobel
	expression ':'

Many languages allow the equivalent of this.  I don't think you'll see it
soon in C, though -- there are a couple of conflicts.  First, C puts
restrictions on the grammar in a number of places to permit better
optimization.   Good C compilers go to a lot of work to figure out how to
optimize case statements, often looking for consecutive or nearly
consective strings of case values so jump tables can be constructed,
figuring out how to test the variant for ranges to avaoid testing every
value individually, and so forth.  Arbitrary expressions would render most
of this optimimiztion impossible.

More importantly, C expressions can and do have wild and crazy side
effects, but if the compiler is going to do any optimization at all, then
the order in which the expressions (constant or otherwise) in the case labels
is evaluated, or even whether or not any particular one is evaluated at
all, must be undefined.  Furthermore, it _is_ undefined in the current
language definition.  To make the side effects of arbitrary expressions in
case-labels controllable, the order of their evaluation would have to be
defined.  This would be major, incompatible, change in the language.

dwh@twg-ap.UUCP (Dave Hamaker) (08/12/89)

In reference to a discussion which began from an expressed wish for
something like the Fortran "Arithmetic IF" statement (for its clarity
when you want to do different things with the <, ==, > cases of a test),
in article <18868@mimsy.UUCP>, chris@mimsy.UUCP (Chris Torek) describes
Mesa's "SELECT" as a real world example of a language construct that is
a generalization of C's "switch."

One of my pet ideas concerns the generalization of things like "switch."
There's one wrinkle to the idea which may be hard to do with current
compiler technology.  I just don't know enough about compilers to tell.
But, there's a good chance some of you on the net do know, and would be
willing to enlighten us.

Applying the idea to switch gives:

	switch (lhs) {
		case (rhs1): statements
		case (rhs2): statements
		 ...
		case (rhsN): statements
		default: statements
	}

where:

	the "(lhs)" can be omitted;
	if present, "lhs" is an expression, or a *part* of one;
	("lhs" stands for "left-hand side");

	the "rhs's" are also expressions, or *parts* of same;
	the parentheses around a "rhs" may be omitted if it does
		not contain a colon (":");
	("rhs" stands for "right-hand side");

	neither the "lhs", nor any "rhs", may contain part of a:
		character constant,
		string constant,
		parenthesized sub-expression, or
		any other token
		(this could be relaxed, but it probably would
		 not be wise to do so).

If "lhs" is a complete (non-null) expression, for each "rhs" which is a
complete expression, the text of "lhs" and "rhs" are concatenated around
the text of an "==" operator and the result is evaluated as an expression.
Otherwise, the text of "lhs" and "rhs" are just concatenated and evaluated
as an expression.  Control is transferred to the first case with a non-zero
(true) expression value, otherwise to the "default" label, if present, or
the statement following the switch construct, if not (but see my "aside").

If "lhs" is a complete expression and all "rhs's" are constants, "lhs"
must be evaluated exactly once; otherwise, "lhs" (or parts of it) may be
evaluated more than once, and the constructed case expressions may be
evaluated in any order (even in parallel) and need not all be evaluated, at
the complete discretion of the compiler.  This means that case expressions
with side effects cause undefined results.  Note also that duplicate case
expressions are legal, but that unreachable cases which are detectable at
compile time certainly deserve warning diagnostics.

With this, we could write things like:

	switch (x) {
	case > 0:
		signum = 1;
		break;
	case 0:
		signum = 0;
		break;
	case < 0:
		signum = -1;
		break;
	}

and:

	switch (p < ) {
	case .1:
		...
	case .5:
		...
	default:
		...
	}

Now, it seems pretty straightforward to me to compile the construct as
follows:  First, reserve space for a jump instruction.  Second, follow
this with code generated for the "statements" as the case construct is
scanned.  As this is done, remember the "lhs" and the "rhs's," and
remember where in the generated code each "rhs" points to.  Classify
the "lhs" and each "rhs" as to whether or not it is a valid expression
(by trying to parse them).  Further classify each valid "rhs" expression
as to whether or not it is a constant expression.  Third, when the end
of the switch is reached, reserve space for another jump instruction.
Fourth, follow this with code generated to evaluate the expressions
constructed from the "lhs" and "rhs's" and to jump to the proper point
in the generated code associated with each case label.  Finally, fill in
the first reserved jump slot to go to the evaluation code, and fill in
the second reserved jump slot to transfer to the end of the switch.

The wrinkle I'm worried about is: is this notion of saving some program
text aside, concatenating expressions out of them and then "reparsing"
the internally constructed expressions something you can build with
current compiler-construction tools?  Comments from those in the know?

Aside: If I had my druthers, I'd have switches without a default case
give undefined results when no case matches.  It would be a promise to
the compiler that one of the cases will match, allowing generation of
"leaner" code in that event (perhaps with a warning, which would also
help catch when you mistype "default").  I like sharp tools, but it
would not be appropriate to change this sort of thing in an existing
construct (perhaps a syntax for specifying no default could be added).

-Dave Hamaker
dwh@twg.com
...!sun!amdahl!twg-ap!dwh

stevenw@oakhill.UUCP (Steven Weintraub) (08/14/89)

There have been a lot of articles about generalizing the case statement
to take expressions instead of constants on the case labels.  It should be
pointed out this feature is already there.  A case statement like this is
nothing more than an if-else if-else and any compiler will have to handle
such a case statement as such.  For example take the the following case
(no pun intended).

>  Some interesting ideas:
>	ifcase
>	  (a < b) code; code;
>	  (a == b) more(code);
>	  (a > b) still(more);
>	endcase;

is nothing more than :

      if (a < b)
	{ code ; code; }
      else if (a == b)
	{ more(code); }
      else if (a > b)
	{ still(more) }

In article <359@twg-ap.UUCP>, dwh@twg-ap.UUCP (Dave Hamaker) writes:
> Applying the idea to switch gives:
> 
> 	switch (lhs) {
> 		case (rhs1): statements
> 		case (rhs2): statements
> 		 ...
> 		case (rhsN): statements
> 		default: statements
> 	}
> 
> where:
> 
> 	the "(lhs)" can be omitted;
> 	if present, "lhs" is an expression, or a *part* of one;
> 	("lhs" stands for "left-hand side");
> 
> 	the "rhs's" are also expressions, or *parts* of same;
> 	the parentheses around a "rhs" may be omitted if it does
> 		not contain a colon (":");
> 	("rhs" stands for "right-hand side");
> 
> 	neither the "lhs", nor any "rhs", may contain part of a:
> 		character constant,
> 		string constant,
> 		parenthesized sub-expression, or
> 		any other token
> 		(this could be relaxed, but it probably would
> 		 not be wise to do so).
> 

You say that the 'lhs' can be an incomplete expression or an complete
expression.

If the 'lhs' is an incomplete expression there are several problems. 
First it is extemely hard to write the syntax for a partial expression. 
Add to that all you are doing with the partial expression is holding a
pointer to a partial expression tree, which just has to completed at each
label anyway.  You might as well use an if-else if structure to do this
because you are not saving any code at cost of complicating the languge.
(I can see some tricks that could be used to generate this tree, but it
would greatly complicate the parser).

If the 'lhs' is a complete expression, then this statement is nothing
more than an extra if-else if structure.  If your worry is evaluation the
statement more than once, then you can always store the expression in a
temporary variable before (or in the first expression) of the if statement.

> 	switch (x) {
> 	case > 0:
> 		signum = 1;
> 		break;
> 	case 0:
> 		signum = 0;
> 		break;
> 	case < 0:
> 		signum = -1;
> 		break;
> 	}

becomes (assuming x to be a complicated expression) :

	temp = (x);
	if (temp > 0)             or if ((temp = (x)) > 0)
		signum = 1;
	else if (temp == 0) 
		signum = 0;
	else if (temp < 0) 
		signum = -1;

> and:
 
> 	switch (p < ) {
> 	case .1:
> 		...
> 	case .5:
> 		...
> 	default:
> 		...
> 	}

generates the same code as: 

       if (p == .1)
	       ...
       else if (p == .5)
	       ...
       else
	       ...

(again p can be place in a temporary if only one evaluation is desired)

The reason for a case statement is that with simple constants as the goals
an if-else if structure can go under a great deal of optimization.  Thus
the case statement is used to tell the compiler this can happen.  To widen
the case statement to take expressions or part of expression, you are adding
nothing more than the if-else if structure you already have at the cost of
losing the case structure, whose purpose is to tell the compiler it can
optimize (Otherwise you'd just have an if-else if).

                   enough from this mooncalf - Steven
----------------------------------------------------------------------------
These opinions aren't necessarily Motorola's or Remora's - but I'd like to
think we share some common views.
----------------------------------------------------------------------------
Steven R Weintraub                             | O Lord,
...!cs.utexas.edu!oakhill!stevenw              |   let me talk gently,
Motorola Inc.  Austin, Texas                   | for I might have to eat my
(512) 891-3023 (office) (512) 453-6953 (home)  |   words tomorrow.
----------------------------------------------------------------------------