Conflict API definitions of Math.pow(x, 0.5) and Math.sqrt(x) for x={-0.0, Double.NEGATIVE_INFINITY}(Internet mail)

jiefu(傅杰) jiefu at tencent.com
Mon Apr 12 13:39:16 UTC 2021


Hi Raffaello,

Thanks for your execllent analysis.
I agree with you now.
And I'll close the optimization PR [1] tomorrow if there is no objections.

Thanks.
Best regards,
Jie

[1] https://github.com/openjdk/jdk/pull/3404/


On 2021/4/12, 9:06 PM, "Raffaello Giulietti" <raffaello.giulietti at gmail.com> wrote:

    Hi Jie,
    
    I don't think that changing the spec of Math.pow() to be misaligned with 
    IEEE 754 would be a wise option. IEEE is much more pervasive than Java. 
    There are many aspects in IEEE that might be seen as questionable, but 
    at least it is a widely adopted standard.
    
    AFAIU, the only reason you would like to "optimize" the special case of 
    y = 0.5 in pow(x, y) to return sqrt(x) is for performance, more accuracy 
    and some kind of consistency.
    
    But then, why not a special case for y = 0.25 as sqrt(sqrt(x))?
    And what about y = 0.75? Should this be translated to sqrt(sqrt(pow(x, 3)))?
    What about y = 1.0 / 3.0? Should this become cbrt(x)?
    And why not consider y = 2.0 / 3.0 in a special rule: cbrt(x * x)?
    
    You see, the special cases can quickly become unmanageable. Also, 
    special rules would produce results which are "discontinuous" with 
    nearby exponents, like y = 0.5000000000000001.
    
    That's probably why IEEE doesn't propose translation rules for finite 
    numerical exponents that are not integers, except when x is a special value.
    
    
    Greetings
    Raffaello
    
    
    
    On 2021-04-12 13:44, jiefu(傅杰) wrote:
    > Hi Andrew H, Andrew D, and Raffaello,
    > 
    > Thank you all for your kind reply and helpful comments.
    > 
    > Now I got where the rules come from.
    > But I don't think the IEEE standars are reasonable to specify conflits rules.
    > Maybe, these computations should be open to be implementation dependent.
    > 
    > (If it's possible) I really hope the special cases of Math.pow(x, 0.5) can be aligned with Math.sqrt(x) in Java.
    > We already allow some plausible behaviors to be different with the IEEE recommendations for some special cases, right?
    > And in that case, we can replace pow(x, 0.5) with sqrt(x) safely.
    > 
    > Thanks.
    > Best regards,
    > Jie
    > 
    > 
    > On 2021/4/12, 6:40 PM, "Raffaello Giulietti" <raffaello.giulietti at gmail.com> wrote:
    > 
    >      Hi Jie,
    >      
    >      the behavior you report is the one specified by the standard IEEE 754.
    >      Java follows this standard as closely as it can.
    >      
    >      The standard says that
    >      * squareRoot(-0) = -0
    >      * squareRoot(-∞) = NaN
    >      
    >      Also, the standard has a long lists of special cases for pow(x, y),
    >      among them:
    >      * pow(±0, y) is +0 for finite y > 0 and not an odd integer
    >      * pow(-∞, y) is +∞ for finite y > 0 and not an odd integer
    >      
    >      Thus, the conflicts you observe originate in following the standard, not
    >      by special Java rules.
    >      
    >      Unfortunately, the IEEE standard does not explain the reasons for the
    >      special rules. Some are obvious, some are not.
    >      
    >      
    >      HTH
    >      Raffaello
    >      
    >      
    >      > Hi all,
    >      >
    >      > I found Math.pow(x, 0.5) and Math.sqrt(x) would compute different values as the following:
    >      > ```
    >      > Math.pow(-0.0, 0.5) = 0.0
    >      > Math.sqrt(-0.0) = -0.0
    >      >
    >      > Math.pow(Double.NEGATIVE_INFINITY, 0.5) = Infinity
    >      > Math.sqrt(Double.NEGATIVE_INFINITY) = NaN
    >      > ```
    >      >
    >      > The reason is that both of pow and sqrt have special rules for these computations.
    >      > For example, this rule [1] specifies Math.pow(-0.0, 0.5) must be 0.0.
    >      > And this one [2] specifies Math.sqrt(-0.0) must be -0.0.
    >      > And we do have rules for Math.pow(Double.NEGATIVE_INFINITY, 0.5) = Infinity and Math.sqrt(Double.NEGATIVE_INFINITY) = NaN too.
    >      >
    >      > I think most people will be confused by these rules because from the view of mathematics, Math.pow(x, 0.5) should be equal to Math.sqrt(x).
    >      >
    >      > So why Java creates conflict special rules for them?
    >      > Is it possible to let Math.pow(-0.0, 0.5) = -0.0 and Math.pow(Double.NEGATIVE_INFINITY, 0.5) = NaN also be allowed?
    >      >
    >      > I came across this problem when I was trying to optimize pow(x, 0.5) with sqrt(x).
    >      > If pow(x, 0.5)'s two special rules can be aligned with sqrt(x), then pow(x, 0.5)'s performance can be improved by 7x~14x [3].
    >      >
    >      > Thanks.
    >      > Best regards,
    >      > Jie
    >      
    >      
    > 
    
    



More information about the hotspot-compiler-dev mailing list