Discussion:
C2124 is most disrespectful of IEEE floating point arithmetic
(too old to reply)
Dr Pizza
2006-08-28 00:51:26 UTC
Permalink
Since VC++ purports to follow IEC 559, and IEC 559 defines the division
of a non-zero by a zero to be a signed infinity, isn't it rather silly
that:

float inf(1.0f / 0.0f);

should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?

What gives? Am I being unreasonable in my expectations? It's
certainly rather nicer to type the above than have to spew:

float inf(std::numeric_limits<float>::infinity());

--
John Carson
2006-08-28 02:21:37 UTC
Permalink
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the
division of a non-zero by a zero to be a signed infinity, isn't it
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
For what it is worth, this compiles:

float zero = 0.0f;
float f(1.0f/zero);

as does

const float zero = 0.0f;
float f(1.0f/zero);

It is apparently only a literal zero that gives a problem.
--
John Carson
Dr Pizza
2006-08-28 10:45:24 UTC
Permalink
Post by John Carson
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the
division of a non-zero by a zero to be a signed infinity, isn't it
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
float zero = 0.0f;
float f(1.0f/zero);
as does
const float zero = 0.0f;
float f(1.0f/zero);
It is apparently only a literal zero that gives a problem.
Weird. I had expected that the compiler would propagate the constant
zero and emit the same error, but looking at the generated assembly it
doesn't; it performs a runtime division.

--
Abdo Haji-Ali
2006-08-28 14:30:29 UTC
Permalink
Post by Dr Pizza
Weird. I had expected that the compiler would propagate the constant
zero and emit the same error, but looking at the generated assembly it
doesn't; it performs a runtime division.
But it does... At least in release builds

This code:
<code>
const float fZero = 0;
float fDummy = 1.0f / fZero;
fDummy += 1.0f;
printf("%f\n" , fDummy);
return 0;
</code>

would give the warning C4723 (in release) and the compiler did propagate the
constant zero but performed a runtime division of the form 1.0f / 0...

Also note that VC doesn't even perform a runtime division *if* the the
second operand wasn't zero. So I guess the zero is a special case (don't
know why though)
--
Abdo Haji-Ali
Programmer
In|Framez
Abdo Haji-Ali
2006-08-28 14:39:05 UTC
Permalink
Post by Abdo Haji-Ali
Post by Dr Pizza
Weird. I had expected that the compiler would propagate the constant
zero and emit the same error, but looking at the generated assembly it
doesn't; it performs a runtime division.
But it does... At least in release builds
<code>
const float fZero = 0;
float fDummy = 1.0f / fZero;
fDummy += 1.0f;
printf("%f\n" , fDummy);
return 0;
</code>
would give the warning C4723 (in release) and the compiler did propagate the
constant zero but performed a runtime division of the form 1.0f / 0...
Also note that VC doesn't even perform a runtime division *if* the the
second operand wasn't zero. So I guess the zero is a special case (don't
know why though)
Thinking about it, I *guess* it does so to set the FPU status word to imply
a division by zero...
--
Abdo Haji-Ali
Programmer
In|Framez
Dr Pizza
2006-08-28 17:41:56 UTC
Permalink
Post by Abdo Haji-Ali
Post by Dr Pizza
Weird. I had expected that the compiler would propagate the
constant zero and emit the same error, but looking at the generated
assembly it doesn't; it performs a runtime division.
But it does... At least in release builds
<code>
const float fZero = 0;
float fDummy = 1.0f / fZero;
fDummy += 1.0f;
printf("%f\n" , fDummy);
return 0;
</code>
would give the warning C4723 (in release) and the compiler did
propagate the constant zero but performed a runtime division of the
form 1.0f / 0...
Well that's odd; it propagates the zero but doesn't see it as being a
guaranteed dead-cert divide by zero; notice it only warns C4723
(potential divide by zero) instead of error C2124 (divide by zero). If
it propagates the zero the two ought to be identical one would have
thought.
Post by Abdo Haji-Ali
Also note that VC doesn't even perform a runtime division if the the
second operand wasn't zero. So I guess the zero is a special case
(don't know why though)
I presume it leaves it as a runtime division because there's no way to
statically determine the FP flags. It can't just load a hardcoded
infinity because FP exceptions may have been enabled, in which case it
should generate a runtime divide by zero. In "normal" divisions, this
presumably isn't the case (although it may be possible to get
differences in rounding mode?).

--
Alexander Grigoriev
2006-08-28 04:47:09 UTC
Permalink
This is a compile-time constant expression, and is evaluated on compilation
time.
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the division
of a non-zero by a zero to be a signed infinity, isn't it rather silly
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
--
Dr Pizza
2006-08-28 10:39:39 UTC
Permalink
Post by Alexander Grigoriev
This is a compile-time constant expression, and is evaluated on
compilation time.
And?

Why won't it evaluate to a compile-time infinite floating point value?

--
Abdo Haji-Ali
2006-08-28 14:44:48 UTC
Permalink
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the division
of a non-zero by a zero to be a signed infinity, isn't it rather silly
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
IIRC, a compiler option can be set to throw an exception even for float
operations
Post by Dr Pizza
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
IMO, this form is much better; at lease it clearly states what you want...
--
Abdo Haji-Ali
Programmer
In|Framez
Doug Harrison [MVP]
2006-08-28 16:27:05 UTC
Permalink
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the division
of a non-zero by a zero to be a signed infinity, isn't it rather silly
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
Division by zero is undefined, so the compiler can do whatever it wants.
For a compile-time expression, emitting an error is highly appropriate.
Using numeric_limits as above is self-documenting and portable, and it is
highly preferable to 1.0/0.0.
--
Doug Harrison
Visual C++ MVP
Dr Pizza
2006-08-28 17:01:17 UTC
Permalink
On Sun, 27 Aug 2006 17:51:26 -0700, "Dr Pizza"
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the
division of a non-zero by a zero to be a signed infinity, isn't it
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
Division by zero is undefined, so the compiler can do whatever it
wants. For a compile-time expression, emitting an error is highly
appropriate. Using numeric_limits as above is self-documenting and
portable, and it is highly preferable to 1.0/0.0.
But it isn't undefined. Well; it's undefined in standard mathematics.
It isn't undefined in IEC 559, and VC++ purports to adhere to IEC 559.

IEEE 754 says that in the case of division of a finite value by zero:
<quotation>
7.2 Division by Zero

If the divisor is zero and the dividend is a finite nonzero number,
then the division by zero exception shall be signaled. The result, when
no trap occurs, shall be a correctly signed [Infinity] (6.3).
</quotation>

So depending on our handling of FP exceptions we should see one of two
things: with exceptions disabled, a signed infinity; with exceptions
enabled a divide by zero exception.

Yet in this case we get neither a trap nor a correctly signed infinity.
Instead, we have a compile-time error.

This is in spite of std::numeric_limits<float>::is_iec559 being 'true'
for float.

I don't see how you can have it both ways. Either is_iec559 should be
'false'--in which case all bets are off as to the behaviour of these
types and they are indeed "undefined", and a compile-time error is
consistent (even if not at all useful)--or the compiler should refrain
from trapping the division at compile-time, and instead allow the
defined runtime behaviour to occur.

I don't see why using numeric_limits is "highly preferable", as 1.0/0.0
is concise, well-defined, and clear.

--
Abdo Haji-Ali
2006-08-28 18:24:59 UTC
Permalink
Post by Dr Pizza
Post by Doug Harrison [MVP]
Division by zero is undefined, so the compiler can do whatever it
wants. For a compile-time expression, emitting an error is highly
appropriate. Using numeric_limits as above is self-documenting and
portable, and it is highly preferable to 1.0/0.0.
But it isn't undefined. Well; it's undefined in standard mathematics.
It isn't undefined in IEC 559, and VC++ purports to adhere to IEC 559.
<quotation>
7.2 Division by Zero
If the divisor is zero and the dividend is a finite nonzero number,
then the division by zero exception shall be signaled. The result, when
no trap occurs, shall be a correctly signed [Infinity] (6.3).
</quotation>
IEEE is a standard for FPU implementation not for C++ compilers. While
division by zero is defined in IEEE it's not defined in C++ standard
--
Abdo Haji-Ali
Programmer
In|Framez
Dr Pizza
2006-08-28 17:36:48 UTC
Permalink
Post by Abdo Haji-Ali
Post by Dr Pizza
Post by Doug Harrison [MVP]
Division by zero is undefined, so the compiler can do whatever it
wants. For a compile-time expression, emitting an error is highly
appropriate. Using numeric_limits as above is self-documenting
and portable, and it is highly preferable to 1.0/0.0.
But it isn't undefined. Well; it's undefined in standard
mathematics. It isn't undefined in IEC 559, and VC++ purports to
adhere to IEC 559.
IEEE 754 says that in the case of division of a finite value by
zero: <quotation>
7.2 Division by Zero
If the divisor is zero and the dividend is a finite nonzero number,
then the division by zero exception shall be signaled. The result,
when no trap occurs, shall be a correctly signed [Infinity] (6.3).
</quotation>
IEEE is a standard for FPU implementation not for C++ compilers. While
division by zero is defined in IEEE it's not defined in C++ standard
Then what possible value can numeric_limits::is_iec559 have?

