[Haskell-cafe] How odd...
Lennart Augustsson
lennart at augustsson.net
Sat Aug 4 13:21:50 EDT 2007
The Haskell type class RealFloat has a reasonable number of operations to
test for NaN, denormalized numbers, etc.
You can also ask if the implementation uses IEEE.
-- Lennart
On 8/4/07, Paul Johnson <paul at cogito.org.uk> wrote:
>
> Andrew Coppin wrote:
> > Paul Johnson wrote:
> >> > log 0
> >> -Infinity
> > Oh. So... since when does Haskell know about infinity?
> I should have mentioned that the underlying platform in my case is an
> Intel P4. Haskell does not specify a floating point implementation; the
> assumption is that it uses whatever the platform provides because
> anything else would be horribly inefficient. The P4 implements IEEE
> floating point, which as Andrew pointed out includes Infinity, -Infinity
> and NaN as special cases of floating point values. It also seems to
> distinguish between 0.0 and (-0.0), although they are still equal. For
> instance:
>
> > (-0.0)
> -0.0
>
> > 1.0 / 0.0
> Infinity
>
> > 1.0 / (-0.0)
> -Infinity
>
> (Aside: should Infinity etc. be included in the Haskell standard? Or
> possibly in a Data.Numeric.IEEE extension? They look like constructors,
> and it would be nice to be able to pattern match on them.)
>
> So if you tried these experiments on a non-IEEE platform then you would
> get different results. You might get exceptions or just wierd big
> numbers. ISTR someone posted results from a Sun Sparc along these lines
> some time ago.
> > foo x
> > | x < 0 = ...
> > | x == 0 = ...
> > | x > 0 = ...
> > I was most perplexed when I got a "non-exhaustive patterns"
> > exception... It turns out there was a NaN in there. I forget about that.
> Nasty. I'll have to bear that one in mind myself.
>
> You can detect infinities by equality, but not NaN.
>
> > let inf = (1.0 / 0.0)
> > let nan = inf * 0.0
> > inf == inf
> True
> >nan == nan
> False
>
> >> > exp (log 0 * 2)
> >> 0.0
> > Well that's interesting. I did wonder why it *doesn't* break in the
> > real case...
> I haven't perused the IEEE standard, but I expect it defines something
> like this:
>
> Infinity * 0 = NaN
> Infinity * _ = Infinity
> exp Infinity = Infinity
> exp (-Infinity) = 0
> > Um... why would infinity * 0 be NaN? That doesn't make sense...
> Infinity times anything is Infinity. Zero times anything is zero. So
> what should Infinity * zero be? There isn't one right answer. In this
> case the "morally correct" answer is zero, but in other contexts it
> might be Infinity or even some finite number other than zero.
>
> Consider 0.0 / 0.0, which also evaluates to NaN. What should its value
> be? If you take the limit of (x / x) as x -> 0 then the right answer is
> 0. On the other hand if you take the limit of (0 / x) as x -> 0 then
> the right answer is infinity. Worse yet, if you take the limit of (2x /
> x) as x-> 0 then the right answer is 2. You can pick any finite or
> infinite value you like. So the only possible answer is NaN.
> >
> >> So no, its not a bug, its according to the standard.
> >
> > So I'm the only person who was expecting zero squared to be zero?
> > (IMHO the standard should try to implement mathematical operations in
> > a mathematically sensible way...)
> It does *try*. I'm not sure if IEEE arithmetic was actually defined
> back in 98. It certainly wasn't widely implemented. There might well
> be a case for revisiting the standard to allow for IEEE values, but you
> can't mandate them because not all platforms support IEEE arithmetic.
> >> While working through this I also came across the following case
> >> which technically is a bug:
> >>
> >> > 0 ** 0
> >> 1.0
> >>
> >> > exp (log 0 * 0)
> >> NaN
> >>
> >> I suspect that GHCi is using a built-in exponentiation operator that
> >> doesn't quite conform to the standard in this case.
> >
> > Now that really *is* odd...
> When I said "built in" I meant "built in to the hardware". This is
> probably another special case defined in the IEEE standard, which is not
> the same as the Haskell 98 definition.
>
> The reason why the IEEE standard was defined in the first place was that
> floating point software portability was being seriously limited by these
> corner cases. You would get some numerical code working on a Sun, and
> then find it broke on a PC because one of them defined (0.0 / 0.0) as 1
> and the other defined it as 0. Worse yet, you might find it worked on
> Intel chips but not IBM or AMD. Programmers also had to code explicit
> checks for division by zero and implement their own versions of Infinity
> and NaN in cases where they might appear, which cluttered up the code
> and slowed down execution.
>
> One way out of this morass would be to define Haskell floating point
> arithmetic as IEEE standard, and document non-conformance for certain
> platforms. In the long term that is probably the way forwards (do any
> currently sold chips *not* implement IEEE?). It would also let us
> include Infinity and NaN as constructors. However it would lead to
> significant problems when compiling code that used these values on
> non-IEEE platforms. What do you do then?
>
> Paul.
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20070804/60599f20/attachment-0001.htm
More information about the Haskell-Cafe
mailing list