is the < operator transitive?

W

Willem

io_x wrote:
) possible exst one define macro processor power enought for allow this:
) #MyDefine ?1<?2<?3 ?1<?2 && ?2<?3
)
) if(a<b<c && c>1) ....
) expanded to
) if(a<b && b<c && c>1) ....
) but that would break C language...
) Ciao

The C way to handle this would be to have a (varargs) function
increasing(...), which you would then call as increasing(a,b,c),
which returns true if a<b<c in the mathematical sense, and which
(listen very carefully) evaluates b only once.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
J

James Kuyper

On 10/09/2011 04:09 AM, Ben Bacarisse wrote:
....
The "problem" (I am not sure i remember what it is) may be worse in the
I used < following your example, but the general idea would be to do
this for all relations operators, so

a == b == c

would be permitted to mean a == b && b == c (with b evaluated only
once). It would be a bog step to outlaw equality testing for bool.

Again, unless I'm missing the main point, I don't see the problem. If
this hypothetical language clearly states all the relational operators
and non-associative, chains of them must mean something other the usual
default pair-wise bracketing that associativity implies.

Associativity isn't the relevant characteristic. Associativity is about
how an expression's meaning can be rearranged, while still having the
same value; my issue with this proposal doesn't have anything to do with
an expression's possible rearrangements. In the hypothetical language I
was discussing, chains of relational or equality operators would
necessarily be constraint violations - unless all values being compared
after the first two were of boolean type - and that's the problem.
There's no way to handle that case which is consistent with the proposed
chain rule for relational and equality operators without violating a key
feature that the hypothetical language was intended to share with C.

The relevant feature of C is that every complex expression can be broken
down recursively into a top-level operator operating on the value of
it's sub-expressions. The value and meaning of the sub-expressions
depends only upon the sub-expression itself, not on the context in which
it occurs. What the top-level operation does depends only upon the
values of it's operands, and not upon how they were calculated. I can
think of a few special exceptions (for instance, the fact that &*p can
have a well-defined meaning in contexts where *p does not), but in
general this is a fundamental feature of the structure of C. The
proposed new interpretation of

x = a == b == c;

would make it quite different from

auto temp = a == b;
x = temp == c;

I've borrowed here a new feature of C++, where the 'auto' keyword causes
'temp' to be declared with precisely the type of it's initializer. That
type would be 'int' in C; and 'bool' in the hypothetical language I've
been referring to, but the issue is the same in both cases.
 
I

Ike Naar

io_x wrote:
) possible exst one define macro processor power enought for allow this:
) #MyDefine ?1<?2<?3 ?1<?2 && ?2<?3
)
) if(a<b<c && c>1) ....
) expanded to
) if(a<b && b<c && c>1) ....
) but that would break C language...
) Ciao

The C way to handle this would be to have a (varargs) function
increasing(...), which you would then call as increasing(a,b,c),
which returns true if a<b<c in the mathematical sense, and which
(listen very carefully) evaluates b only once.

Wouldn't this lead to a combinatorial explosion of functions?

a < b < c -> increasing(a,b,c)
a <= b <= c -> younameit0(a,b,c)
a <= b < c -> younameit1(a,b,c)
a < b == c -> younameit2(a,b,c)
...
a < b > c -> younameitn(a,b,c)
 
W

Willem

Ike Naar wrote:
)> The C way to handle this would be to have a (varargs) function
)> increasing(...), which you would then call as increasing(a,b,c),
)> which returns true if a<b<c in the mathematical sense, and which
)> (listen very carefully) evaluates b only once.
)
) Wouldn't this lead to a combinatorial explosion of functions?

You perhaps missed the 'varargs' bit:
increasing(a,b,c,d,e,f) -> a<b<c<d<e<f

) a < b < c -> increasing(a,b,c)
) a <= b <= c -> younameit0(a,b,c)
Yup, one for each inequality operator, that's 4.

) a <= b < c -> younameit1(a,b,c)
I can see the need for this, to check if a value is inside a certain range,
where both ends can be closed or open.

That's a different approach from what I proposed above.
Still, you get 4 combinations in total.

) a < b == c -> younameit2(a,b,c)
I fail to see the need for this.

) ...
) a < b > c -> younameitn(a,b,c)
That's a different set, where you check if one element is smaller than a
number of others. Again, 4 functions if you want all of them.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
I

Ike Naar

Ike Naar wrote:
)> The C way to handle this would be to have a (varargs) function
)> increasing(...), which you would then call as increasing(a,b,c),
)> which returns true if a<b<c in the mathematical sense, and which
)> (listen very carefully) evaluates b only once.
)
) Wouldn't this lead to a combinatorial explosion of functions?

You perhaps missed the 'varargs' bit:

No, I did not miss that, I was trying to keep the examples simple.
increasing(a,b,c,d,e,f) -> a<b<c<d<e<f

) a < b < c -> increasing(a,b,c)
) a <= b <= c -> younameit0(a,b,c)
Yup, one for each inequality operator, that's 4.

But if the number of variables increases (when using varargs),
so does the number of combinations.
) a <= b < c -> younameit1(a,b,c)
I can see the need for this, to check if a value is inside a certain range,
where both ends can be closed or open.

It's not so far-fetched. Here is a common idiom in C:

/* precondition for evaluating a where a has N_A elements */
0 <= i < N_A
That's a different approach from what I proposed above.
Still, you get 4 combinations in total.

That's 2^n if there are n operators in the general (varargs) case.
) a < b == c -> younameit2(a,b,c)
I fail to see the need for this.

Use your imagination.
) ...
) a < b > c -> younameitn(a,b,c)
That's a different set, where you check if one element is smaller than a
number of others. Again, 4 functions if you want all of them.