If what you say is true then numeric_limits::is_iec559 is 100% useless
and surely should not exist?

--
Victor Bazarov
2006-08-28 17:44:01 UTC
Permalink
Post by Dr Pizza
Post by Abdo Haji-Ali
Post by Dr Pizza
Post by Doug Harrison [MVP]
Division by zero is undefined, so the compiler can do whatever it
wants. For a compile-time expression, emitting an error is highly
appropriate. Using numeric_limits as above is self-documenting
and portable, and it is highly preferable to 1.0/0.0.
But it isn't undefined. Well; it's undefined in standard
mathematics. It isn't undefined in IEC 559, and VC++ purports to
adhere to IEC 559.
IEEE 754 says that in the case of division of a finite value by
zero: <quotation>
7.2 Division by Zero
If the divisor is zero and the dividend is a finite nonzero number,
then the division by zero exception shall be signaled. The result,
when no trap occurs, shall be a correctly signed [Infinity] (6.3).
</quotation>
IEEE is a standard for FPU implementation not for C++ compilers.
While division by zero is defined in IEEE it's not defined in C++
standard
Then what possible value can numeric_limits::is_iec559 have?
'false' and not 'false'.
Post by Dr Pizza
If what you say is true then numeric_limits::is_iec559 is 100% useless
and surely should not exist?
Is that a question? The existence of IEC 559 (IEEE 754) is acknowledged
by the C++ Standard but C++ floating point types don't have to adhere to
it. That's what it means.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
John Carson
2006-08-28 18:15:49 UTC
Permalink
Post by Victor Bazarov
Post by Dr Pizza
If what you say is true then numeric_limits::is_iec559 is 100%
useless and surely should not exist?
Is that a question? The existence of IEC 559 (IEEE 754) is
acknowledged by the C++ Standard but C++ floating point types don't
have to adhere to it. That's what it means.
The point is that

bool result = numeric_limits<float>::is_iec559;

sets result to true in VC++. This rather implies that VC++ floats do have to
adhere to IEC 559.
--
John Carson
Sean M. DonCarlos
2006-08-28 19:21:02 UTC
Permalink
Post by John Carson
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats do have to
adhere to IEC 559.
They do. The compiler doesn't:

#include <cstdlib>
#include <limits>
#define F_INF (std::numeric_limits<float>::infinity())

int main()
{
float a = 1.0f;
float b = 0.0f;

float c = 1.0f / 0.0f; // error C2124 - compiler sees divison by
constant zero
float d = a / b; // no compiler error - b is not a constant zero

bool e = (d == F_INF); // e is expected to be true here

return 0;
}

Sean
John Carson
2006-08-28 19:37:57 UTC
Permalink
Post by Sean M. DonCarlos
Post by John Carson
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats do
have to adhere to IEC 559.
This is a distinction that is at best subtle and at worst meaningless. I
find it hard to see how the conformance of particular C++ types to a
standard can be independent of how the C++ compiler behaves.

Your examples below illustrate what compiles and what doesn't. They don't
tell me the conceptual distinction involved --- why one thing compiling and
another not compiling constitute conformance with IEC 559.
Post by Sean M. DonCarlos
#include <cstdlib>
#include <limits>
#define F_INF (std::numeric_limits<float>::infinity())
int main()
{
float a = 1.0f;
float b = 0.0f;
float c = 1.0f / 0.0f; // error C2124 - compiler sees divison by
constant zero
float d = a / b; // no compiler error - b is not a constant zero
bool e = (d == F_INF); // e is expected to be true here
return 0;
}
--
John Carson
Sean M. DonCarlos
2006-08-28 22:55:02 UTC
Permalink
Post by John Carson
This is a distinction that is at best subtle and at worst meaningless. I
find it hard to see how the conformance of particular C++ types to a
standard can be independent of how the C++ compiler behaves.
IEC 559 defines certain standard behaviors for certain data types and
certain operations inside an FPU. It doesn't define anything about how these
data types and operations function outside of the FPU. If a given C++
compiler can't process 1.0f / 0.0f, that has nothing to do with the FPU or
IEC 559.

Let's look at the relevant section of IEC 559, thoughtfully quoted earlier:

7.2 Division by Zero
If the divisor is zero and the dividend is a finite nonzero number,
then the division by zero exception shall be signaled. The result,
when no trap occurs, shall be a correctly signed [Infinity] (6.3).

As I understand it, this means:

If the FPU has a value representing a finite nonzero number in one of its
registers and the FPU has a value representing zero in another of its
registers and the FPU receives the instruction to divide the contents of the
first register by the contents of the second register, the FPU will signal
the divide-by-zero exception. If no trap occurs, the result of processing the
instruction will be a value representing an infinity with the correct sign.

Note that there is nothing in the above paragraph that is specific to C++,
or any other programming language for that matter. Therefore, IEC 559 has
nothing to do with why MS's C++ compiler won't compile "1.0f / 0.0f".

The specific C++ data type "float" is IEC 559-compliant in the sense that IF
you can get an object of type "float" into the FPU, that object will behave
in accordance with IEC 559. Compliance is an attribute of the data type, not
of the compiler.

If I had to guess why the compiler doesn't allow "1.0f / 0.0f", I would say
that the number of applications where dividing by a literal zero is an error
far outweighs the number of applications where it is intended (as opposed to
dividing by a variable that might happen to be zero, which the compiler does
allow), and that in most cases where dividing by literal zero is intended, it
is because the developer wanted an infinity. One of the libraries has an
explicit method of producing an infinity - std::numeric_limits<T>::infinity()
- and so the compiler developers decided that the compiler would not accept
any division by literal zero, since there was already a well-defined way of
supplying an infinite value.

I am not even going to begin to touch on the question of whether this is a
good idea or not. Suffice to say that at least one of the compiler developers
thought it was, and several of us here think it is not.

Sean
John Carson
2006-08-29 02:01:11 UTC
Permalink
Post by Sean M. DonCarlos
If the FPU has a value representing a finite nonzero number in one of
its registers and the FPU has a value representing zero in another of
its registers and the FPU receives the instruction to divide the
contents of the first register by the contents of the second
register, the FPU will signal the divide-by-zero exception. If no
trap occurs, the result of processing the instruction will be a value
representing an infinity with the correct sign.
Note that there is nothing in the above paragraph that is specific to
C++, or any other programming language for that matter. Therefore,
IEC 559 has nothing to do with why MS's C++ compiler won't compile
"1.0f / 0.0f".
The specific C++ data type "float" is IEC 559-compliant in the sense
that IF you can get an object of type "float" into the FPU, that
object will behave in accordance with IEC 559. Compliance is an
attribute of the data type, not of the compiler.
So on this interpretation

numeric_limits<float>::is_iec559;

is informing you of a property of the hardware that the program will run on?
--
John Carson
Doug Harrison [MVP]
2006-08-29 02:40:17 UTC
Permalink
On Tue, 29 Aug 2006 12:01:11 +1000, "John Carson"
Post by John Carson
So on this interpretation
numeric_limits<float>::is_iec559;
is informing you of a property of the hardware that the program will run on?
No, it's telling you about the behavior of the float type.
--
Doug Harrison
Visual C++ MVP
Dr Pizza
2006-08-28 21:17:41 UTC
Permalink
Post by John Carson
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats
do have to adhere to IEC 559.
If the compiler doesn't then the compiler should leave well enough
alone. If the compiler is too stupid to compute the value at compile
time then it should leave it to be evaluated at runtime (when it works).

