473,883 Members | 1,763 Online

Floating Point and Wide Registers

9899:1999 5.1.2.3 Example 4 reads:
"EXAMPLE 4 Implementations employing wide registers have to take care
to honor appropriate semantics. Values are independent of whether they
are represented in a register or in memory. For example, an implicit
spilling of a register is not permitted to alter the value. Also, an
explicit store and load is required to round to the precision of the
storage type. In particular, casts and assignments are required to
perform their specified conversion. For the fragment

double d1, d2;
float f;
d1 = f = expression;
d2 = (float) expression;

the values assigned to d1 and d2 are required to have been converted to
float."

The output of the following program is:

d3 != d1 * d2
d3 != (double) (d1 * d2)
fdim == 0

I expected an output of

d3 != d1 * d2
d3 == (double) (d1 * d2)
fdim == 0

Here is the program:

#include <math.h>
#include <stdio.h>

int main (void) {
double d1, d2, d3;
d1 = 0.1;
d2 = 10.0;
d3 = d1 * d2;

/* First part */
if (d3 == d1 * d2)
puts("d3 == d1 * d2");
else
puts("d3 != d1 * d2");

/* Second part */
if (d3 == (double) (d1 * d2))
puts("d3 == (double) (d1 * d2)");
else
puts("d3 != (double) (d1 * d2)");

/* Third part */
if (fdim(d3, d1 * d2) == 0)
puts("fdim == 0");
else
puts("fdim != 0");

return 0;
}

It was compiled with gcc using -Wall -W -std=c99 -pedantic

I understand the pitfalls of floating point arithmetic and I understand
what is going on here. On my machine (x86) floating point arithmetic
is performed in 80-bit registers and doubles are 64-bits. In the first
example the compiler is computing the result of the multiplication in
an 80-bit register and comparing the result to the double with less
precision. The result is not unexpected because d3 lost some precision
when it was stored into a 64-bit object but the result of the
multiplication did not undergo this loss. I don't have a problem with
this, it is AFAICT Standard conforming.
The part that is unexpected, to me, is the second part where the result
of the multiplication is explicitly cast to double which, according to
my interpretation of the above-quoted Standard verse, requires that the
result is converted to the narrower type of double before the test for
equality if performed. This does not appear to be happening. If I use
the gcc option -ffloat-store the result is as expected but this
shouldn't be required in a Standard-conforming mode.
The result of the last part of the program shows that when the results
of "d1 * d2" is actually converted to a double, it compares equal to
d3.

So my question is: Is my interpretation correct and are the results of
the second two parts guaranteed? If not, where did I go wrong?

Robert Gamble

Aug 21 '06
70 3663

Robert Gamble wrote On 08/22/06 10:52,:
>
The Standard says that the implementation must "document how the choice
is made" which implies that there is a systematic way to determine how
the choice will be made in each instance. If the choice doesn't have
to be consistent there is no point in having implementation defined
behavior at all.
I don't think you can go from "document the choice" to
"document the choice in a systematic way." For one thing,
you've got to define what you mean by "systematic ," which
probably means you've got to enumerate the conditions that
are and are not allowed to influence the choice.

DEATHSTATION 9000 OFFICIAL DOCUMENTATION
(quoted without permission)

When a floating-point result must be rounded, the
Rounding Mode Bit (RMB) is consulted. If the RMB
is clear, the floating-point result is rounded
toward zero. If the RMB is set, the result is
rounded toward infinity.

The RMB is set to zero when the system is shipped
from the factory, and thereafter inverts each time
the on-board detector observes the arrival of an
alpha particle.

All right, it's whimsical -- but doesn't it "document
how the choice is made?" There's a QoI issue, but I don't
think there's a conformance problem.

--
Er*********@sun .com

Aug 22 '06 #31
"Robert Gamble" <rg*******@gmai l.comwrote in message
news:11******** **************@ p79g2000cwp.goo glegroups.com.. .
The Standard says that the implementation must "document how the choice
is made" which implies that there is a systematic way to determine how
the choice will be made in each instance. If the choice doesn't have
to be consistent there is no point in having implementation defined
behavior at all.
The point in having implementation-defined behaviour is to ensure that you
can determine, by reading an implementation' s documentation, whether the
implementation satisfies your requirements.

Aug 22 '06 #32
Robert Gamble wrote:
Richard Bos wrote:
"Robert Gamble" <rg*******@gmai l.comwrote:
....
The number 1 can be exactly represented according to the model
described in 5.2.4.2.2 using any radix (b) since an exponent (e) of
zero must be allowed and b^e is 1 when e is zero. Since a floating
point number must be represented exactly if it can be exactly
represented it is guaranteed that 1 will always be represented exactly
in a floating point number. The same cannot be said for 2.
Yes, it can. 2 is exactly 0.100000e+2 if the base is 2 (or, if you want
the exponent expressed in the base as well, 0.100000e+10), and exactly
0.200000e+1 if the base is anything larger.

How would you represent 2.0 with a radix of 3 in the floating point
model?
As indicated above, 0.200000e+1. In terms of 5.2.4.2.2:

s = +1
b = 3
e = 1
f[1] = 2, all other f[k] = 0

