Proposal: Add log1p and expm1 to GHC.Float.Floating

John Lato jwlato at gmail.com
Fri Apr 25 00:39:22 UTC 2014


Yes, I realized this after I suggested it.  I don't think it's possible to
preserve higher precision in any meaningful way.


On Thu, Apr 24, 2014 at 8:16 AM, Carter Schonwald <
carter.schonwald at gmail.com> wrote:

> Agreed, (I tried thinking this through myself, Floating doesn't provide
> enough structure to give you any notion of precision)
>
>
> On Thu, Apr 24, 2014 at 10:37 AM, Edward Kmett <ekmett at gmail.com> wrote:
>
>> The idea of a slower more careful default doesn't work. Without
>> ratcheting up the requirements to RealFloat you don't have any notion of
>> precision to play with, and moving it there rules out many important cases
>> like Complex, Quaternion, etc.
>>
>>
>> On Thu, Apr 24, 2014 at 10:17 AM, Casey McCann <cam at uptoisomorphism.net>wrote:
>>
>>> I expect the largest audience involved here are the group that doesn't
>>> know or care about these functions, but definitely wants their code to
>>> work.
>>>
>>> As such, I'm opposed to anything that would break code that doesn't
>>> need the benefits of these functions. Two specific scenarios come to
>>> mind:
>>>
>>> - Floating instances written for DSLs or AST-like types (the only
>>> common example of Floating instances not already mentioned) needing
>>> implementations of functions their author may not have heard of in
>>> order to compile without warnings. This could be mitigated by good
>>> documentation and providing "defaultFoo" functions suitable for
>>> implementations that don't or can't do anything useful with these
>>> functions anyway.
>>>
>>> - Programmers who don't actually need the extra precision using these
>>> functions anyway due to having a vague sense that they're "better".
>>> Yes, in my experience this sort of thing is a common mentality among
>>> programmers. Silently introducing runtime exceptions in this scenario
>>> seems completely unacceptable to my mind and I'm strongly opposed to
>>> any proposal involving that.
>>>
>>> As far as I can see, together these rule out any proposal that would
>>> directly add functions to an existing class unless default
>>> implementations no worse than the status quo (in some sense) are
>>> provided.
>>>
>>> For default implementations, I would prefer the idea suggested earlier
>>> of a (probably slower) algorithm that does preserve precision rather
>>> than a naive version, if that's feasible. This lives up to the claimed
>>> benefit of higher precision, and as a general rule I feel that any
>>> pitfalls left for the unwary should at worst provide the correct
>>> result more slowly.
>>>
>>> Also, of all the people who might be impacted by this, I suspect that
>>> the group who really do need both speed and precision for number
>>> crunching are the most likely to know what they're doing and be aware
>>> of potential pitfalls.
>>>
>>> - C.
>>>
>>>
>>>
>>> On Wed, Apr 23, 2014 at 11:55 PM, Edward Kmett <ekmett at gmail.com> wrote:
>>> > Let's try taking a step back here.
>>> >
>>> > There are clearly two different audiences in mind here and that the
>>> > parameters for debate here are too narrow for us to achieve consensus.
>>> >
>>> > Maybe we can try changing the problem a bit and see if we can get
>>> there by
>>> > another avenue.
>>> >
>>> > Your audience would wants a claim that these functions do everything in
>>> > their power to preserve accuracy.
>>> >
>>> > My audience wants to be able to opportunistically grab accuracy without
>>> > leaking it into the type and destroying the usability of their
>>> libraries for
>>> > the broadest set of users.
>>> >
>>> > I essence here it is your audience is the one seeking an extra
>>> > guarantee/law.
>>> >
>>> > Extra guarantees are the sort of thing one often denotes through a
>>> class.
>>> >
>>> > However, putting them in a separate class destroys the utility of this
>>> > proposal for me.
>>> >
>>> > As a straw-man / olive-branch / half-baked idea:
>>> >
>>> > Could we get you what you want by simply making an extra class to
>>> indicate
>>> > the claim that the guarantee holds, and get what I want by placing
>>> these
>>> > methods in the existing Floating with the defaults?
>>> >
>>> > I rather don't like that solution, but I'm just trying to broaden the
>>> scope
>>> > of debate, and at least expose where the fault lines lie in the design
>>> > space, and find a way for us to stop speaking past each other.
>>> >
>>> > -Edward
>>> >
>>> >
>>> > On Wed, Apr 23, 2014 at 11:38 PM, Edward Kmett <ekmett at gmail.com>
>>> wrote:
>>> >>
>>> >> On Wed, Apr 23, 2014 at 8:16 PM, John Lato <jwlato at gmail.com> wrote:
>>> >>>
>>> >>> Ah.  Indeed, that was not what I thought you meant.  But the user
>>> may not
>>> >>> be compiling DodgyFloat; it may be provided via apt/rpm or similar.
>>> >>
>>> >>
>>> >> That is a fair point.
>>> >>
>>> >>>
>>> >>> Could you clarify one other thing?  Do you think that \x -> log (1+x)
>>> >>> behaves the same as log1p?
>>> >>
>>> >>
>>> >> I believe that \x -> log (1 + x) is a passable approximation of log1p
>>> in
>>> >> the absence of a better alternative and that I'd rather have the user
>>> get
>>> >> something no worse than they get today if they refactored their code
>>> to take
>>> >> advantage of the extra capability we are exposing, than just wind up
>>> in a
>>> >> situation where they have to choose between trying to use it because
>>> the
>>> >> types say they should be able to call it and getting unexpected
>>> bottoms they
>>> >> can't protect against, so that the new functionality can't be used in
>>> a way
>>> >> that can be detected at compile time.
>>> >>
>>> >> At this point we're just going around in circles.
>>> >>
>>> >> Under your version of things we put them into a class in a way that
>>> >> everyone has to pay for it, and nobody including me gets to have
>>> enough
>>> >> faith that it won't crash when invoked to actually call it.
>>> >>
>>> >> -Edward
>>> >>
>>> >>>
>>> >>> On Wed, Apr 23, 2014 at 5:08 PM, Edward Kmett <ekmett at gmail.com>
>>> wrote:
>>> >>>>
>>> >>>> I think you may have interpreted me as saying something I didn't
>>> try to
>>> >>>> say.
>>> >>>>
>>> >>>> To clarify, what I was indicating was that during the compilation of
>>> >>>> your 'DodgyFloat' supplying package a bunch of warnings about
>>> unimplemented
>>> >>>> methods would scroll by.
>>> >>>>
>>> >>>> -Edward
>>> >>>>
>>> >>>>
>>> >>>> On Wed, Apr 23, 2014 at 8:06 PM, Edward Kmett <ekmett at gmail.com>
>>> wrote:
>>> >>>>>
>>> >>>>> This does work.
>>> >>>>>
>>> >>>>> MINIMAL is checked based on the definitions supplied locally in the
>>> >>>>> instance, not based on the total definitions that contribute to the
>>> >>>>> instance.
>>> >>>>>
>>> >>>>> Otherwise we couldn't have the very poster-chid example of this
>>> from
>>> >>>>> the documentation for MINIMAL
>>> >>>>>
>>> >>>>> class Eq a where
>>> >>>>>     (==) :: a -> a -> Bool
>>> >>>>>     (/=) :: a -> a -> Bool
>>> >>>>>     x == y = not (x /= y)
>>> >>>>>     x /= y = not (x == y)
>>> >>>>>     {-# MINIMAL (==) | (/=) #-}
>>> >>>>>
>>> >>>>>
>>> >>>>>
>>> >>>>> On Wed, Apr 23, 2014 at 7:57 PM, John Lato <jwlato at gmail.com>
>>> wrote:
>>> >>>>>>
>>> >>>>>> There's one part of this alternative proposal I don't understand:
>>> >>>>>>
>>> >>>>>> On Mon, Apr 21, 2014 at 5:04 AM, Edward Kmett <ekmett at gmail.com>
>>> >>>>>> wrote:
>>> >>>>>>>
>>> >>>>>>>
>>> >>>>>>> * If you can compile sans warnings you have nothing to fear. If
>>> you
>>> >>>>>>> do get warnings, you can know precisely what types will have
>>> degraded back
>>> >>>>>>> to the old precision at compile time, not runtime.
>>> >>>>>>
>>> >>>>>>
>>> >>>>>> I don't understand the mechanism by which this happens (maybe I'm
>>> >>>>>> misunderstanding the MINIMAL pragma?).  If a module has e.g.
>>> >>>>>>
>>> >>>>>> > import DodgyFloat (DodgyFloat) -- defined in a 3rd-party
>>> package,
>>> >>>>>> > doesn't implement log1p etc.
>>> >>>>>> >
>>> >>>>>> > x = log1p 1e-10 :: DodgyFloat
>>> >>>>>>
>>> >>>>>> I don't understand why this would generate a warning (i.e. I don't
>>> >>>>>> believe it will generate a warning).  So the user is in the same
>>> situation
>>> >>>>>> as with the original proposal.
>>> >>>>>>
>>> >>>>>> John L.
>>> >>>>>>
>>> >>>>>>>
>>> >>>>>>> On Mon, Apr 21, 2014 at 5:24 AM, Aleksey Khudyakov
>>> >>>>>>> <alexey.skladnoy at gmail.com> wrote:
>>> >>>>>>>>
>>> >>>>>>>> On 21 April 2014 09:38, John Lato <jwlato at gmail.com> wrote:
>>> >>>>>>>> > I was just wondering, why not simply numerically robust
>>> algorithms
>>> >>>>>>>> > as
>>> >>>>>>>> > defaults for these functions?  No crashes, no errors, no loss
>>> of
>>> >>>>>>>> > precision,
>>> >>>>>>>> > everything would just work.  They aren't particularly
>>> complicated,
>>> >>>>>>>> > so the
>>> >>>>>>>> > performance should even be reasonable.
>>> >>>>>>>> >
>>> >>>>>>>> I think it's best option. log1p and exp1m come with guarantees
>>> >>>>>>>> about precision. log(1+p) default makes it impossible to depend
>>> in
>>> >>>>>>>> such
>>> >>>>>>>> guarantees. They will silenly give wrong answer
>>> >>>>>>>
>>> >>>>>>>
>>> >>>>>>
>>> >>>>>
>>> >>>>
>>> >>>
>>> >>
>>> >
>>> >
>>> > _______________________________________________
>>> > Libraries mailing list
>>> > Libraries at haskell.org
>>> > http://www.haskell.org/mailman/listinfo/libraries
>>> >
>>>
>>
>>
>> _______________________________________________
>> Libraries mailing list
>> Libraries at haskell.org
>> http://www.haskell.org/mailman/listinfo/libraries
>>
>>
>
> _______________________________________________
> Libraries mailing list
> Libraries at haskell.org
> http://www.haskell.org/mailman/listinfo/libraries
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/libraries/attachments/20140424/61b1f2f6/attachment-0001.html>


More information about the Libraries mailing list