There is no proscription against writing 1.0f / 0.0f in C++. The
compiler should not reject such an expression (provided that the
expression occurs in an appropriate place, of course).

--
Victor Bazarov
2006-08-28 22:09:39 UTC
Permalink
Post by Dr Pizza
Post by John Carson
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats
do have to adhere to IEC 559.
If the compiler doesn't then the compiler should leave well enough
alone. If the compiler is too stupid to compute the value at compile
time then it should leave it to be evaluated at runtime (when it works).
It's not too stupid. It's protecting you from being too stupid. Such
calculation at run time is likely to signal, which can cause abnormal
termination (unless you provide a trap, at which case the result is
still useless). That's why you should never use 1.f/0.f to produce
the infinity, and use 'std::numeric_limits<float>::infinity()' instead.
Post by Dr Pizza
There is no proscription against writing 1.0f / 0.0f in C++.
No, but the behaviour of a program that necessitates such operation is
*undefined*. Either the compiler's behaviour (if the compiler does in
fact evaluate that expression) is undefined, or, if the compiler produces
the code to do the calculation during run-time, the program's behaviour
is undefined. And that's NOT dependent on IEC 559.
Post by Dr Pizza
The
compiler should not reject such an expression (provided that the
expression occurs in an appropriate place, of course).
Why?

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Tom Widmer [VC++ MVP]
2006-08-29 15:26:28 UTC
Permalink
Post by Dr Pizza
Post by John Carson
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats
do have to adhere to IEC 559.
If the compiler doesn't then the compiler should leave well enough
alone. If the compiler is too stupid to compute the value at compile
time then it should leave it to be evaluated at runtime (when it works).
There is no proscription against writing 1.0f / 0.0f in C++. The
compiler should not reject such an expression (provided that the
expression occurs in an appropriate place, of course).
Conforming compilers are required to reject the expression regardless of
iec 559 support:

5/5
"If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable values for
its type, the behavior is undefined, unless such an expression is a
constant expression (5.19), in which case the program is ill-formed."

That seems pretty clear to me. 1.0/0.0 is a constant expression, and
hence a compiler error is expected. If that's not sufficient for you,
then there's also this:

5.6/4
"The binary / operator yields the quotient, and the binary % operator
yields the remainder from the division of the first expression by the
second. If the second operand of / or % is zero the behavior is undefined;"

Tom
Victor Bazarov
2006-08-28 19:26:32 UTC
Permalink
Post by John Carson
Post by Victor Bazarov
Post by Dr Pizza
If what you say is true then numeric_limits::is_iec559 is 100%
useless and surely should not exist?
Is that a question? The existence of IEC 559 (IEEE 754) is
acknowledged by the C++ Standard but C++ floating point types don't
have to adhere to it. That's what it means.
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats do
have to adhere to IEC 559.
That's true. IOW, the program in which is_iec559 is 'true' has to
provide the functionality in accordance to IEC 559. How do we know
that the _compiler_ is such program? FP division by 0 happens in
the compiler, not in our program. Do we know what is_iec559 is in
the compiler itself?

The other side of the story is that the compiler *probably* provides
a *trap* for a FP division by 0. In the existence of such trap, the
result doesn't have to be of any specific kind.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dr Pizza
2006-08-28 21:15:26 UTC
Permalink
Post by Victor Bazarov
Post by John Carson
Post by Victor Bazarov
Post by Dr Pizza
If what you say is true then numeric_limits::is_iec559 is 100%
useless and surely should not exist?
Is that a question? The existence of IEC 559 (IEEE 754) is
acknowledged by the C++ Standard but C++ floating point types
don't have to adhere to it. That's what it means.
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats do
have to adhere to IEC 559.
That's true. IOW, the program in which is_iec559 is 'true' has to
provide the functionality in accordance to IEC 559. How do we know
that the compiler is such program?
The compiler doesn't have to be, because the compiler is not the
program that performs the computation.
Post by Victor Bazarov
FP division by 0 happens in
the compiler, not in our program. Do we know what is_iec559 is in
the compiler itself?
Except it doesn't happen in the compiler. It's a runtime expression.
The compiler is under no compulsion to try to compute the value at
compile time, and if the compiler cannot do so then the compiler should
leave the runtime expression--NOT generate an error.
Post by Victor Bazarov
The other side of the story is that the compiler probably provides
a trap for a FP division by 0. In the existence of such trap, the
result doesn't have to be of any specific kind.
There is nothing malformed about the code snippet, so the compiler
should compile it WITHOUT COMPLAINT.


--
Victor Bazarov
2006-08-29 01:21:59 UTC
Permalink
Post by Dr Pizza
Post by Victor Bazarov
Post by John Carson
Post by Victor Bazarov
Post by Dr Pizza
If what you say is true then numeric_limits::is_iec559 is 100%
useless and surely should not exist?
Is that a question? The existence of IEC 559 (IEEE 754) is
acknowledged by the C++ Standard but C++ floating point types
don't have to adhere to it. That's what it means.
The point is that
bool result = numeric_limits<float>::is_iec559;
sets result to true in VC++. This rather implies that VC++ floats do
have to adhere to IEC 559.
That's true. IOW, the program in which is_iec559 is 'true' has to
provide the functionality in accordance to IEC 559. How do we know
that the compiler is such program?
The compiler doesn't have to be, because the compiler is not the
program that performs the computation.
Why not? Is there something that prohibits the compiler from trying
to compute the expression whose all parts are constant?
Post by Dr Pizza
Post by Victor Bazarov
FP division by 0 happens in
the compiler, not in our program. Do we know what is_iec559 is in
the compiler itself?
Except it doesn't happen in the compiler. It's a runtime expression.
So what if it is? The compiler is allowed to check semantics just
like it can check them when you write

bool blah = false;
if (blah) {
throw 10; /// unreacheable code.
}
Post by Dr Pizza
The compiler is under no compulsion to try to compute the value at
compile time, and if the compiler cannot do so then the compiler
should leave the runtime expression--NOT generate an error.
The compiler is free to calculate it if it wants to. The division by
zero, however, has undefined behaviour, and if the compiler can tell
me, I'd rather know when it's compiling.
Post by Dr Pizza
Post by Victor Bazarov
The other side of the story is that the compiler probably provides
a trap for a FP division by 0. In the existence of such trap, the
result doesn't have to be of any specific kind.
There is nothing malformed about the code snippet, so the compiler
should compile it WITHOUT COMPLAINT.
Post it as the error on the Microsoft's Visual C++ site.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dr Pizza
2006-08-29 19:32:15 UTC
Permalink
Post by Victor Bazarov
So what if it is? The compiler is allowed to check semantics just
like it can check them when you write
But the semantics are *fine*. They are *defined*. They are
*meaningful*. They are not a problem at all. Yet the compiler is
prohibiting the expression.
Post by Victor Bazarov
The compiler is free to calculate it if it wants to. The division by
zero, however, has undefined behaviour, and if the compiler can tell
me, I'd rather know when it's compiling.
It doesn't have undefined behaviour. IEC 559 exactly defines the
behaviour. I want to use this defined behaviour. VC++ gets in my way.

--
Victor Bazarov
2006-08-29 20:00:10 UTC
Permalink
[..] IEC 559 exactly defines the
behaviour. I want to use this defined behaviour. VC++ gets in my way.
You're confused. VC++ does not have to adhere to IEC 559, only to
ISO/IEC 14882. In VC++ world the behaviour is NOT defined. Snap
out of it!

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dr Pizza
2006-08-30 07:40:22 UTC
Permalink
Post by Victor Bazarov
[..] IEC 559 exactly defines the
behaviour. I want to use this defined behaviour. VC++ gets in my way.
You're confused. VC++ does not have to adhere to IEC 559, only to
ISO/IEC 14882. In VC++ world the behaviour is NOT defined. Snap
out of it!
V
The behaviour is defined, because VC++ claims that its floats are IEC
559 floats.

If its floats are NOT IEC 559 floats then we have NO WAY of knowing
what the result of ANY floating point operation are, because the C++
standard does NOT spell out the details.

