floating point arithmetic

T

Tim Prince

Ben said:
The same applies to 4.3.3, of course, but I did not want to post a set
of unsurprising results!
I don't find "dodgy" results obtained by options for targets of more
than 8 years ago so surprising either. icc/ia32 got around to making P4
a default target a year ago.
gcc has such a "surprising" default only for i386. I'm equally inclined
to complain to my employer's IT for locking my laptop down to 32-bit
Windows last week as to complain to c.l.c about gcc defaults.
If you want to discuss why a certain compiler has obsolete defaults, if
it is a currently maintained compiler, there should be a more suitable
forum. (e-mail address removed) for example.
 
B

Ben Bacarisse

Tim Prince said:
Ben Bacarisse wrote:
I don't find "dodgy" results obtained by options for targets of more
than 8 years ago so surprising either.

Someone posted because there were surprised (or, to be literal,
puzzled) by the output. That the SSE2 code does what you expect is
interesting but I wanted to show that even a change in optimisation
level can alter the result of the posted code. If I had access to the
hardware, I'd have tried other architectures as well.
icc/ia32 got around to making
P4 a default target a year ago.
gcc has such a "surprising" default only for i386.

Personally, I don't find either the gcc default nor the resulting
output surprising, but there seemed to me to be some value in posting
examples of compiler settings (default or otherwise) that reinforce
the idea that exact comparison of floating values is dangerous.
I'm equally
inclined to complain to my employer's IT for locking my laptop down to
32-bit Windows last week as to complain to c.l.c about gcc defaults.
If you want to discuss why a certain compiler has obsolete defaults,
if it is a currently maintained compiler, there should be a more
suitable forum. (e-mail address removed) for example.

No, my point was all about what one might expect C code to do rather
than what compilers might do by default.
 
B

Ben Bacarisse

Joe Wright said:
Exactly my point, thanks. Optimization shouldn't affect this and so I
think it a gcc bug.

I was all set to say that that makes no difference because of a
general permission to use more precision than required at any time,
but I thought it worth checking and I find (new to me):

5.2.4.2.2 p8:

Except for assignment and cast (which remove all extra range and
precision), the values 8 of operations with floating operands and
values subject to the usual arithmetic conversions and of floating
constants are evaluated to a format whose range and precision may be
greater than required by the type. The use of evaluation formats is
characterized by the implementation-defined value of
FLT_EVAL_METHOD: [followed by the text already quoted by pete]

The first line has a change bar against it in my copy of n1256.pdf.
This means (I think) that some part of that text was changed after
publication. I don't have any other copy to hand so I don't know
exactly what has changed. It seems, anyway, that casts and assignment
are exempted and must remove extra precision.
 
B

Ben Bacarisse

Richard Heathfield said:
Ben Bacarisse said:
5.2.4.2.2 p8:

Except for assignment and cast (which remove all extra range and
precision), the values 8 of operations with floating operands
and values subject to the usual arithmetic conversions and of
floating constants are evaluated to a format whose range and
precision may be greater than required by the type. The use of
evaluation formats is characterized by the
implementation-defined value of FLT_EVAL_METHOD: [followed by
the text already quoted by pete]

The first line has a change bar against it in my copy of
n1256.pdf. This means (I think) that some part of that text was
changed after
publication. I don't have any other copy to hand so I don't know
exactly what has changed. It seems, anyway, that casts and
assignment are exempted and must remove extra precision.

If we compare the above to the original paragraph from ISO/IEC
9899:1999 (note that, in the original, it is actually para7, not
para8), we find that the revision has inserted the words "Except
for assignment and cast (which remove all extra range and
precision)". Otherwise, it is as quoted above.

Thank you. I see now that pete quoted that whole paragraph (I did not
recognise it precisely because of the different number and initial
words).

No -std=c99 was given in any of the examples but it seems to make no
difference. The cast should throw way any extra precision and I think
is not doing so at least with some combinations of compiler options.
 
K

Keith Thompson

pete said:
What is n1256.pdf supposed to be?
Is it a revision of the last standard
or a proposal for the next?

N1256 is a revision of C99, consisting of the text of the C99 standard
with the three Technical Corrigenda merged into it (and I think the
editor snuck in some minor editorial changes while he was at it).
It's a draft, not an "official" document.

