1 /*
2  * ====================================================
3  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
4  *
5  * Developed at SunPro, a Sun Microsystems, Inc. business.
6  * Permission to use, copy, modify, and distribute this
7  * software is freely granted, provided that this notice
8  * is preserved.
9  * ====================================================
10  */
11 
12 /* __ieee754_remainder(x,p)
13  * Return :
14  * 	returns  x REM p  =  x - [x/p]*p as if in infinite
15  * 	precise arithmetic, where [x/p] is the (infinite bit)
16  *	integer nearest x/p (in half way case choose the even one).
17  * Method :
18  *	Based on fmod() return x-[x/p]chopped*p exactlp.
19  */
20 
21 #include "math.h"
22 #include "math_private.h"
23 
24 static const double zero = 0.0;
25 
__ieee754_remainder(double x,double p)26 double __ieee754_remainder(double x, double p)
27 {
28 	int32_t hx,hp;
29 	u_int32_t sx,lx,lp;
30 	double p_half;
31 
32 	EXTRACT_WORDS(hx,lx,x);
33 	EXTRACT_WORDS(hp,lp,p);
34 	sx = hx&0x80000000;
35 	hp &= 0x7fffffff;
36 	hx &= 0x7fffffff;
37 
38     /* purge off exception values */
39 	if((hp|lp)==0) return (x*p)/(x*p); 	/* p = 0 */
40 	if((hx>=0x7ff00000)||			/* x not finite */
41 	  ((hp>=0x7ff00000)&&			/* p is NaN */
42 	  (((hp-0x7ff00000)|lp)!=0)))
43 	    return (x*p)/(x*p);
44 
45 
46 	if (hp<=0x7fdfffff) x = __ieee754_fmod(x,p+p);	/* now x < 2p */
47 	if (((hx-hp)|(lx-lp))==0) return zero*x;
48 	x  = fabs(x);
49 	p  = fabs(p);
50 	if (hp<0x00200000) {
51 	    if(x+x>p) {
52 		x-=p;
53 		if(x+x>=p) x -= p;
54 	    }
55 	} else {
56 	    p_half = 0.5*p;
57 	    if(x>p_half) {
58 		x-=p;
59 		if(x>=p_half) x -= p;
60 	    }
61 	}
62 	GET_HIGH_WORD(hx,x);
63 	SET_HIGH_WORD(x,hx^sx);
64 	return x;
65 }
66 
67 /*
68  * wrapper remainder(x,p)
69  */
70 #ifndef _IEEE_LIBM
remainder(double x,double y)71 double remainder(double x, double y)
72 {
73 	double z = __ieee754_remainder(x, y);
74 	if (_LIB_VERSION == _IEEE_ || isnan(y))
75 		return z;
76 	if (y == 0.0)
77 		return __kernel_standard(x, y, 28); /* remainder(x,0) */
78 	return z;
79 }
80 strong_alias(remainder, drem)
81 #else
82 strong_alias(__ieee754_remainder, remainder)
83 strong_alias(__ieee754_remainder, drem)
84 #endif
85 libm_hidden_def(remainder)
86