--
Sean M. DonCarlos
2006-08-28 17:50:01 UTC
Permalink
Post by Dr Pizza
But it isn't undefined. Well; it's undefined in standard mathematics.
It isn't undefined in IEC 559, and VC++ purports to adhere to IEC 559.
IEC 559 / IEEE 754 applies to floating-point processors, not C++ compilers.
The Standard C++ Library does contain certain types that conform to IEC 559.
Post by Dr Pizza
Yet in this case we get neither a trap nor a correctly signed infinity.
Instead, we have a compile-time error.
Yes, because the compiler sees division by constant zero, which is error
C2124.
Post by Dr Pizza
This is in spite of std::numeric_limits<float>::is_iec559 being 'true'
for float.
Yes. The complier doesn't really know about IEC 559 and doesn't really care.
All it knows is not to allow division by constant zero.
Post by Dr Pizza
I don't see why using numeric_limits is "highly preferable", as 1.0/0.0
is concise, well-defined, and clear.
What's wrong with something like:

#define F_INF (std::numeric_limits<float>::infinity())
// Use F_INF wherever a positive infinity is needed

Sean
Alexander Grigoriev
2006-08-29 04:14:08 UTC
Permalink
In the standard:

"If during the evaluation of an expression, the result is not mathematically
defined or not in the range of representable
values for its type, the behavior is undefined, unless such an expression is
a constant expression
(5.19), in which case the program is illformed.
[Note: most existing implementations of C++ ignore integer
overflows. Treatment of division by zero, forming a remainder using a zero
divisor, and all floating
point exceptions vary among machines, and is usually adjustable by a library
function. ]"

Clause 5.119.3:
An arithmetic constant expression shall have arithmetic or enumeration type
and shall only have operands
that are integer literals (2.13.1), floating literals (2.13.3), enumerators,
character literals (2.13.2) and
sizeof expressions (5.3.3). Cast operators in an arithmetic constant
expression shall only convert arithmetic
or enumeration types to arithmetic or enumeration types, except as part of
an operand to the sizeof
operator.

This means: 1.f/0.f is a constant expression and the compiler is evaluating
it on compile time. Since it's not _mathematically_ defined (don't mind it's
defined by IEC559), the program is illformed.

const float zero = 0.;
float inf = 1. / zero; // not a constant expression, contains non-integer
variables (even though const).

Note that const variables form a integer constant expression only if they
are int or enum. See 5.19.1.
Post by Dr Pizza
On Sun, 27 Aug 2006 17:51:26 -0700, "Dr Pizza"
Post by Dr Pizza
Since VC++ purports to follow IEC 559, and IEC 559 defines the
division of a non-zero by a zero to be a signed infinity, isn't it
float inf(1.0f / 0.0f);
should result in a compile-time error, C2124? An error may be
appropriate for integer arithmetic (as it'll generate a runtime SEH
exception), but for floating point arithmetic it's surely incorrect
behaviour?
What gives? Am I being unreasonable in my expectations? It's
float inf(std::numeric_limits<float>::infinity());
Division by zero is undefined, so the compiler can do whatever it
wants. For a compile-time expression, emitting an error is highly
appropriate. Using numeric_limits as above is self-documenting and
portable, and it is highly preferable to 1.0/0.0.
But it isn't undefined. Well; it's undefined in standard mathematics.
It isn't undefined in IEC 559, and VC++ purports to adhere to IEC 559.
<quotation>
7.2 Division by Zero
If the divisor is zero and the dividend is a finite nonzero number,
then the division by zero exception shall be signaled. The result, when
no trap occurs, shall be a correctly signed [Infinity] (6.3).
</quotation>
So depending on our handling of FP exceptions we should see one of two
things: with exceptions disabled, a signed infinity; with exceptions
enabled a divide by zero exception.
Yet in this case we get neither a trap nor a correctly signed infinity.
Instead, we have a compile-time error.
This is in spite of std::numeric_limits<float>::is_iec559 being 'true'
for float.
I don't see how you can have it both ways. Either is_iec559 should be
'false'--in which case all bets are off as to the behaviour of these
types and they are indeed "undefined", and a compile-time error is
consistent (even if not at all useful)--or the compiler should refrain
from trapping the division at compile-time, and instead allow the
defined runtime behaviour to occur.
I don't see why using numeric_limits is "highly preferable", as 1.0/0.0
is concise, well-defined, and clear.
--
John Carson
2006-08-29 12:03:45 UTC
Permalink
Post by Alexander Grigoriev
"If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable
values for its type, the behavior is undefined, unless such an
expression is a constant expression
(5.19), in which case the program is illformed.
[Note: most existing implementations of C++ ignore integer
overflows. Treatment of division by zero, forming a remainder using a
zero divisor, and all floating
point exceptions vary among machines, and is usually adjustable by a
library function. ]"
An arithmetic constant expression shall have arithmetic or
enumeration type and shall only have operands
that are integer literals (2.13.1), floating literals (2.13.3),
enumerators, character literals (2.13.2) and
sizeof expressions (5.3.3). Cast operators in an arithmetic constant
expression shall only convert arithmetic
or enumeration types to arithmetic or enumeration types, except as
part of an operand to the sizeof
operator.
This means: 1.f/0.f is a constant expression and the compiler is
evaluating it on compile time. Since it's not _mathematically_
defined (don't mind it's defined by IEC559), the program is illformed.
You almost had me convinced. As I understand your argument, the C++ standard
leaves the compiler implementer wriggle room (i.e., behaviour is undefined)
in handling mathematically undefined expressions provided they are not
constant expressions. To that extent, the compiler can conform with IEC 559
with regards to division by zero.

However, when dealing with constant expressions, there is no wriggle room
for mathematically undefined expressions (the program is ill-formed), so IEC
559 is irrelevant for a conforming implementation.

I note, however, that Comeau online compiles

float f (1.0f/0.0f);

without complaint.

On the other hand, it issues a warning for

float f(1/0);

So is Comeau non-conformant, or is something being missed here?

You refer to the standard but seem to have merged some passages. The 2003
standard says in section 5.19/1:

"An integral constant-expression can involve only literals (2.13),
enumerators, const variables or static data members of integral or
enumeration types initialized with constant expressions (8.5), non-type
template parameters of integral or enumeration types, and sizeof
expressions. Floating literals (2.13.3) can appear only if they are cast to
integral or enumeration types. Only type conversions to integral or
enumeration types can be used. In particular, except in sizeof expressions,
functions, class objects, pointers, or references shall not be used, and
assignment, increment, decrement, function-call, or comma operators shall
not be used."

Now, since the floating literals in 1.0f/0.0f are not cast to integral or
enumeration types, 1.0f/0.0f does not constitute an "integral
constant-expression".

There is another possibility: an "arithmetic constant expression". By 5.19/3

"An arithmetic constant expression shall satisfy the requirements for an
integral constant expression, except that
- floating literals need not be cast to integral or enumeration type,
- conversions to floating point types are permitted."

Thus 1.0f/0.0f is an "arithmetic constant expression". Is this the same as a
"constant expression" that would make the program ill-formed. Section 5.19/2
appears to give the answer:

"Other expressions [including arithmetic constant expressions] are
considered constant-expressions only for the purpose of non-local static
object initialization (3.6.2)."

In

int main()
{
float f (1.0f/0.0f);
}

f is not a non-local static object, so 1.0f/0.0f is not a "constant
expression" and therefore the program is *not* ill-formed.

By this reasoning, however,

float f (1.0f/0.0f);
int main()
{
}

is ill-formed. Comeau, however, compiles this program too, so I am still
puzzled.
--
John Carson
Abdo Haji-Ali
2006-08-29 13:33:50 UTC
Permalink
Post by John Carson
I note, however, that Comeau online compiles
float f (1.0f/0.0f);
without complaint.
On the other hand, it issues a warning for
float f(1/0);
So is Comeau non-conformant, or is something being missed here?
The behavior is *undefined* the compiler can do whatever it wants... It can
give a warning, an error or just let it through; nothing can be
guaranteed.... In this case Comeau gives a warning about integer division by
zero because it probably issues an exception, while it doesn't give anything
for float division by zero, because it's *likely* doesn't cause one. I'm not
saying this is right or wrong in any sense; it's the compiler call to do
whatever it can live with :)
Post by John Carson
You refer to the standard but seem to have merged some passages. The 2003
<snip>
However, this section still stands...