There have been two (very) preliminary drafts of the upcoming C201X
standard. I don't have the document numbers handy. The biggest
change is a revamping of the sequence point rules.
 
J

James Kuyper

Keith said:
N1256 is a revision of C99, consisting of the text of the C99 standard
with the three Technical Corrigenda merged into it (and I think the
editor snuck in some minor editorial changes while he was at it).
It's a draft, not an "official" document.

It should be emphasized that all of the source documents for n1256 are
official. The Technical Corrigenda were approved in the form of changes
to be made to the C99 standard, and n1256 is intended only to show what
the standard would look like with those changes made to it. It has the
string "Septermber 7, 2007" at the top of every page of the document. To
the best of my knowledge, in the nearly two years since that date, the
only defect that has been reported against that document in the type
which appears in that date.

It may be unofficial, but by reason of combining all the official
documents together the way they were intended to be, I find it more
useful than any of the official documents.
 
K

Keith Thompson

James Kuyper said:
It should be emphasized that all of the source documents for n1256 are
official. The Technical Corrigenda were approved in the form of
changes to be made to the C99 standard, and n1256 is intended only to
show what the standard would look like with those changes made to
it. It has the string "Septermber 7, 2007" at the top of every page of
the document. To the best of my knowledge, in the nearly two years
since that date, the only defect that has been reported against that
document in the type which appears in that date.

It may be unofficial, but by reason of combining all the official
documents together the way they were intended to be, I find it more
useful than any of the official documents.

Agreed.

Except that by "in the type", I presume you meant "is the typo".
 
M

Mark Dickinson

gcc 4.3.3
-O0               equal,     equal
-O1               not equal, equal
-O1 -ffloat-store equal,     equal
-O0               equal,     equal
-O1               not equal, no equal
[snipped]

gcc 4.5 win32
-O -march=pentium-m -mfpmath-sse        equal,equal

icl 11.1 win32
-prec-div                               equal,equal

SSE2 platforms have been the norm for 8 years, and most compilers have
caught up.

This may have more to do with Windows than with SSE2:
I believe that Windows sets the x87 FPU precision to
53 bits by default, while many other x86 operating
systems (Linux, Solaris, OS X; not FreeBSD) leave
the x87 precision setting at its default of 64 bits.

To check, you can try compiling the following program:
if the division is implemented using SSE2, or using
x87 with 64-bit precision, you'll get a result of
4.9e-324. If it's using x87 with 53-bit precision
you'll get 9.9e-324 (except when the compiler
optimizes away the computation, as e.g., gcc-4.4 -O2
seems to do).

(Example stolen from David Monniaux's 'pitfalls' paper:
http://arxiv.org/pdf/cs/0701192v5
..)

#include <stdio.h>

static double div(double x, double y) {
return x/y;
}

int main(void) {
double x, y, z;
x = 0x1.8000000000001p-1018;
y = 0x1.0000000000001p+56;
z = div(x, y);
printf("z is %.2g\n", z);
return 0;
}
 
J

James Kuyper

Keith said:
....
Except that by "in the type", I presume you meant "is the typo".

It wouldn't be a proper spelling complaint without at least one
misspelling. I'll pretend it was deliberate, to satisfy tradition. :)
 
T

Tim Prince

Mark said:
Ben said:
<snip>
Puzzling.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
double a, b;
if ((a=(double)atoi("1")/atoi("3")) ==
(b=(double)atoi("1")/atoi("3")))
puts("equal");
else
puts("not equal");
if (a == b)
puts("equal");
else
puts("not equal");
return 0;
}
Prints
not equal
equal
gcc 3.1
gcc 4.3.3
-O0 equal, equal
-O1 not equal, equal
-O1 -ffloat-store equal, equal
icc 10.0
-O0 equal, equal
-O1 not equal, no equal
[snipped]
gcc 4.5 win32
-O -march=pentium-m -mfpmath-sse equal,equal

icl 11.1 win32
-prec-div equal,equal

SSE2 platforms have been the norm for 8 years, and most compilers have
caught up.