The value give by the formula in 5.2.4.2.2p2 is then

x = +1*3*2*3^-1 == 2.0

For the model defined in 5.2.4.2.2, there do exist values of b, p,
emin, and emax such that 2.0 isn't exactly representable: if e-min is
high enough, 2.0 < DBL_MIN; if e-max were low enough, 2.0 >
DBL_EPSILON*DBL _MAX. but that would require DBL_MIN, and either
DBL_EPSILON or DBL_MAX, to have values inconsistent with
5.2.4.2.2p8-10.

Any implementation where 2.0 was either too large or too small to be
represented exactly would also be pretty unpopular, but that's a QoI
issue.

Aug 22 '06 #33
Robert Gamble wrote:
... Is the following guaranteed:
double d1 = 0.1;
double d2 = d1;
d1 == d2; /* always true? */
I don't think it's guaranteed, even if the declarations were
volatile-qualified (to prevent register caching). However,
it's hard to imagine code in that case that would fail the test.
Aug 22 '06 #34
Robert Gamble wrote:
Since when is an implementation allowed to manifest
implementation-defined behavior in a non-consistent fashion?
The implementation definition could be arbitrarily complicated,
specifying variations based on context (for example).
Aug 22 '06 #35
"Robert Gamble" <rg*******@gmai l.comwrote in message
news:11******** **************@ 74g2000cwt.goog legroups.com...
How would you represent 2.0 with a radix of 3 in the floating point
model?
Others have already explained how this is possible. Perhaps you're thinking
of 0.5? That is indeed inexact in radix 3 floating-point.

Philip

Aug 22 '06 #36
In article <4l************ @individual.net >, Wojtek Lerch
<Wo******@yahoo .cawrites
>Where does the standard say that it must be consistent, or even describe
what "consistent " means in this context? The behaviour is unspecified --
the implementation is free to decide whether to round up or down, separately
for each case. I don't see a requirement that the decision must always be
the same, or that it must be the same for any two constants that have
identical spelling, or identical mathematical value. As long as the
implementati on documents how it makes the decision, the requirement of
"implementatio n-defined" is satisfied.
And in some circumstances it might be preferred to either strictly
alternate up and down or do so randomly
--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
Aug 22 '06 #37
In article <11************ **********@p79g 2000cwp.googleg roups.com>,
Robert Gamble <rg*******@gmai l.comwrites
>The Standard says that the implementation must "document how the choice
is made" which implies that there is a systematic way to determine how
the choice will be made in each instance. If the choice doesn't have
to be consistent there is no point in having implementation defined
behavior at all.
But suppose the implementation states that the rounding will be up and
down dependant on the lsb in a hardware random number generator? That
documents the choice but does not allow the programmer to know what it
is.

--
Francis Glassborow ACCU
Author of 'You Can Do It!' and "You Can Program in C++"
see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects
Aug 22 '06 #38
In comp.std.c Robert Gamble <rg*******@gmai l.comwrote:
>
Thanks for the response. It's unfortunate that gcc doesn't follow the
Standard in this regard
As I recall, *most* of GCC tries to do it right, but the x86 back end
lies about what it can do and thus defeats the best efforts of the rest
of the compiler. I believe GCC on other platforms gets it right.

-Larry Jones

I'm not a vegetarian! I'm a dessertarian. -- Calvin
Aug 22 '06 #39
"Robert Gamble" <rg*******@gmai l.comwrites:
Chris Dollin wrote:
>Robert Gamble wrote:
Douglas A. Gwyn wrote:
Robert Gamble wrote:
The part that is unexpected, to me, is the second part where the result
of the multiplication is explicitly cast to double which, according to
my interpretation of the above-quoted Standard verse, requires that the
result is converted to the narrower type of double before the test for
equality if performed. ...

When the "same" mathematical value is computed twice, the
results need not be the same, so long as each result is one
of the two nearest representable values to the "true" value.
Thus, not even 0.1==0.1 is guaranteed.

Where is this stated? 6.4.4.2p3 states in part:
"For decimal floating constants, and also for hexadecimal floating
constants when FLT_RADIX is not a power of 2, the result is either the
nearest representable value, or the larger or smaller representable
value immediately adjacent to the nearest representable value, chosen
in an implementation-defined manner."

There is similiar language for converting floating point numbers from
other types.

Since when is an implementation allowed to manifest
implementation-defined behavior in a non-consistent fashion?

Could it not, for example, pick the lower value for left operands,
and the upper value for right operands?

That would be consistent. Stupid, perhaps, but consistent. Or
perhaps I mean "predictabl e".

No, the choices are "the larger representable value immediately
adjacent to the nearest representable value" and "the smaller
representable value immediately adjacent to the nearest representable
value"; "Larger for right operands" is not a valid choice. The
implementation needs to choice between which of these behaviors to use
and document it.
The implementation needs to document how the choice is made.

Your reading would forbid different rounding methods for float and
double, which I don't think is the intent.

--
Keith Thompson (The_Other_Keit h) ks***@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <* <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
Aug 22 '06 #40

This thread has been closed and replies have been disabled. Please start a new discussion.