"If during the evaluation of an expression, the result is not mathematically
defined or not in the range of representable
values for its type, the behavior is undefined"



1.0/0.0 is not mathematically defined so the behavior is *undefined*
--
Abdo Haji-Ali
Programmer
In|Framez
John Carson
2006-08-29 14:36:39 UTC
Permalink
Post by Abdo Haji-Ali
Post by John Carson
I note, however, that Comeau online compiles
float f (1.0f/0.0f);
without complaint.
On the other hand, it issues a warning for
float f(1/0);
So is Comeau non-conformant, or is something being missed here?
The behavior is *undefined* the compiler can do whatever it wants...
It can give a warning, an error or just let it through; nothing can be
guaranteed....
Not on my reading of the Standard. See my reply to Victor.
Post by Abdo Haji-Ali
<snip>
However, this section still stands...
"If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable
values for its type, the behavior is undefined"
1.0/0.0 is not mathematically defined so the behavior is *undefined*
By the C++ standard, yes. However, a particular implementation might
document what happens. From section 1.3.12 of the Standard:

"permissible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation or
program execution in a documented manner characteristic of the environment
(with or without the issuance of a diagnostic message), to terminating a
translation or execution (with the issuance of a diagnostic message)."

Note the "program execution in a documented manner" possibility.
--
John Carson
Abdo Haji-Ali
2006-08-29 16:01:54 UTC
Permalink
Post by John Carson
Post by Abdo Haji-Ali
Post by John Carson
I note, however, that Comeau online compiles
float f (1.0f/0.0f);
without complaint.
On the other hand, it issues a warning for
float f(1/0);
So is Comeau non-conformant, or is something being missed here?
The behavior is *undefined* the compiler can do whatever it wants...
It can give a warning, an error or just let it through; nothing can be
guaranteed....
Not on my reading of the Standard. See my reply to Victor.
Post by Abdo Haji-Ali
<snip>
However, this section still stands...
"If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable
values for its type, the behavior is undefined"
1.0/0.0 is not mathematically defined so the behavior is *undefined*
By the C++ standard, yes. However, a particular implementation might
"permissible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation or
program execution in a documented manner characteristic of the environment
(with or without the issuance of a diagnostic message), to terminating a
translation or execution (with the issuance of a diagnostic message)."
Note the "program execution in a documented manner" possibility.
Ehem... Also note the "terminating a translation" possibility.
--
Abdo Haji-Ali
Programmer
In|Framez
John Carson
2006-08-29 15:24:01 UTC
Permalink
Post by Abdo Haji-Ali
Post by John Carson
By the C++ standard, yes. However, a particular implementation might
"permissible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during
translation or program execution in a documented manner
characteristic of the environment (with or without the issuance of a
diagnostic message), to terminating a translation or execution (with
the issuance of a diagnostic message)."
Note the "program execution in a documented manner" possibility.
Ehem... Also note the "terminating a translation" possibility.
Excellent point. Amazing how blind I can be when looking at something.
--
John Carson
Victor Bazarov
2006-08-29 12:52:52 UTC
Permalink
[..] By
5.19/3
"An arithmetic constant expression shall satisfy the requirements for
an integral constant expression, except that
- floating literals need not be cast to integral or enumeration type,
- conversions to floating point types are permitted."
Thus 1.0f/0.0f is an "arithmetic constant expression". Is this the
same as a "constant expression" that would make the program
"Other expressions [including arithmetic constant expressions] are
considered constant-expressions only for the purpose of non-local
static object initialization (3.6.2)."
In
int main()
{
float f (1.0f/0.0f);
}
f is not a non-local static object, so 1.0f/0.0f is not a "constant
expression" and therefore the program is *not* ill-formed.
By this reasoning, however,
float f (1.0f/0.0f);
int main()
{
}
is ill-formed. Comeau, however, compiles this program too, so I am
still puzzled.
Compilers have bugs. Undefined behaviour is just that, undefined.
Combine the two and you can have any behaviour either due to compiler
vendor's intent or dispite it, and there is nothing that one could
deduce about code correctness by looking how compilers behave. The
only true sources of information are the Standard and time.

If we think that either VC++ or Comeau C++ misbehave, we need to talk
to the folks who make them. But even then, considering the situation
at hand, you are most likely simply get the response "the behaviour
[of the division by zero] is undefined by the Standard, so we decided
to define it as this..." followed by what you already know, Comeau
lets it slide, VC++ complains.

VC++ is known to be overprotective. I don't know about Comeau in that
regard. It is very likely that if you do get a response from VC++
team, it's going to be one of those "since the 1.f/0.f expression has
undefined behaviour in run-time, we diagnose it for you and protect
you from doing the wrong thing". Then you ask "what about a/b when
b is initialised to 0.f", and you'll hear "well, we're not gods, you
know".

As to the fact that Comeau compiles what seems to be an ill-formed
program, the answer is simple: compilers are allowed to do that. It
might be required to give a diagnostic, but I'm too lazy to find that
out.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
John Carson
2006-08-29 14:30:22 UTC
Permalink
Post by Victor Bazarov
[..] By
5.19/3
"An arithmetic constant expression shall satisfy the requirements for
an integral constant expression, except that
- floating literals need not be cast to integral or enumeration type,
- conversions to floating point types are permitted."
Thus 1.0f/0.0f is an "arithmetic constant expression". Is this the
same as a "constant expression" that would make the program
"Other expressions [including arithmetic constant expressions] are
considered constant-expressions only for the purpose of non-local
static object initialization (3.6.2)."
In
int main()
{
float f (1.0f/0.0f);
}
f is not a non-local static object, so 1.0f/0.0f is not a "constant
expression" and therefore the program is *not* ill-formed.
By this reasoning, however,
float f (1.0f/0.0f);
int main()
{
}
is ill-formed. Comeau, however, compiles this program too, so I am
still puzzled.
Compilers have bugs. Undefined behaviour is just that, undefined.
Combine the two and you can have any behaviour either due to compiler
vendor's intent or dispite it, and there is nothing that one could
deduce about code correctness by looking how compilers behave. The
only true sources of information are the Standard and time.
In principle, yes. In practice, whether Comeau compiles something is
generally a much better indication of whether it is conformant code that
whether, after studying the Standard, I think it is conformant code. I
routinely use Comeau to tell me with at least 99% accuracy whether or not
something is standard compliant.
Post by Victor Bazarov
If we think that either VC++ or Comeau C++ misbehave, we need to talk
to the folks who make them. But even then, considering the situation
at hand, you are most likely simply get the response "the behaviour
[of the division by zero] is undefined by the Standard, so we decided
to define it as this..." followed by what you already know, Comeau
lets it slide, VC++ complains.
VC++ is known to be overprotective. I don't know about Comeau in that
regard. It is very likely that if you do get a response from VC++
team, it's going to be one of those "since the 1.f/0.f expression has
undefined behaviour in run-time, we diagnose it for you and protect
you from doing the wrong thing". Then you ask "what about a/b when
b is initialised to 0.f", and you'll hear "well, we're not gods, you
know".
As to the fact that Comeau compiles what seems to be an ill-formed
program, the answer is simple: compilers are allowed to do that. It
might be required to give a diagnostic, but I'm too lazy to find that
out.
Let me save you the trouble. From section 1.4/1-2 of the standard:

"1. The set of diagnosable rules consists of all syntactic and semantic
rules in this International Standard
except for those rules containing an explicit notation that "no diagnostic
is required" or which are described
as resulting in "undefined behavior."

2. Although this International Standard states only requirements on C++
implementations, those requirements
are often easier to understand if they are phrased as requirements on
programs, parts of programs, or execution
of programs. Such requirements have the following meaning:
- If a program contains no violations of the rules in this International
Standard, a conforming implementation
shall, within its resource limits, accept and correctly execute [fn.
"Correct execution" can include undefined behavior, depending on the data
being processed; see 1.3 and 1.9.] that program.
- If a program contains a violation of any diagnosable rule, a conforming
implementation shall issue at
least one diagnostic message, except that
- If a program contains a violation of a rule for which no diagnostic is
required, this International Standard
places no requirement on implementations with respect to that program."

Thus if it is correct that the program

float f (1.0f/0.0f);
int main()
{
}