This may have more to do with Windows than with SSE2:
I believe that Windows sets the x87 FPU precision to
53 bits by default, while many other x86 operating
systems (Linux, Solaris, OS X; not FreeBSD) leave
the x87 precision setting at its default of 64 bits.
You're over-simplifying this. All recent versions of Visual Studio
run-time for 32-bit Windows set 53-bit precision mode during
initialization, but it's possible to run gcc (as I did), where that
doesn't happen.
Windows 64-bit sets 53-bit precision mode before handing over control to
..exe, even if that .exe is built by gcc. However, compilers for X64 use
sse2 by default, so you won't see the "surprising" extra precision.
53-bit precision mode will avoid the so-called "surprising" results for
this example, but not for analogous examples using float data types.
Certain compilers have options to reset to 64-bit precision mode so as
to support long double.
Traditional (pre-89) C used double evaluation of all float expressions,
and many compilers carry on that behavior, for example in the
/fp:precise default compilation mode of MSVC. Standard C doesn't
prohibit that, but it permits the behavior which is considered
"non-surprising" by the originators of this thread.
 
M

Mark Dickinson

Mark said:
Ben Bacarisse wrote:
<snip>
Puzzling.
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   double a, b;
   if ((a=(double)atoi("1")/atoi("3")) ==
       (b=(double)atoi("1")/atoi("3")))
      puts("equal");
   else
      puts("not equal");
   if (a == b)
      puts("equal");
   else
      puts("not equal");
   return 0;
}
Prints
not equal
equal
gcc 3.1
gcc 4.3.3
-O0               equal,     equal
-O1               not equal, equal
-O1 -ffloat-store equal,     equal
icc 10.0
-O0               equal,     equal
-O1               not equal, no equal
[snipped]
gcc 4.5 win32
-O -march=pentium-m -mfpmath-sse        equal,equal
icl 11.1 win32
-prec-div                               equal,equal
SSE2 platforms have been the norm for 8 years, and most compilers have
caught up.
This may have more to do with Windows than with SSE2:
I believe that Windows sets the x87 FPU precision to
53 bits by default, while many other x86 operating
systems (Linux, Solaris, OS X; not FreeBSD) leave
the x87 precision setting at its default of 64 bits.

You're over-simplifying this.  All recent versions of Visual Studio
run-time for 32-bit Windows set 53-bit precision mode during
initialization, but it's possible to run gcc (as I did), where that
doesn't happen.

Ah, yes. I hadn't thought too carefully about exactly when the 53-bit
precision got set. Thanks for the clarification.
Windows 64-bit sets 53-bit precision mode before handing over control to
.exe, even if that .exe is built by gcc.  However, compilers for X64 use
sse2 by default, so you won't see the "surprising" extra precision.
53-bit precision mode will avoid the so-called "surprising" results for
this example, but not for analogous examples using float data types.

And also not for doubles in examples involving underflow or
overflow, since the exponent range of x87+53-bit precision
is still much larger than the exponent range of IEEE 754 doubles.
The sooner the x87 FPU becomes ancient history the better, as
far as I'm concerned. :)
 
L

lawrence.jones

James Kuyper said:
It should be emphasized that all of the source documents for n1256 are
official. The Technical Corrigenda were approved in the form of changes
to be made to the C99 standard, and n1256 is intended only to show what
the standard would look like with those changes made to it. It has the
string "Septermber 7, 2007" at the top of every page of the document. To
the best of my knowledge, in the nearly two years since that date, the
only defect that has been reported against that document in the type
which appears in that date.

Actually, there's one other known defect: the predefined macro
__STDC_MB_MIGHT_NEQ_WC__ should appear in 6.10.8p2 (optional predefined
macros) rather than p1 (required predefined macros).
 
L

lawrence.jones

Mark Dickinson said:
Can someone explain why this behaviour doesn't contravene
C99 5.1.2.3, paragraph 12? "... In particular, casts and
assignments are required to perform their specified
conversion"?

No, because it *does* contravene that clause, as well as the actual
requirements which are specified normatively in 6.3.1. Many compilers
(including gcc in most cases) do not conform to those requirements by
default because most programmers are so clueless about floating point
that the excess precision helps rather than hurts and it avoids the
performance penalty of removing it.
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top