tech-userlevel archive

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

Re: port-amd64/45391: pow(3) wrong result for x = 0.0 and y < 0



On Mon, Oct 07, 2013 at 05:30:00AM +0000, David Holland wrote:
 >  On Tue, May 15, 2012 at 12:30:05AM +0000, NARUSE, Yui wrote:
 >   >  Hi,
 >   >  
 >   >  I reported a duplicated pr, lib/45755, and attached a patch.
 >   >  But I noticed it is wrong.
 >   >  
 >   >  I show a correct patch as below.
 >   >  It makes related tests pass.
 >  
 >  This has still not been committed; is there any reason I shouldn't
 >  go ahead and commit?

So, it turns out to cause other cases to fail. The following
additional (gross) change is needed to get all the right answers out.

Should I commit this, or revert?

Index: src/w_pow.c
===================================================================
RCS file: /cvsroot/src/lib/libm/src/w_pow.c,v
retrieving revision 1.7
diff -u -p -r1.7 w_pow.c
--- src/w_pow.c	26 May 2002 22:02:02 -0000	1.7
+++ src/w_pow.c	8 Sep 2015 08:25:42 -0000
@@ -43,8 +43,26 @@ pow(double x, double y)	/* wrapper pow *
 	if(x==0.0){
 	    if(y==0.0)
 	        return __kernel_standard(x,y,20); /* pow(0.0,0.0) */
-	    if(finite(y)&&y<0.0)
-	        return __kernel_standard(x,y,23); /* pow(0.0,negative) */
+	    if(finite(y)&&y<0.0) {
+		double z2;
+
+		/*
+		 * -0^even is supposed to generate +HUGE_VAL;
+		 * -0^odd is supposed to generate -HUGE_VAL.
+		 *
+		 * __kernel_standard doesn't know this and yields
+		 * positive HUGE_VAL by default in both cases.
+		 *
+		 * However, __ieee754_pow produces what we want, and
+		 * contains the not-entirely-trivial logic to check if
+		 * y is odd, so if __kernel_standard yields HUGE_VAL
+		 * return the original result instead; that will be
+		 * -HUGE_VAL in the right cases.
+		 */
+		z2 = __kernel_standard(x,y,23); /* pow(0.0,negative) */
+		if (z2 != HUGE_VAL)
+		    return z2;
+	    }
 	    return z;
 	}
 	if(!finite(z)) {
Index: src/w_powf.c
===================================================================
RCS file: /cvsroot/src/lib/libm/src/w_powf.c,v
retrieving revision 1.6
diff -u -p -r1.6 w_powf.c
--- src/w_powf.c	26 May 2002 22:02:02 -0000	1.6
+++ src/w_powf.c	8 Sep 2015 08:25:42 -0000
@@ -46,9 +46,15 @@ powf(float x, float y)	/* wrapper powf *
 	    if(y==(float)0.0)
 	        /* powf(0.0,0.0) */
 	        return (float)__kernel_standard((double)x,(double)y,120);
-	    if(finitef(y)&&y<(float)0.0)
+	    if(finitef(y)&&y<(float)0.0) {
 	        /* powf(0.0,negative) */
-	        return (float)__kernel_standard((double)x,(double)y,123);
+		double z2;
+
+		/* see analogous case in w_pow.c */
+		z2 = __kernel_standard((double)x,(double)y,123);
+		if (z2 != HUGE_VAL)
+		    return (float)z2;
+	    }
 	    return z;
 	}
 	if(!finitef(z)) {


-- 
David A. Holland
dholland%netbsd.org@localhost


Home | Main Index | Thread Index | Old Index