is ill-formed, then Comeau is obliged to give a diagnostic. However,
consistent with what I said earlier, I suspect that I have got some subtle
point wrong and the code is *not* ill-formed.

As for VC++, my reading of 1. and the first dashed item under 2. says that
the mere fact that behaviour is undefined does not allow a conforming
implementation to fail to compile it. Since, on my reading

int main()
{
float f (1.0f/0.0f);
}

only involves undefined behaviour and is not ill-formed, VC++ should compile
it.

Of course, I could be wrong.
--
John Carson
Doug Harrison [MVP]
2006-08-29 14:57:11 UTC
Permalink
On Wed, 30 Aug 2006 00:30:22 +1000, "John Carson"
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2. says that
the mere fact that behaviour is undefined does not allow a conforming
implementation to fail to compile it. Since, on my reading
int main()
{
float f (1.0f/0.0f);
}
only involves undefined behaviour and is not ill-formed, VC++ should compile
it.
It isn't required to. See the definition of "undefined behavior" in 1.3.12.
--
Doug Harrison
Visual C++ MVP
John Carson
2006-08-29 15:14:43 UTC
Permalink
Post by Doug Harrison [MVP]
On Wed, 30 Aug 2006 00:30:22 +1000, "John Carson"
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2.
says that the mere fact that behaviour is undefined does not allow a
conforming implementation to fail to compile it. Since, on my reading
int main()
{
float f (1.0f/0.0f);
}
only involves undefined behaviour and is not ill-formed, VC++ should
compile it.
It isn't required to. See the definition of "undefined behavior" in 1.3.12.
Yep, you are right. One possible response to undefined behaviour is:

"terminating a translation or execution (with the issuance of a diagnostic
message)."

I stand corrected.
--
John Carson
Abdo Haji-Ali
2006-08-29 16:07:59 UTC
Permalink
Post by John Carson
In principle, yes. In practice, whether Comeau compiles something is
generally a much better indication of whether it is conformant code that
whether, after studying the Standard, I think it is conformant code. I
routinely use Comeau to tell me with at least 99% accuracy whether or not
something is standard compliant.
Says who? I know that VC isn't as standard-compatible as Comeau (or gcc),
however it doesn't mean that both of them is fully standard-compatible ...
The only thing that is 100% percent compatible with the standard is the the
standard itself...
<snip>
Post by John Carson
float f (1.0f/0.0f);
int main()
{
}
is ill-formed, then Comeau is obliged to give a diagnostic. However,
consistent with what I said earlier, I suspect that I have got some subtle
point wrong and the code is *not* ill-formed.
Or Comeau is not 100% standard-compatible...
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2. says that
the mere fact that behaviour is undefined does not allow a conforming
implementation to fail to compile it. Since, on my reading
only involves undefined behaviour and is not ill-formed, VC++ should compile
it
Read my other reply to you...
Post by John Carson
Of course, I could be wrong.
We all could be :)
--
Abdo Haji-Ali
Programmer
In|Framez
John Carson
2006-08-29 15:25:01 UTC
Permalink
Post by Abdo Haji-Ali
Post by John Carson
In principle, yes. In practice, whether Comeau compiles something is
generally a much better indication of whether it is conformant code
that whether, after studying the Standard, I think it is conformant
code. I routinely use Comeau to tell me with at least 99% accuracy
whether or not something is standard compliant.
Says who?
I think if you trawl through comp.lang.c++, you will find that Comeau comes
out producing the right behaviour with a very high level of consistency. It
certainly gets it right much more often than I do.
Post by Abdo Haji-Ali
I know that VC isn't as standard-compatible as Comeau (or
gcc), however it doesn't mean that both of them is fully
standard-compatible
You mean "either of them"?
Post by Abdo Haji-Ali
... The only thing that is 100% percent
compatible with the standard is the the standard itself...
Which doesn't contradict anything I said.
--
John Carson
Abdo Haji-Ali
2006-08-29 16:36:01 UTC
Permalink
Post by John Carson
Post by Abdo Haji-Ali
Says who?
I think if you trawl through comp.lang.c++, you will find that Comeau comes
out producing the right behaviour with a very high level of consistency. It
certainly gets it right much more often than I do.
I didn't say otherwise. However, I only trust the standard when it comes to
the standard...
Post by John Carson
Post by Abdo Haji-Ali
I know that VC isn't as standard-compatible as Comeau (or
gcc), however it doesn't mean that both of them is fully
standard-compatible
You mean "either of them"?
Ah... Let me see... Oh yes... "Either of them".
Glad you got the point of my sentence :)
Post by John Carson
Post by Abdo Haji-Ali
... The only thing that is 100% percent
compatible with the standard is the the standard itself...
Which doesn't contradict anything I said.
Great
--
Abdo Haji-Ali
Programmer
In|Framez
Tom Widmer [VC++ MVP]
2006-08-29 15:36:54 UTC
Permalink
Post by John Carson
Thus if it is correct that the program
float f (1.0f/0.0f);
int main()
{
}
is ill-formed, then Comeau is obliged to give a diagnostic. However,
consistent with what I said earlier, I suspect that I have got some subtle
point wrong and the code is *not* ill-formed.
From my reading, the code *is* ill-formed, so this appears to be a
(minor) EDG bug.

