Default implementation of Floating (**)

Hi, I was using Numeric.Interval in my code and found an issue with the (**) operator, if the interval contains negative values, it will return a wrong result (as reported in this open issue https://github.com/ekmett/intervals/issues/50). Investigating the source of this problem, I found that it uses the default implementation of (**) from base defined as x ** y = exp (log x * y). So I was wondering, is there any reason to have this (potentially dangerous) default implementation on base? Best, Fabricio Olivetti de França

On Wed, 19 May 2021, Fabrício Olivetti de França wrote:
I was using Numeric.Interval in my code and found an issue with the (**) operator, if the interval contains negative values, it will return a wrong result (as reported in this open issue https://github.com/ekmett/intervals/issues/50).
If you need negative bases you must use (^^) instead of (**).
Investigating the source of this problem, I found that it uses the default implementation of (**) from base defined as x ** y = exp (log x * y).
This default implementation is correct. Power (**) is only defined for positive reals like in mathematics. The example in the GitHub issue will not work if your interval is slightly larger than just the point 2. Think of the interval x=[-2.1,-1.9]. What should x**x be? In contrast to that x^^(-2) would be fine.

On Wed, May 19, 2021 at 11:50:22AM -0300, Fabrício Olivetti de França wrote:
Investigating the source of this problem, I found that it uses the default implementation of (**) from base defined as x ** y = exp (log x * y).
The type of (**) is: Floating a => a -> a -> a with the base and exponent having the same type. The only practical way to define pow(x, y) for a floating point y, is via the exp() and log() functions.
So I was wondering, is there any reason to have this (potentially dangerous) default implementation on base?
The behaviour for negative inputs seems to be correct:
λ> log(-2)
NaN
λ> exp(log(-2))
NaN
λ> exp(log(-2) * (-2))
NaN
λ> log(0)
-Infinity
were you expecting these to check for non-positive inputs and to throw a
floating point exception? When I compile and run:
#include

On Wed, 19 May 2021, Viktor Dukhovni wrote:
On Wed, May 19, 2021 at 11:50:22AM -0300, Fabrício Olivetti de França wrote:
So I was wondering, is there any reason to have this (potentially dangerous) default implementation on base?
The behaviour for negative inputs seems to be correct:
λ> log(-2) NaN λ> exp(log(-2)) NaN λ> exp(log(-2) * (-2)) NaN λ> log(0) -Infinity
were you expecting these to check for non-positive inputs and to throw a floating point exception?
I guess he expects (-2)**(-2) = 1/4. But defined this way, (**) would be rather discontinuous.

nevermind, I was thinking of integer exponents. I should be using (^^) instead.
Thank you all.
Best,
Fabricio Olivetti de França
On Wed, May 19, 2021 at 12:29 PM Henning Thielemann
On Wed, 19 May 2021, Viktor Dukhovni wrote:
On Wed, May 19, 2021 at 11:50:22AM -0300, Fabrício Olivetti de França wrote:
So I was wondering, is there any reason to have this (potentially dangerous) default implementation on base?
The behaviour for negative inputs seems to be correct:
λ> log(-2) NaN λ> exp(log(-2)) NaN λ> exp(log(-2) * (-2)) NaN λ> log(0) -Infinity
were you expecting these to check for non-positive inputs and to throw a floating point exception?
I guess he expects (-2)**(-2) = 1/4.
But defined this way, (**) would be rather discontinuous._______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.

On Wed, May 19, 2021 at 02:08:06PM -0300, Fabrício Olivetti de França wrote:
I guess he expects (-2)**(-2) = 1/4.
But defined this way, (**) would be rather discontinuous
Indeed, that's what I was expecting. For Float and Double (-2)**(-2) = 1/4, but for the interval arithmetic library that uses the default implementation, it doesn't.
This shows the difference between the math library's pow(x, y) and exp(log(x)*y) Indeed pow(x, y) appears to attempt to detect integer-valued floating point exponents and take the interger-exponent code path in that case. -- Viktor.

The issue here, I guess, is that this behavior is inconsistent. While the default implementation for (**) would produce NaNs and such, the implementation for Float and Double overrides this behavior:
(-3 :: Float) ** (-5) -4.115226e-3 (-3 :: Double) ** (-5) -4.11522633744856e-3
Which is in accordance to what other languages such as C and Python do (and also to what I would expect): C float b = -3.0; float e = -5.0; printf("%f\n", powf(b, e)); -0.004115 python
-3.0 ** -5.0 -0.00411522633744856
The Haskell Report is not clear (or at least I was not able to find a clearer explanation) about this: 6.4.3 Exponentiation and Logarithms The one-argument exponential function exp and the logarithm function log act on floating-point numbers and use base e. logBase a x returns the logarithm of x in base a. sqrt returns the principal square root of a floating-point number. There are three two-argument exponentiation operations: (^) raises any number to a nonnegative integer power, (^^) raises a fractional number to any integer power, and (⋆⋆)takes two floating-point arguments. The value of x^0 or x^^0 is 1 for any x, including zero; 0⋆⋆y is 1 if y is 1, and 0 otherwise. Regards, Emilio On Wed, May 19, 2021 at 12:29 PM Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Wed, 19 May 2021, Viktor Dukhovni wrote:
On Wed, May 19, 2021 at 11:50:22AM -0300, Fabrício Olivetti de França wrote:
So I was wondering, is there any reason to have this (potentially dangerous) default implementation on base?
The behaviour for negative inputs seems to be correct:
λ> log(-2) NaN λ> exp(log(-2)) NaN λ> exp(log(-2) * (-2)) NaN λ> log(0) -Infinity
were you expecting these to check for non-positive inputs and to throw a floating point exception?
I guess he expects (-2)**(-2) = 1/4.
But defined this way, (**) would be rather discontinuous._______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (4)
-
Emilio Francesquini
-
Fabrício Olivetti de França
-
Henning Thielemann
-
Viktor Dukhovni