[GHC] #14927: Hyperbolic area sine is unstable for (even moderately) big negative arguments.

GHC ghc-devs at haskell.org
Thu Mar 15 19:25:14 UTC 2018


#14927: Hyperbolic area sine is unstable for (even moderately) big negative
arguments.
-------------------------------------+-------------------------------------
        Reporter:  leftaroundabout   |                Owner:  (none)
            Type:  bug               |               Status:  new
        Priority:  normal            |            Milestone:
       Component:  libraries/base    |              Version:  8.2.1
      Resolution:                    |             Keywords:
Operating System:  Unknown/Multiple  |         Architecture:
 Type of failure:  Incorrect result  |  Unknown/Multiple
  at runtime                         |            Test Case:
      Blocked By:                    |             Blocking:
 Related Tickets:                    |  Differential Rev(s):
       Wiki Page:                    |
-------------------------------------+-------------------------------------

Comment (by leftaroundabout):

 Alternatives to the fix suggestion above:

 - {{{asinh x = signum x * log (abs x + sqrt (1 + x*x))}}}

   More concise form of the same thing; quite possibly faster performance
 because a branch can be avoided.

 - Actually, the Python version has also a higher ''upper'' limit:
   {{{
   Prelude> asinh 1e200               In [3]: asinh(1e200)
   Infinity                           Out[3]: 461.2101657793691
   }}}
  The reason is that `x*x` overflows even though the function as a whole
 could still be well-defined. I consider this not nearly as problematic as
 the much earlier problems I showed for the negative side, but it's still
 not great. This issue can be fixed by noting that for `x > 1/ε²`, we have
 anyways `1 + x*x == x*x` and thus `asinh x` gives the same result as `log
 (2*x) = log 2 + log x`. So, a ''really'' stable area hyperbolic sine would
 be
   {{{
      asinh x
        | x > huge   = log 2 + log x
        | x < 0      = -asinh (-x)
        | otherwise  = log (1 + sqrt (1 + x*x))
   }}}
   with
   {{{
   huge = 1 / last (takeWhile ((>1).(+1)) $ recip . (2^) <$> [0..])
   {-  == 1 / Numeric.IEEE.epsilon -}
   }}}
   Mind, the exact value is completely uncritical, we could as well hard-
 code `huge = 1e20`.

   That implementation accurately left-inverts `sinh` (for `Double`) for
 all the range from `-710` to `710` (in other words, it right-inverts
 `sinh` for all the range from `-1.17e308` to `1.17e308`), which is
 basically the same as in Python. The current implementation only reaches
 up to `sinh 355`.

-- 
Ticket URL: <http://ghc.haskell.org/trac/ghc/ticket/14927#comment:1>
GHC <http://www.haskell.org/ghc/>
The Glasgow Haskell Compiler


More information about the ghc-tickets mailing list