NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

standards/46388: pow() behaves inconsistently and not POSIXly correct



>Number:         46388
>Category:       standards
>Synopsis:       pow(1, inf) results in NaN or 1.0 in different situations
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    standards-manager
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Apr 29 14:55:00 +0000 2012
>Originator:     Peter Bex
>Release:        NetBSD 5.0.1_PATCH
>Organization:
N/A
>Environment:
        
        
System: NetBSD frohike.homeunix.org 5.0.1_PATCH NetBSD 5.0.1_PATCH (FROHIKE) 
#0: Tue Aug 11 22:31:56 CEST 2009 
sjamaan%frohike.homeunix.org@localhost:/usr/obj/sys/arch/amd64/compile/FROHIKE 
amd64
Architecture: x86_64
Machine: amd64
>Description:
        The pow() function does not behave like the specification at
        http://pubs.opengroup.org/onlinepubs/9699919799/functions/pow.html
        says it should for infinity (and NaN?) values.

        Worse, gcc seems to optimize calls to pow with constant values away
        and replace it with POSIXly correct values, which means the result
        may differ depending on how the code is structured and possibly also
        on which optimization level is chosen.

        See below for the offending code.

>How-To-Repeat:
        $ cat test.c
        #include <stdio.h>
        #include <math.h>
        int main(void) {
        
                double m1 = 1.0, m2 = -1.0/0.0;
        
                printf("directly: pow(%f, %f) = %lf\n", (double)1.0, 
(double)-1.0/0.0, pow(1.0, -1.0/0.0));
                printf("indirectly: pow(%f, %f) = %lf\n", m1, m2, pow(m1, m2));

                return 0;
        }
        
        $ gcc -lm test.c
        $ ./a.out
        directly: pow(1.000000, -inf) = 1.000000
        indirectly: pow(1.000000, -inf) = nan

        This is obviously inconsistent, and SuS says the second line is
        wrong:

        "For any value of y (including NaN), if x is +1, 1.0 shall be returned."

        Looking at the generated assembly, there's only one call to
        the pow function (and when commenting out the "indirect" line and
        compiling/linking without libm I get no error), so it looks like
        GCC decides to optimize away this call, even though I specified
        no optimization level.

        By the way, the spec also says:
        "If x is -1, and y is ±Inf, 1.0 shall be returned."
        This goes wrong as well:

        directly: pow(-1.000000, -inf) = nan
        indirectly: pow(-1.000000, -inf) = nan


        Looking at the generated assembly, this contains two calls
        to pow().  I don't know why GCC decides not to optimize away
        pow(-1.0, -1.0/0.0) but it does for pow(1.0, -1.0/0.0)....

>Fix:
        No patch since this code is a little above my head, but
        it looks like the problem occurs in src/lib/libm/src/e_pow.c:145

        That line reads
                 return  y - y; /* inf**+-1 is NaN */
        but just above, it says
                if (iy==0x7ff00000) {   /* y is +-inf */
        this means that the comment on line 145 is wrong, and I think the
        returned value is wrong as well because this seems to be the
        branch that's taken for pow(1, -inf).

>Unformatted:
        
        


Home | Main Index | Thread Index | Old Index