What shall return "0.0 ? 1 : 0" ?

X

Xavier Roche

Hi folks!

Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result is.. 1.

Is the result undefined by the standard, by chance ?


Regards,
Xavier Roche
 
B

Ben Bacarisse

Xavier Roche said:
Hi folks!

Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result
is.. 1.

How odd.
Is the result undefined by the standard, by chance ?

No, it's defined to be 0.

It does not violate any constraint that I can see, and the meaning
depends solely on whether 0.0 "compares equal to 0". I can't find any
justification for 0.0 not comparing equal to 0.

The phases "x compares equal to 0" and "x compares unequal to 0" are
used a lot in the standard. I've always taken them to mean x == 0 and x
!= 0, but I don't think that's ever stated explicitly.
 
N

Noob

Xavier said:
Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result is.. 1.

Is the result undefined by the standard, by chance ?

Lemme see...

3.3.15 Conditional operator

Syntax

conditional-expression:
logical-OR-expression
logical-OR-expression ? expression : conditional-expression

Constraints

The first operand shall have scalar type.
[...]

Semantics

The first operand is evaluated; there is a sequence point after
its evaluation. The second operand is evaluated only if the first
compares unequal to 0; the third operand is evaluated only if the
first compares equal to 0; the value of the second or third operand
(whichever is evaluated) is the result[41].

[41] A conditional expression does not yield an lvalue.

0.0 is a 'floating-constant' which is a kind of 'primary-expression'
which is a kind of 'logical-OR-expression'.

(Scalar type means integral or floating or pointer.)

Since 0.0 (the floating constant) compares equal to 0 (the integral constant)
(0.0 ? 1 : 0) has value 0, as far as I can tell.

Regards.
 
X

Xavier Roche

Since 0.0 (the floating constant) compares equal to 0 (the integral constant)
(0.0 ? 1 : 0) has value 0, as far as I can tell.

Thanks a lot to both of you. It appears to be a bug in Visual C++ 2010
(*) then.

This impression is confirmed when trying:
static double zero = 0.0;
...
zero ? 0 : 1
which returns the correct value (0).

(*) tested version: cl.exe 16.00.30319.01 for x64 (same issue using the
x86 release)
 
N

Noob

Xavier said:
Thanks a lot to both of you. It appears to be a bug in Visual C++ 2010
(*) then.

This impression is confirmed when trying:
static double zero = 0.0;
..
zero ? 0 : 1
which returns the correct value (0).

NB: You swapped 0 and 1 there.

( 0.0 ? 42 : 666) evaluates to 666
(zero ? 42 : 666) evaluates to 666
 
X

Xavier Roche

NB: You swapped 0 and 1 there.

Yes, my mistake (but the tested code is the initial one and has the
wrong value)

I have reported the issue on the "Visual C++ Language" forums (I can't
understand why they ditched the microsoft.* groups for this piece of
webforum junk by the way)
 
S

Stefan Ram

Xavier Roche said:
Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

An expression does not return. A function may return. After