Again, 2^n in the varargs case.
 
W

Willem

Ike Naar wrote:
)> That's a different approach from what I proposed above.
)> Still, you get 4 combinations in total.
)
) That's 2^n if there are n operators in the general (varargs) case.

No, because in the varargs case you have to have all operators the same.
There cannot be 2^n cases, because you don't know beforehand what n is.


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
B

BartC

Willem said:
Ike Naar wrote:
) a < b == c -> younameit2(a,b,c)
I fail to see the need for this.

You might use it wherever you might write:

a<b && b==c

And C allows that without questioning whether or not it might be useful!

If you're going to allow an arbitrary chain of relational operators, you
can't just pick and choose whatever combinations might appear useful.

And a general solution using macros probably isn't how to implement it.
 
W

Willem

BartC wrote:
)
) )> Ike Naar wrote:
)
)> ) a < b == c -> younameit2(a,b,c)
)> I fail to see the need for this.
)
) You might use it wherever you might write:
)
) a<b && b==c
)
) And C allows that without questioning whether or not it might be useful!
)
) If you're going to allow an arbitrary chain of relational operators, you
) can't just pick and choose whatever combinations might appear useful.
)
) And a general solution using macros probably isn't how to implement it.

But I'm NOT picking an arbitrary chain of relational operators.
I'm picking a chain of the _same_ operator, of arbitrary length.

Although there is no real need for that either, in retrospect.
"a < b < c" is very common (in maths) but "a < b < c < d" is not.

What *would* be useful would be a 'between' function.
In 4 flavours, of course (either end can be open and closed).
With open and closed I mean:

a < b < c
a <= b < c
a < b <= c
a <= b <= c

Or, written differently:
b in (a .. c)
b in [a .. c)
b in (a .. c]
b in [a .. c]


SaSW, Willem
--
Disclaimer: I am in no way responsible for any of the statements
made in the above text. For all I know I might be
drugged or something..
No I'm not paranoid. You all think I'm paranoid, don't you !
#EOT
 
F

Francois Grieu

enum { MINUSONE = -1 };

Now MINUSONE *is* an `int' constant with negative value, hence

(MINUSONE < 0 && 0 < 1u && !(MINUSONE < 1u))

Exactly the counterexample that I was looking after.

Francois Grieu
 
E

Eric Sosman

Exactly the counterexample that I was looking after.

It's a bit of a nit-pick because it relies on sometimes converting
and sometimes not converting an operand. To the best of my knowledge,
your original expression `( a<b && b<c && !(a<c) )' is guaranteed to be
zero if (not "iff")

1: a,b,c are expressions of the same type, and
2: there are no side-effects (including `volatile' references)
in evaluating a,b,c, and
3: evaluating a,b,c produces no undefined behavior, and
4: the three comparisons are themselves defined (a,b,c aren't
structs, aren't pointers into unrelated arrays, etc.)

NaN seems a red herring: If any of a,b,c is NaN, then at least one
of a<b and b<c evaluates to zero and the entire expression therefore
evaluates to zero.

In a follow-up you asked about the case where one or more of
a,b,c is an uninitialized variable. If so, it has an indeterminate
value and the (3) test fails; the behavior is undefined, and nothing
can be said about the larger expression's value.
 
F

Francois Grieu

Le 09/10/2011 22:34, Eric Sosman a écrit :
(..) To the best of my knowledge,
your original expression `( a<b && b<c && !(a<c) )' is guaranteed
to be zero if (not "iff")

1: a,b,c are expressions of the same type, and
2: there are no side-effects (including `volatile' references)
in evaluating a,b,c, and
3: evaluating a,b,c produces no undefined behavior, and
4: the three comparisons are themselves defined (a,b,c aren't
structs, aren't pointers into unrelated arrays, etc.)


I agree with that. I wonder how much we can usefully expand 1,
perhaps to
1': (among a,b,c, there are not one which is an unsigned integer
expression and another which is a signed integer expression), and

Francois Grieu
 
D

David Thompson

Cobol 68 did something like that. You could write:

IF A IS GREATER THAN B OR C

(or equivalently)

IF A > B OR C

You could also do things like:

IF A IS EQUAL TO B AND NOT C

(and yes, the second term(?) is "A IS NOT EQUAL TO C")

My history on this is a bit fuzzy, but I think that form was removed
in Cobol 7x. Or maybe that was pre-68 and it was removed in '68.
Still in -74 and -85. And still in the last draft I looked at for -03;
I didn't follow to completion, but I would be astonished if they
dropped a longstanding feature that is trivial to implement.

Of course this repeats the _left_ comparand (and possibly the
operator), not the right which as elsethread Icon does.

FWIW in (Common)Lisp all operators are syntactically function calls,
allowing variable number of arguments e.g. (< 3 4) and (< 3 4 5 6 7).
These do have the 'obvious' semantics, except maybe /= notequal which
per standard checks all pairs not just adjacent pairs (as the C syntax
presumably would); I don't recall ever wanting /= with more than 2
operands for any real purpose, and thus exercising that case.
 
T

Tim Rentsch

Eric Sosman said:
It's a bit of a nit-pick because it relies on sometimes converting
and sometimes not converting an operand. To the best of my knowledge,
your original expression `( a<b && b<c && !(a<c) )' is guaranteed to be
zero if (not "iff")

1: a,b,c are expressions of the same type, and
2: there are no side-effects (including `volatile' references)
in evaluating a,b,c, and
3: evaluating a,b,c produces no undefined behavior, and
4: the three comparisons are themselves defined (a,b,c aren't
structs, aren't pointers into unrelated arrays, etc.)

Can be 1 if a, b, and c are expressions with floating-point
operations in them.
 

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

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top