Tom
Tom Widmer [VC++ MVP]
2006-08-29 15:47:08 UTC
Permalink
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2. says that
the mere fact that behaviour is undefined does not allow a conforming
implementation to fail to compile it. Since, on my reading
int main()
{
float f (1.0f/0.0f);
}
only involves undefined behaviour and is not ill-formed, VC++ should compile
it.
UB allows non-compilation (as you've already noted), but that leads to
this genuine VC++ bug:

int main()
{
if (false)
{
float f (1.0f/0.0f);
}
}

That doesn't compile for me, but doesn't have UB (since the expression
is never evaluated).

1.9/5
"A conforming implementation executing a well-formed program shall
produce the same observable behavior as one of the possible execution
sequences of the corresponding instance of the abstract machine with
the same program and the same input. However, if any such execution
sequence contains an undefined operation, this International Standard
places no requirement on the implementation executing that program"

The program is well-formed, and no execution sequence contains an
undefined operation, so it must compile and execute without error.
Unless I'm wrong of course.

Tom
Abdo Haji-Ali
2006-08-29 16:57:16 UTC
Permalink
Post by Tom Widmer [VC++ MVP]
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2. says that
the mere fact that behaviour is undefined does not allow a conforming
implementation to fail to compile it. Since, on my reading
int main()
{
float f (1.0f/0.0f);
}
only involves undefined behaviour and is not ill-formed, VC++ should compile
it.
UB allows non-compilation (as you've already noted), but that leads to
int main()
{
if (false)
{
float f (1.0f/0.0f);
}
}
That doesn't compile for me, but doesn't have UB (since the expression
is never evaluated).
Did you try release builds? IIRC in debug build every expression is
evaluated even if it never happens...
--
Abdo Haji-Ali
Programmer
In|Framez
Tom Widmer [VC++ MVP]
2006-08-30 11:04:10 UTC
Permalink
Post by Abdo Haji-Ali
Post by Tom Widmer [VC++ MVP]
UB allows non-compilation (as you've already noted), but that leads to
int main()
{
if (false)
{
float f (1.0f/0.0f);
}
}
That doesn't compile for me, but doesn't have UB (since the expression
is never evaluated).
Did you try release builds? IIRC in debug build every expression is
evaluated even if it never happens...
It doesn't compile for debug or release builds using VS2005.

Tom
Alexander Grigoriev
2006-08-30 03:02:49 UTC
Permalink
'f' initialization is never executed at runtime, nevertheless this doesn't
preclude the compiler from evaluating all constant expressions, even in
unreacheable code. I think the compile-time evaluation is done before the
compiler does any code path analysis.
Post by Tom Widmer [VC++ MVP]
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2. says
that the mere fact that behaviour is undefined does not allow a
conforming implementation to fail to compile it. Since, on my reading
int main()
{
float f (1.0f/0.0f);
}
only involves undefined behaviour and is not ill-formed, VC++ should
compile it.
UB allows non-compilation (as you've already noted), but that leads to
int main()
{
if (false)
{
float f (1.0f/0.0f);
}
}
That doesn't compile for me, but doesn't have UB (since the expression is
never evaluated).
1.9/5
"A conforming implementation executing a well-formed program shall produce
the same observable behavior as one of the possible execution sequences of
the corresponding instance of the abstract machine with
the same program and the same input. However, if any such execution
sequence contains an undefined operation, this International Standard
places no requirement on the implementation executing that program"
The program is well-formed, and no execution sequence contains an
undefined operation, so it must compile and execute without error. Unless
I'm wrong of course.
Tom
Tom Widmer [VC++ MVP]
2006-08-30 11:01:35 UTC
Permalink
Post by Alexander Grigoriev
'f' initialization is never executed at runtime, nevertheless this doesn't
preclude the compiler from evaluating all constant expressions, even in
unreacheable code. I think the compile-time evaluation is done before the
compiler does any code path analysis.
If you read the rest of the thread, you'll see that 1.0/0.0 is *not* a
constant-expression. It only becomes one if used to initialize a
non-local variable of static storage duration. Hence, regardless of how
the compiler works, it has to be able to compile and run the code to be
conforming.

Tom
Abdo Haji-Ali
2006-08-30 12:52:17 UTC
Permalink
Post by Tom Widmer [VC++ MVP]
Post by John Carson
As for VC++, my reading of 1. and the first dashed item under 2. says that
the mere fact that behaviour is undefined does not allow a conforming
implementation to fail to compile it. Since, on my reading
int main()
{
float f (1.0f/0.0f);
}
only involves undefined behaviour and is not ill-formed, VC++ should compile
it.
UB allows non-compilation (as you've already noted), but that leads to
int main()
{
if (false)
{
float f (1.0f/0.0f);
}
}
That doesn't compile for me, but doesn't have UB (since the expression
is never evaluated).
1.9/5
"A conforming implementation executing a well-formed program shall
produce the same observable behavior as one of the possible execution
sequences of the corresponding instance of the abstract machine with
the same program and the same input. However, if any such execution
sequence contains an undefined operation, this International Standard
places no requirement on the implementation executing that program"
The program is well-formed, and no execution sequence contains an
undefined operation, so it must compile and execute without error.
Right, however the error is given in the compilation state not the execution
state. And the standard is talking about the execution one
--
Abdo Haji-Ali
Programmer
In|Framez
Tom Widmer [VC++ MVP]
2006-08-30 12:11:49 UTC
Permalink
Post by Abdo Haji-Ali
Post by Sean M. DonCarlos
int main()
{
if (false)
{
float f (1.0f/0.0f);
}
}
The program is well-formed, and no execution sequence contains an
undefined operation, so it must compile and execute without error.
Right, however the error is given in the compilation state not the execution
state. And the standard is talking about the execution one
Could you elaborate what you mean? Do you think my example should
compile and run? If not, why not?

Tom
Alexander Grigoriev
2006-08-30 02:58:49 UTC
Permalink
Behavior is undefined for runtime-evaluated expressions. The standard
explicitly says that if result of a constant expression is not
mathematically defined, the program is malformed.
Post by John Carson
You almost had me convinced. As I understand your argument, the C++
standard leaves the compiler implementer wriggle room (i.e., behaviour is
undefined) in handling mathematically undefined expressions provided they
are not constant expressions. To that extent, the compiler can conform
with IEC 559 with regards to division by zero.
John Carson
2006-08-30 03:27:07 UTC
Permalink
Post by Alexander Grigoriev
Behavior is undefined for runtime-evaluated expressions. The standard
explicitly says that if result of a constant expression is not
mathematically defined, the program is malformed.
Yes, the problem is that 1.0f/0.0f does not appear to be a constant
expression in terms of the Standard unless used for the purpose of non-local
static object initialization.
--
John Carson
Dr Pizza
2006-08-29 19:24:50 UTC
Permalink
Post by Alexander Grigoriev
"If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable values
for its type, the behavior is undefined, unless such an expression is
a constant expression (5.19), in which case the program is illformed.
[Note: most existing implementations of C++ ignore integer overflows.
Treatment of division by zero, forming a remainder using a zero
divisor, and all floating point exceptions vary among machines, and
is usually adjustable by a library function. ]"
An arithmetic constant expression shall have arithmetic or
enumeration type and shall only have operands that are integer
literals (2.13.1), floating literals (2.13.3), enumerators, character
literals (2.13.2) and sizeof expressions (5.3.3). Cast operators in
an arithmetic constant expression shall only convert arithmetic or
enumeration types to arithmetic or enumeration types, except as part
of an operand to the sizeof operator.
This means: 1.f/0.f is a constant expression and the compiler is
evaluating it on compile time. Since it's not mathematically defined
(don't mind it's defined by IEC559), the program is illformed.
What are you talking about? According to the mathematical rules for
floating point numbers (which are NOT the rules for real numbers) the
result is both defined and representable.


--
Abdo Haji-Ali
2006-08-29 20:37:36 UTC
Permalink
Post by Dr Pizza
What are you talking about? According to the mathematical rules for
floating point numbers (which are NOT the rules for real numbers) the
result is both defined and representable.
Agreed... However, C++ standards says that if the expression is not
*mathematically* defined the behavior is undefined
No floating point or IEEE standard is involved in this statement...
--
Abdo Haji-Ali
Programmer
In|Framez
Dr Pizza
2006-08-29 19:56:54 UTC
Permalink
Post by Abdo Haji-Ali
Post by Dr Pizza
What are you talking about? According to the mathematical rules for
floating point numbers (which are NOT the rules for real numbers)
the result is both defined and representable.
Agreed... However, C++ standards says that if the expression is not
*mathematically* defined the behavior is undefined
No floating point or IEEE standard is involved in this statement...
Erm, if that is your interpretation then that part of the standard has
no meaning. There is not one single "mathematics". For example, the
mathematics of integers has different properties from the mathematics
of reals (consider how for example things like division behave
differently with integers as compared to reals). There are a number of
peculiarities to the mathematics used for various types; the
arithmetics for the three kinds basic numeric types (signed integers,
unsigned integers, floating point) are all different.

The domain under consideration here (even if not stated explicitly) is
that of IEEE floating point numbers. And IEEE floating point numbers
have well-defined mathemetical rules that state unequivocally that any
finite number divided by zero is an appropriately signed infinity.

I don't see why any other mathematical system should be considered.
You already concede, surely, that different systems are used for
integers compared to floating point types? Even aside from division by
zero, their behaviour in the face of e.g. division is already very
different.

It is unreasonable to use any system of mathematics when evaluating
these expressions other than the one defined by IEC 559, just as it is
unreasonable to use any system other than modulo integer arithmetic
when considering unsigned integral expressions, or an appropriate
signed arithmetic when considering signed integral expressions.

--
Victor Bazarov
2006-08-29 20:05:26 UTC
Permalink
Post by Dr Pizza
[..]
The domain under consideration here (even if not stated explicitly) is
that of IEEE floating point numbers. And IEEE floating point numbers
have well-defined mathemetical rules that state unequivocally that any
finite number divided by zero is an appropriately signed infinity.
...unless there is a trap... Don't trim or bend the rules to your
convenience. How do you know there is no trap? And if there is a trap,
the result is not defined even in IEC 559.
Post by Dr Pizza
I don't see why any other mathematical system should be considered.
You already concede, surely, that different systems are used for
integers compared to floating point types? Even aside from division
by zero, their behaviour in the face of e.g. division is already very
different.
It is unreasonable to use any system of mathematics when evaluating
these expressions other than the one defined by IEC 559, just as it is
unreasonable to use any system other than modulo integer arithmetic
when considering unsigned integral expressions, or an appropriate
signed arithmetic when considering signed integral expressions.
Why do you keep insisting on mixing up IEC 559 into this? The governing
standard for VC++ is *not* IEC 559, it's ISO 14882, which says that the
behaviour of dividing by zero is undefined.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Dr Pizza
2006-08-30 07:45:54 UTC
Permalink
Post by Victor Bazarov
Post by Dr Pizza
[..]
The domain under consideration here (even if not stated explicitly)
is that of IEEE floating point numbers. And IEEE floating point
numbers have well-defined mathemetical rules that state
unequivocally that any finite number divided by zero is an
appropriately signed infinity.
...unless there is a trap... Don't trim or bend the rules to your
convenience. How do you know there is no trap? And if there is a
trap, the result is not defined even in IEC 559.
OK, or a trap. It doesn't matter. VC++ does neither. It should
support both (with the exact outcome being determined by the mode of
the FP hardware).
Post by Victor Bazarov
Why do you keep insisting on mixing up IEC 559 into this? The
governing standard for VC++ is not IEC 559, it's ISO 14882, which
says that the behaviour of dividing by zero is undefined.
No, the governing standard of floats in VC++ is not ISO 14882. It's
IEC 559. We know it's IEC 559 because is_iec559 is true for floats.
That's what is_iec559 means. That says that the rules for floats are
governed by IEC 559. That's just as well, because the C++ standard
does not otherwise define the behaviour of floats (at least, not to any
extent that would allow us to actually use those floats for
calculation).


--
Abdo Haji-Ali
2006-08-30 12:44:39 UTC
Permalink
Post by Dr Pizza
Erm, if that is your interpretation then that part of the standard has
no meaning. There is not one single "mathematics". For example, the
mathematics of integers has different properties from the mathematics
of reals (consider how for example things like division behave
differently with integers as compared to reals). There are a number of
peculiarities to the mathematics used for various types; the
arithmetics for the three kinds basic numeric types (signed integers,
unsigned integers, floating point) are all different.
Give me the name of the book that says 1.0/0.0 is defined under any
"mathmatics"... It's undefined in every math science
In pure math, 1.0/0.0 is undefined. However, 1.0/n when n tends to 0.0 (n !=
0.0) is infinity
Post by Dr Pizza
The domain under consideration here (even if not stated explicitly) is
that of IEEE floating point numbers. And IEEE floating point numbers
have well-defined mathemetical rules that state unequivocally that any
finite number divided by zero is an appropriately signed infinity.
IEEE is not a math science, it can't define what isn't defined in math, nor
it can put any math rules. IEEE is simply a representation of float numbers
in digital systems
Post by Dr Pizza
It is unreasonable to use any system of mathematics when evaluating
these expressions other than the one defined by IEC 559, just as it is
unreasonable to use any system other than modulo integer arithmetic
when considering unsigned integral expressions, or an appropriate
signed arithmetic when considering signed integral expressions.
is_iec559 is simply a flag that tells you how the *CPU* is treating the
type. It's not a flag from the compiler but from the C++ library. You can't
blame the compiler for its value
--
Abdo Haji-Ali
Programmer
In|Framez
Dr Pizza
2006-08-30 20:02:28 UTC
Permalink
Post by Abdo Haji-Ali
Post by Dr Pizza
Erm, if that is your interpretation then that part of the standard
has no meaning. There is not one single "mathematics". For
example, the mathematics of integers has different properties from
the mathematics of reals (consider how for example things like
division behave differently with integers as compared to reals).
There are a number of peculiarities to the mathematics used for
various types; the arithmetics for the three kinds basic numeric
types (signed integers, unsigned integers, floating point) are all
different.
Give me the name of the book that says 1.0/0.0 is defined under any
"mathmatics"...
It's not a book as such, but IEC 559 clearly states that 1.0 / 0.0 is
defined to be +inf. And IEC 559 governs this situation because
is_iec559 is true for both float and double.
Post by Abdo Haji-Ali
It's undefined in every math science
In pure math, 1.0/0.0 is undefined. However, 1.0/n when n tends to
0.0 (n != 0.0) is infinity
In real arithmetic there's no inexactness of representation either.
Nor is there any concept of overflow or underflow. Reals are dense
unlike floats which are not. In floats, the identity x = x does not
hold true; it does for reals. Yet you accept these peculiar properties
of floats without question.

The mathematics of reals is irrelevant, because floating point numbers
are not real numbers. Floating point numbers are an approximation to
real numbers, and that approximation has different numerical
properties. And those properties are the ones laid out in IEC 559.
Post by Abdo Haji-Ali
IEEE is not a math science, it can't define what isn't defined in
math, nor it can put any math rules. IEEE is simply a representation
of float numbers in digital systems
IEC 559 is not merely a representation. It also describes the
behaviour, as I've already quoted elsewhere in the thread. IEC 559
defines what occurs when a floating point division by zero is performed.
Post by Abdo Haji-Ali
Post by Dr Pizza
It is unreasonable to use any system of mathematics when evaluating
these expressions other than the one defined by IEC 559, just as it
is unreasonable to use any system other than modulo integer
arithmetic when considering unsigned integral expressions, or an
appropriate signed arithmetic when considering signed integral
expressions.
is_iec559 is simply a flag that tells you how the CPU is treating the
type. It's not a flag from the compiler but from the C++ library. You
can't blame the compiler for its value
The compiler ships with the library, and Microsoft bundle them all
together; VC++ is a hosted environment. If the library is lying (i.e.
does not properly describe the environment) then MS's implementation is
faulty. The library and the compiler go together; if you maintain that
the compiler is correct then the library is incorrect and there is
still a problem.


--
Tom Widmer [VC++ MVP]
2006-08-31 12:26:53 UTC
Permalink
Post by Dr Pizza
Post by Abdo Haji-Ali
Post by Dr Pizza
Erm, if that is your interpretation then that part of the standard
has no meaning. There is not one single "mathematics". For
example, the mathematics of integers has different properties from
the mathematics of reals (consider how for example things like
division behave differently with integers as compared to reals).
There are a number of peculiarities to the mathematics used for
various types; the arithmetics for the three kinds basic numeric
types (signed integers, unsigned integers, floating point) are all
different.
Give me the name of the book that says 1.0/0.0 is defined under any
"mathmatics"...
It's not a book as such, but IEC 559 clearly states that 1.0 / 0.0 is
defined to be +inf. And IEC 559 governs this situation because
is_iec559 is true for both float and double.
Actually, IEC 559 makes no such guarantee. 1.0/0.0 produces a division
by zero exception, which may cause a trap depending on whether a trap
handler is set up (which it apparently is in the compiler!). In
addition, IEC 559 does not define how source code maps onto floating
point operations, and nor does the C++ standard for that matter, so
that's really up to the compiler (and indeed, some compilers use
extended precision registers for intermediate operations, etc.).
Post by Dr Pizza
Post by Abdo Haji-Ali
is_iec559 is simply a flag that tells you how the CPU is treating the
type. It's not a flag from the compiler but from the C++ library. You
can't blame the compiler for its value
The compiler ships with the library, and Microsoft bundle them all
together; VC++ is a hosted environment. If the library is lying (i.e.
does not properly describe the environment) then MS's implementation is
faulty. The library and the compiler go together; if you maintain that
the compiler is correct then the library is incorrect and there is
still a problem.
The program:
double d = 1.0/0.0;
int main(){}
is ill-formed according to the standard, regardless of whether
has_infinity or is_iec559 is true or not. If MSVC compiled it without
warning, it would be non-conforming.

Regarding the case where the double isn't a global (and therefore the
initializer isn't a constant-expression), I agree that MS would be
better to define their undefined behaviour as returning +inf, but at
least the error forces you to be explicit, and use infinity() when you
mean it.

Tom
Dr Pizza
2006-09-13 16:42:12 UTC
Permalink
Post by Tom Widmer [VC++ MVP]
Actually, IEC 559 makes no such guarantee. 1.0/0.0 produces a
division by zero exception, which may cause a trap depending on
whether a trap handler is set up (which it apparently is in the
compiler!).
Er, if traps are disabled (which IEC 559 allows) then IEC 559
explicitly guarantees the result. If the compiler has traps enabled
thereby preventing it from compiling programs whose semantics are
well-defined and legal the the compiler is at fault IMO.
Post by Tom Widmer [VC++ MVP]
In addition, IEC 559 does not define how source code maps
onto floating point operations, and nor does the C++ standard for
that matter, so that's really up to the compiler (and indeed, some
compilers use extended precision registers for intermediate
operations, etc.).
The C++ compiler shouldn't trap perfectly sound expressions.
Post by Tom Widmer [VC++ MVP]
Regarding the case where the double isn't a global (and therefore the
initializer isn't a constant-expression), I agree that MS would be
better to define their undefined behaviour as returning +inf, but at
least the error forces you to be explicit, and use infinity() when
you mean it.
1.0 / 0.0 is a perfectly good IEC 559 alternative.


--

Loading...