From: Gerry Snyder on
Robert Heller wrote:
> At Sat, 05 Sep 2009 08:11:48 -0700 Gerry Snyder <mesmerizerfan(a)gmail.com> wrote:
>
>> Errr,...
>>
>> A math library that says 15 / 3 = 4.999999 or sqrt(10201) = 100.9999999
>> has an error that should be fixed.
>
> You are assuming that the inputs are 15 and 3 (or 10201). If one does a
> long string of fp calculations, it is quite possible to end up with:
>
> 14.999997 / 3 = 4.999999
> or
> sqrt(10200.9999798000) = 100.9999999

The discussion was not about a long string of fp calculations. The
original problem was based on squaring two integers and taking the
square root of the sum. A very different situation.

Yes, I am aware of the dangers of expecting integer results from
floating point math. I was first bitten by them over 45 years ago.

But here I think the 10201 should be exact and its root should be exact.


Gerry
From: Kevin Kenny on
Gerry Snyder wrote:
> But here I think the 10201 should be exact and its root should be exact.

What part of "the bug is in the Microsoft Visual C++ runtime" didn't
you understand?

The C hypot() function is a little bit more complicated than
sqrt(a*a + b*b),
since it's required to take precautions against overflow and underflow
in the intermediate results. The usual calculation (assuming that
a <= b) looks something like:

abs(a) * sqrt(1.0 + (abs(b)/abs(a))**2)

with code around it to avoid divisions by zero and underflows if
a and b are too different in magnitude (including if a is zero,
of course). The imprecision comes from the division of abs(b)/abs(a);
this division can yield a number that cannot be represented exactly.
This approach is taken in Ancient Unix:
http://unix-tree.huihoo.org/V7/usr/src/libm/hypot.c.html
and in the Netlib 'fn' package:
http://www.netlib.org/fn/cabs.f
A similar approach, with Newton-Raphson iteration for sqrt(1 + p)
is due to Moler and Morrison:

http://www.koders.com/c/fid7D3C8841ADC384A5F8DE0D081C88331E3909BF3A.aspx

I suspect, without source diving, that the Microsoft implementation
is similar, since the Ancient Unix, Netlib, and Moler implementations
all get the same result that it does.

The BSD math library has a better implementation, which is hardly
surprising, since it came from Kahan's lab and was written at about
the same time as Kahan was working on the IEEE floating point standard.
Both BSD and glibc return correctly rounded results for our problem
child.

It is clear that the MSVC library (like the Ancient Unix, Netlib and
Moler ones) exhibits less-than-optimal rounding behaviour. It's less
clear whether this is a severe enough problem to justify having the
Tcl maintainers take on the maintenance of an independent implementation
of hypot. As I said, I'm getting tired of carrying around code that
serves no other purpose than to work around platform deficiencies in
the standard C libraries.

--
73 de ke9tv/2, Kevin
From: Jackson on
Try http://docs.sun.com/source/806-3568/ncg_goldberg.html for more
than you ever wanted to know about floating point numbers.

Jackson
From: Donald Arseneau on
On Sep 5, 4:43 am, Robert Heller <hel...(a)deepsoft.com> wrote:
> At Sat, 5 Sep 2009 01:43:14 -0700 (PDT) Donald Arseneau <a...(a)triumf.ca> wrote:

> > On Sep 4, 5:12 pm, Robert Heller <hel...(a)deepsoft.com> wrote:
>
> > > > > why do you think 101 would have an exact representation in binary?
>
> > > > Because it is 1100101 ?
>
> > > That is an integer. It is not a floating point binary fraction.
>
> > Let me turn it around then ... why do you think it doesn't?
>
> > (I *know* it does.)
>
> > Do you think integers are not a subset of fp numbers for
> > some reason?
>
> Sure they are. It is just not always the case that a fp math library
> function will in fact return an integer result.

Then why didn't you say "Are you sure the number you have is exactly
101?"

> I.e. the match function
> is not return 101, it is returning 100.9999999999999 or something like
> that.

Yes, the demonstration was that the hypot function was returning
100.99999999999999 instead of 101. I don't necessarily hold the
view that all built-in mathematical functions must be precise to
the last bit (but it would sure be nice). However it is not helpful
to blur the distinction between what results were calculated and
what numbers are representable.

> to guard bit jitter and round off, etc. One should never assume
> mathenetically exact results and almost *never* should use an equality
> test, even when mathematically called for.

To an extent, what is "mathematically" called for doesn't matter.
Given

expr { 100.0+(1.0/3.0)+(1.0/3.0)+(1.0/3.0) }

the fp result *should be* 100.99999999999999 instead of 101... 101
would
be an *error*!

I will join in encouraging fuzzy comparisons for floating point
numbers,
but am still disappointed that hypot is inexact. (Knowing the floating-
point
hardware in use would clarify the deficiency... most fp processors
today
carry extra precision to eliminate round-off error in the final
answer.)

Donald Arseneau
From: Kevin Kenny on
Donald Arseneau wrote:
> I will join in encouraging fuzzy comparisons for floating point numbers,
> but am still disappointed that hypot is inexact. (Knowing the floating-
> point hardware in use would clarify the deficiency... most fp processors
> today carry extra precision to eliminate round-off error in the final
> answer.)

Reiterating what I've said before:

The hardware is any x86. The library is MS Visual C++ runtime, any
version up to VC2008. As I said before, hypot(a,b) isn't a simple
sqrt(a*a+b*b), because it's required to take precautions against
overflow of the intermediate results. A common na�ve implementation
is

hypot(a,b) = abs(b)*sqrt(1.0+(abs(a)/abs(b))**2)

(assuming without loss of generality that 0 < a <= b.) It's easy to
see where the roundoff problem comes from in the formula above.
The MSVC library has this bug, as do the example hypot implementations
in netlib and in Moler and Morrison. The BSD and glibc implementations
use a somewhat more complex implementation but give errors that are
thought to be <1 ulp in all cases.

Tcl could get around the problem - WHICH IS IN THE MSVC RUNTIME, NOT
IN TCL ITSELF (sorry for shouting, but this thread has gone on too
long) - by carrying around its own implementation of hypot(). The
decision on whether to do so involves balancing the value of having
a bit-precise hypot() function with the cost of the additional work
for the Tcl maintainers.

(My read: Bit-precise floating point *conversions* are worthwhile,
because they restored Everything Is A String. Bit-precise hypot()
is less so. On the other hand, the cost to the maintainers of
answering the ignorant postings in this thread is beginning to
approach the amortized cost of maintaining our own hypot() in
perpetuity.)

--
73 de ke9tv/2, Kevin