int f(){ return 0.0 ? 1 : 0; {

, we can say that f »shall return 0.0 ? 1 : 0«.
 
J

jacob navia

Le 20/07/12 15:21, Xavier Roche a écrit :
Hi folks!

Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result
is.. 1.

Is the result undefined by the standard, by chance ?


Regards,
Xavier Roche

The bug is at the level of the compile-time interpretation since the
result is not calculated at run time (even without aptimizations!)

cl -FA bug.c yields this code:

; Listing generated by Microsoft (R) Optimizing Compiler Version
16.00.30319.01

include listing.inc

INCLUDELIB LIBCMT
INCLUDELIB OLDNAMES

_DATA SEGMENT
$SG2584 DB '???', 00H
ORG $+4
$SG2585 DB '0.0 ? ??? : OK = %s', 0aH, 00H
_DATA ENDS
PUBLIC main
EXTRN printf:pROC
pdata SEGMENT
$pdata$main DD imagerel $LN3
DD imagerel $LN3+30
DD imagerel $unwind$main
pdata ENDS
xdata SEGMENT
$unwind$main DD 010401H
DD 04204H
; Function compile flags: /Odtp
xdata ENDS
_TEXT SEGMENT
main PROC
; File d:\lcc\bug.c
; Line 3
$LN3:
sub rsp, 40 ; 00000028H
; Line 4
lea rdx, OFFSET FLAT:$SG2584
lea rcx, OFFSET FLAT:$SG2585
call printf
; Line 5
xor eax, eax
add rsp, 40 ; 00000028H
ret 0
main ENDP
_TEXT ENDS
END
 
K

Keith Thompson

An expression does not return. A function may return. After

int f(){ return 0.0 ? 1 : 0; {

, we can say that f »shall return 0.0 ? 1 : 0«.

An expression *yields* a value. (I think earlier versions of the
standard used the word "return" for the results of expressions in
some places; as far as I know it's been cleaned up.)

I agree that it's not strictly correct to say that an expression
returns a value, but the intended meaning is clear enough.
 
S

Stefan Ram

Keith Thompson said:
An expression *yields* a value. (I think earlier versions of the
standard used the word "return" for the results of expressions in
some places; as far as I know it's been cleaned up.)

I'd say that an expression /had/ a value (and that an /evaluation/
yielded a value). Let me try to find quotations in N1570:

»Its lifetime begins when the expression is evaluated
and its initial value is the value of the expression.«
¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯¯
»An actual implementation need not evaluate part of an
expression if it can deduce that its value is not used
and that no needed side effects are produced«

»the value of CHAR_MIN«

»expressions with implementation-defined values«

»Its lifetime begins when the expression is evaluated
and its initial value is the value of the expression.«

»If an expression of any other type is evaluated as a
void expression, its value or designator is discarded.«

The relationship between an expression and its value in all
these quotes (selected without bias) is always /possessive/,
hence /has/.

However, I'd like to add that for run-time values, it would
be more correct never to say that /an expression had/ a value,
since the value is in a one-to-one correspondence only with
a single /evaluation/, because each evaluation of an
expression may yield a different value. But it might be too
cumbersome to always write »the value of an evaluation of x«
instead of »the value of x«.
 
K

Keith Thompson

Xavier Roche said:
Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result is.. 1.

Is the result undefined by the standard, by chance ?

As other responses have said, the result is well defined, and this
appears to be a bug in Visual C++ 2010.

I just tried this program:

#include <stdio.h>
int main(void) {
printf("%d\n", 0.0 ? 1 : 0);
if (0.0) {
puts("0.0 is true");
}
else {
puts("0.0 is false");
}
if (0.0 == 0) {
puts("0.0 compares equal to 0");
}
else {
puts("0.0 does not compare equal to 0");
}
return 0;
}

With gcc, the output is:

0
0.0 is false
0.0 compares equal to 0

With Visual Studio, the output is:

1
0.0 is false
0.0 compares equal to 0

with the language set to C and extensions disabled.
 
K

Keith Thompson

pete said:
Section "6.5 Expressions" in both C89 and in C99,
described the bitwise operators as returning values.

C99 says they "return" values; N1256 says they "yield" values,
as does N1570 (the C11 pre-release draft).

None of the three Technical Corrigenda (which in theory constitute
the difference between C99 and N1256) contain the word "yield".
I think the editor, Larry Jones, just made the change himself.
 
P

Phil Carmody

Keith Thompson said:
C99 says they "return" values; N1256 says they "yield" values,
as does N1570 (the C11 pre-release draft).

None of the three Technical Corrigenda (which in theory constitute
the difference between C99 and N1256) contain the word "yield".
I think the editor, Larry Jones, just made the change himself.

Not just that, but he disclosed that here after a discussion
almost identical to this one. IIRC.

Whilst I think it's good to wean people off inappropriate use of
"return", I don't think it's worth making too big a thing of, at
least if the question has been understood by everyone who didn't
deliberately want to be adversarial.

Phil
--
I'd argue that there is much evidence for the existence of a God.
Pics or it didn't happen.
-- Tom (/. uid 822)
 
T

Tim Rentsch

Ben Bacarisse said:
Xavier Roche said:
Hi folks!

Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result
is.. 1.

How odd.
Is the result undefined by the standard, by chance ?

No, it's defined to be 0.

It does not violate any constraint that I can see, and the meaning
depends solely on whether 0.0 "compares equal to 0". I can't find any
justification for 0.0 not comparing equal to 0. [snip elaboration]

Because of the vagaries of how floating point is represented,
I believe it is possible in principle for 0.0 to be seen as
true (that is, != 0) in a conforming implementation, if that
implementation (a) does not have an exact FP representation for zero,
and (b) has implementation-defined rounding rules which are defined
suitably. AFAIK both (a) and (b) may be true in a conforming
implementation, that is, I don't know of any requirement that
prevents the possibility of either (or of both together).

Of course, I don't know of any ACTUAL implementation for which
even just (a) holds, but just theoretically I think it is possible.
 
T

Tim Rentsch

Keith Thompson said:
An expression *yields* a value. (I think earlier versions of the
standard used the word "return" for the results of expressions in
some places; as far as I know it's been cleaned up.)

I'd say that an expression /had/ a value (and that an /evaluation/
yielded a value). Let me try to find quotations in N1570:
and its initial value is the value of the expression.<<
-----------------------expression if it can deduce that its value is not used
and that no needed side effects are produced<<
and its initial value is the value of the expression.<<
void expression, its value or designator is discarded.<<

The relationship between an expression and its value in all
these quotes (selected without bias) is always /possessive/,
hence /has/. [snip]

There are also lots of places where the Standard uses phrasing like
'an expression yields the value ...' or 'x[3][5] yields ...'.
Generally speaking the Standard often doesn't do a good job of
observing the distinction between translation-time properties and
execution-time properties. Strictly speaking, an expression is a
translation-time entity; it is only an evaulation of an expression
that has (or yields) a value, or evaluating an expression that yields
a value. Some expressions have the property that every time they are
evaluated the evaluations always yield the same value, and there it
might be more defensible to say that the expression /has/ that value.
But I don't think the Standard itself is careful about these
distinctions one way or the other.
 
T

Tim Rentsch

Keith Thompson said:
pete said:
Section "6.5 Expressions" in both C89 and in C99,
described the bitwise operators as returning values.

C99 says they "return" values; N1256 says they "yield" values,
as does N1570 (the C11 pre-release draft). [snip]

Yes, and N1124 is like N1256 in this regard.
 
R

Ralf Damaschke

Tim Rentsch said:
I believe it is possible in principle for 0.0 to be seen as
true (that is, != 0) in a conforming implementation, if that
implementation (a) does not have an exact FP representation for
zero, and (b) has implementation-defined rounding rules which
are defined suitably. AFAIK both (a) and (b) may be true in a
conforming implementation, that is, I don't know of any
requirement that prevents the possibility of either (or of both
together).

There is one. An implementation (a) would not suffice C99 5.2.4.2.2
"Characteristics of floating types <float.h>"; esp. the sum used to
define a floating-point number gives 0 if f(k) = 0 for all
1 <= k <= p.

-- Ralf
 
B

Ben Bacarisse

Tim Rentsch said:
Ben Bacarisse said:
Xavier Roche said:
Hi folks!

Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result
is.. 1.

How odd.
Is the result undefined by the standard, by chance ?

No, it's defined to be 0.

It does not violate any constraint that I can see, and the meaning
depends solely on whether 0.0 "compares equal to 0". I can't find any
justification for 0.0 not comparing equal to 0. [snip elaboration]

Because of the vagaries of how floating point is represented,
I believe it is possible in principle for 0.0 to be seen as
true (that is, != 0) in a conforming implementation, if that
implementation (a) does not have an exact FP representation for zero,
and (b) has implementation-defined rounding rules which are defined
suitably. AFAIK both (a) and (b) may be true in a conforming
implementation, that is, I don't know of any requirement that
prevents the possibility of either (or of both together).

I took the characteristics of floating point numbers presented in
5.2.4.2.2 to mean that C had to use a representation that includes (an
exact) zero.

But, as you say, it turns out that an implementation is not required to
represent exactly even exactly representable floating constants.
Fortunately, this must be documented so in the absence of any such
explanation, 0.0 will be equal to 0.
Of course, I don't know of any ACTUAL implementation for which
even just (a) holds, but just theoretically I think it is possible.

Well, I thought not, but it doesn't matter anyway as far as I can see.
Even if zero is representable, 0.0 can convert to any one of three
values according to 6.4.4.2 p3.
 
T

Tim Rentsch

Ralf Damaschke said:
There is one. An implementation (a) would not suffice C99 5.2.4.2.2
"Characteristics of floating types <float.h>"; esp. the sum used to
define a floating-point number gives 0 if f(k) = 0 for all
1 <= k <= p.

If you read the footnote to 5.2.4.2.2 p1, and also 5.2.4.2.2 p3,
I think you'll agree that the condition you describe need not
be an actual representable value in a particular conforming
implementation. The value does exist in the model, but the
model may not reflect what the implementation actually uses,
and even if it does, the implementation might not provide FP
numbers with f(1) == 0. Needless to say, I did consult this
section (and these paragraphs) before making my earlier
comments. So I still think it's possible for an implementation
to not have zero as a representable FP value.
 
T

Tim Rentsch

Ben Bacarisse said:
Tim Rentsch said:
Ben Bacarisse said:
Hi folks!

Is there a C standard expert who can confirm what shall return
0.0 ? 1 : 0

With gcc 4.3/Linux, the result is 0. With Visual C++2010, the result
is.. 1.

How odd.

Is the result undefined by the standard, by chance ?

No, it's defined to be 0.

It does not violate any constraint that I can see, and the meaning
depends solely on whether 0.0 "compares equal to 0". I can't find any
justification for 0.0 not comparing equal to 0. [snip elaboration]

Because of the vagaries of how floating point is represented,
I believe it is possible in principle for 0.0 to be seen as
true (that is, != 0) in a conforming implementation, if that
implementation (a) does not have an exact FP representation for zero,
and (b) has implementation-defined rounding rules which are defined
suitably. AFAIK both (a) and (b) may be true in a conforming
implementation, that is, I don't know of any requirement that
prevents the possibility of either (or of both together).

I took the characteristics of floating point numbers presented in
5.2.4.2.2 to mean that C had to use a representation that includes (an
exact) zero.

But, as you say, it turns out that an implementation is not required to
represent exactly even exactly representable floating constants.
Fortunately, this must be documented so in the absence of any such
explanation, 0.0 will be equal to 0.
Of course, I don't know of any ACTUAL implementation for which
even just (a) holds, but just theoretically I think it is possible.

Well, I thought not, but it doesn't matter anyway as far as I can see.
Even if zero is representable, 0.0 can convert to any one of three
values according to 6.4.4.2 p3.

I had read this paragraph earlier, but either I misread it or
I missed the full implications of what it says. I expected
that any FP constant that could be represented exactly must
necessarily be given that exact value, but now that you point
it out obviously it doesn't. So this isn't just a theoretical
problem -- it's only QOI that saves us from some very surprising
results.

Thank you for following up with this observation. Yet another
strange corner of C that I didn't realize was so strange.
 

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,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top