xref: /illumos-gate/usr/src/lib/libm/common/m9x/remquo.c (revision ddc0e0b5)
125c28e83SPiotr Jasiukajtis /*
225c28e83SPiotr Jasiukajtis  * CDDL HEADER START
325c28e83SPiotr Jasiukajtis  *
425c28e83SPiotr Jasiukajtis  * The contents of this file are subject to the terms of the
525c28e83SPiotr Jasiukajtis  * Common Development and Distribution License (the "License").
625c28e83SPiotr Jasiukajtis  * You may not use this file except in compliance with the License.
725c28e83SPiotr Jasiukajtis  *
825c28e83SPiotr Jasiukajtis  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
925c28e83SPiotr Jasiukajtis  * or http://www.opensolaris.org/os/licensing.
1025c28e83SPiotr Jasiukajtis  * See the License for the specific language governing permissions
1125c28e83SPiotr Jasiukajtis  * and limitations under the License.
1225c28e83SPiotr Jasiukajtis  *
1325c28e83SPiotr Jasiukajtis  * When distributing Covered Code, include this CDDL HEADER in each
1425c28e83SPiotr Jasiukajtis  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1525c28e83SPiotr Jasiukajtis  * If applicable, add the following below this CDDL HEADER, with the
1625c28e83SPiotr Jasiukajtis  * fields enclosed by brackets "[]" replaced with your own identifying
1725c28e83SPiotr Jasiukajtis  * information: Portions Copyright [yyyy] [name of copyright owner]
1825c28e83SPiotr Jasiukajtis  *
1925c28e83SPiotr Jasiukajtis  * CDDL HEADER END
2025c28e83SPiotr Jasiukajtis  */
2125c28e83SPiotr Jasiukajtis 
2225c28e83SPiotr Jasiukajtis /*
2325c28e83SPiotr Jasiukajtis  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
2425c28e83SPiotr Jasiukajtis  */
2525c28e83SPiotr Jasiukajtis /*
2625c28e83SPiotr Jasiukajtis  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
2725c28e83SPiotr Jasiukajtis  * Use is subject to license terms.
2825c28e83SPiotr Jasiukajtis  */
2925c28e83SPiotr Jasiukajtis 
30*ddc0e0b5SRichard Lowe #pragma weak __remquo = remquo
3125c28e83SPiotr Jasiukajtis 
3225c28e83SPiotr Jasiukajtis /* INDENT OFF */
3325c28e83SPiotr Jasiukajtis /*
3425c28e83SPiotr Jasiukajtis  * double remquo(double x, double y, int *quo) return remainder(x,y) and an
3525c28e83SPiotr Jasiukajtis  * integer pointer quo such that *quo = N mod {2**31}, where N is the
3625c28e83SPiotr Jasiukajtis  * exact integral part of x/y rounded to nearest even.
3725c28e83SPiotr Jasiukajtis  *
3825c28e83SPiotr Jasiukajtis  * remquo call internal fmodquo
3925c28e83SPiotr Jasiukajtis  */
4025c28e83SPiotr Jasiukajtis /* INDENT ON */
4125c28e83SPiotr Jasiukajtis 
4225c28e83SPiotr Jasiukajtis #include "libm.h"
4325c28e83SPiotr Jasiukajtis #include "libm_protos.h"
4425c28e83SPiotr Jasiukajtis #include <math.h>		/* fabs() */
4525c28e83SPiotr Jasiukajtis #include <sys/isa_defs.h>
4625c28e83SPiotr Jasiukajtis 
4725c28e83SPiotr Jasiukajtis #if defined(_BIG_ENDIAN)
4825c28e83SPiotr Jasiukajtis #define	HIWORD	0
4925c28e83SPiotr Jasiukajtis #define	LOWORD	1
5025c28e83SPiotr Jasiukajtis #else
5125c28e83SPiotr Jasiukajtis #define	HIWORD	1
5225c28e83SPiotr Jasiukajtis #define	LOWORD	0
5325c28e83SPiotr Jasiukajtis #endif
5425c28e83SPiotr Jasiukajtis #define	__HI(x)	((int *) &x)[HIWORD]
5525c28e83SPiotr Jasiukajtis #define	__LO(x)	((int *) &x)[LOWORD]
5625c28e83SPiotr Jasiukajtis 
5725c28e83SPiotr Jasiukajtis static const double one = 1.0, Zero[] = {0.0, -0.0};
5825c28e83SPiotr Jasiukajtis 
5925c28e83SPiotr Jasiukajtis static double
fmodquo(double x,double y,int * quo)6025c28e83SPiotr Jasiukajtis fmodquo(double x, double y, int *quo) {
6125c28e83SPiotr Jasiukajtis 	int n, hx, hy, hz, ix, iy, sx, sq, i, m;
6225c28e83SPiotr Jasiukajtis 	unsigned lx, ly, lz;
6325c28e83SPiotr Jasiukajtis 
6425c28e83SPiotr Jasiukajtis 	hx = __HI(x);		/* high word of x */
6525c28e83SPiotr Jasiukajtis 	lx = __LO(x);		/* low  word of x */
6625c28e83SPiotr Jasiukajtis 	hy = __HI(y);		/* high word of y */
6725c28e83SPiotr Jasiukajtis 	ly = __LO(y);		/* low  word of y */
6825c28e83SPiotr Jasiukajtis 	sx = hx & 0x80000000;	/* sign of x */
6925c28e83SPiotr Jasiukajtis 	sq = (hx ^ hy) & 0x80000000;	/* sign of x/y */
7025c28e83SPiotr Jasiukajtis 	hx ^= sx;		/* |x| */
7125c28e83SPiotr Jasiukajtis 	hy &= 0x7fffffff;	/* |y| */
7225c28e83SPiotr Jasiukajtis 
7325c28e83SPiotr Jasiukajtis 	/* purge off exception values */
7425c28e83SPiotr Jasiukajtis 	*quo = 0;
7525c28e83SPiotr Jasiukajtis 	if ((hy | ly) == 0 || hx >= 0x7ff00000 ||	/* y=0, or x !finite */
7625c28e83SPiotr Jasiukajtis 	    (hy | ((ly | -ly) >> 31)) > 0x7ff00000)	/* or y is NaN */
7725c28e83SPiotr Jasiukajtis 		return ((x * y) / (x * y));
7825c28e83SPiotr Jasiukajtis 	if (hx <= hy) {
7925c28e83SPiotr Jasiukajtis 		if (hx < hy || lx < ly)
8025c28e83SPiotr Jasiukajtis 			return (x);	/* |x|<|y| return x */
8125c28e83SPiotr Jasiukajtis 		if (lx == ly) {
8225c28e83SPiotr Jasiukajtis 			*quo = 1 + (sq >> 30);
8325c28e83SPiotr Jasiukajtis 			/* |x|=|y| return x*0 */
8425c28e83SPiotr Jasiukajtis 			return (Zero[(unsigned) sx >> 31]);
8525c28e83SPiotr Jasiukajtis 		}
8625c28e83SPiotr Jasiukajtis 	}
8725c28e83SPiotr Jasiukajtis 
8825c28e83SPiotr Jasiukajtis 	/* determine ix = ilogb(x) */
8925c28e83SPiotr Jasiukajtis 	if (hx < 0x00100000) {	/* subnormal x */
9025c28e83SPiotr Jasiukajtis 		if (hx == 0) {
9125c28e83SPiotr Jasiukajtis 			for (ix = -1043, i = lx; i > 0; i <<= 1)
9225c28e83SPiotr Jasiukajtis 				ix -= 1;
9325c28e83SPiotr Jasiukajtis 		} else {
9425c28e83SPiotr Jasiukajtis 			for (ix = -1022, i = (hx << 11); i > 0; i <<= 1)
9525c28e83SPiotr Jasiukajtis 				ix -= 1;
9625c28e83SPiotr Jasiukajtis 		}
9725c28e83SPiotr Jasiukajtis 	} else
9825c28e83SPiotr Jasiukajtis 		ix = (hx >> 20) - 1023;
9925c28e83SPiotr Jasiukajtis 
10025c28e83SPiotr Jasiukajtis 	/* determine iy = ilogb(y) */
10125c28e83SPiotr Jasiukajtis 	if (hy < 0x00100000) {	/* subnormal y */
10225c28e83SPiotr Jasiukajtis 		if (hy == 0) {
10325c28e83SPiotr Jasiukajtis 			for (iy = -1043, i = ly; i > 0; i <<= 1)
10425c28e83SPiotr Jasiukajtis 				iy -= 1;
10525c28e83SPiotr Jasiukajtis 		} else {
10625c28e83SPiotr Jasiukajtis 			for (iy = -1022, i = (hy << 11); i > 0; i <<= 1)
10725c28e83SPiotr Jasiukajtis 				iy -= 1;
10825c28e83SPiotr Jasiukajtis 		}
10925c28e83SPiotr Jasiukajtis 	} else
11025c28e83SPiotr Jasiukajtis 		iy = (hy >> 20) - 1023;
11125c28e83SPiotr Jasiukajtis 
11225c28e83SPiotr Jasiukajtis 	/* set up {hx,lx}, {hy,ly} and align y to x */
11325c28e83SPiotr Jasiukajtis 	if (ix >= -1022)
11425c28e83SPiotr Jasiukajtis 		hx = 0x00100000 | (0x000fffff & hx);
11525c28e83SPiotr Jasiukajtis 	else {			/* subnormal x, shift x to normal */
11625c28e83SPiotr Jasiukajtis 		n = -1022 - ix;
11725c28e83SPiotr Jasiukajtis 		if (n <= 31) {
11825c28e83SPiotr Jasiukajtis 			hx = (hx << n) | (lx >> (32 - n));
11925c28e83SPiotr Jasiukajtis 			lx <<= n;
12025c28e83SPiotr Jasiukajtis 		} else {
12125c28e83SPiotr Jasiukajtis 			hx = lx << (n - 32);
12225c28e83SPiotr Jasiukajtis 			lx = 0;
12325c28e83SPiotr Jasiukajtis 		}
12425c28e83SPiotr Jasiukajtis 	}
12525c28e83SPiotr Jasiukajtis 	if (iy >= -1022)
12625c28e83SPiotr Jasiukajtis 		hy = 0x00100000 | (0x000fffff & hy);
12725c28e83SPiotr Jasiukajtis 	else {			/* subnormal y, shift y to normal */
12825c28e83SPiotr Jasiukajtis 		n = -1022 - iy;
12925c28e83SPiotr Jasiukajtis 		if (n <= 31) {
13025c28e83SPiotr Jasiukajtis 			hy = (hy << n) | (ly >> (32 - n));
13125c28e83SPiotr Jasiukajtis 			ly <<= n;
13225c28e83SPiotr Jasiukajtis 		} else {
13325c28e83SPiotr Jasiukajtis 			hy = ly << (n - 32);
13425c28e83SPiotr Jasiukajtis 			ly = 0;
13525c28e83SPiotr Jasiukajtis 		}
13625c28e83SPiotr Jasiukajtis 	}
13725c28e83SPiotr Jasiukajtis 
13825c28e83SPiotr Jasiukajtis 	/* fix point fmod */
13925c28e83SPiotr Jasiukajtis 	n = ix - iy;
14025c28e83SPiotr Jasiukajtis 	m = 0;
14125c28e83SPiotr Jasiukajtis 	while (n--) {
14225c28e83SPiotr Jasiukajtis 		hz = hx - hy;
14325c28e83SPiotr Jasiukajtis 		lz = lx - ly;
14425c28e83SPiotr Jasiukajtis 		if (lx < ly)
14525c28e83SPiotr Jasiukajtis 			hz -= 1;
14625c28e83SPiotr Jasiukajtis 		if (hz < 0) {
14725c28e83SPiotr Jasiukajtis 			hx = hx + hx + (lx >> 31);
14825c28e83SPiotr Jasiukajtis 			lx = lx + lx;
14925c28e83SPiotr Jasiukajtis 		} else {
15025c28e83SPiotr Jasiukajtis 			m += 1;
15125c28e83SPiotr Jasiukajtis 			if ((hz | lz) == 0) {	/* return sign(x)*0 */
15225c28e83SPiotr Jasiukajtis 				if (n < 31)
15325c28e83SPiotr Jasiukajtis 					m <<= 1 + n;
15425c28e83SPiotr Jasiukajtis 				else
15525c28e83SPiotr Jasiukajtis 					m = 0;
15625c28e83SPiotr Jasiukajtis 				m &= 0x7fffffff;
15725c28e83SPiotr Jasiukajtis 				*quo = sq >= 0 ? m : -m;
15825c28e83SPiotr Jasiukajtis 				return (Zero[(unsigned) sx >> 31]);
15925c28e83SPiotr Jasiukajtis 			}
16025c28e83SPiotr Jasiukajtis 			hx = hz + hz + (lz >> 31);
16125c28e83SPiotr Jasiukajtis 			lx = lz + lz;
16225c28e83SPiotr Jasiukajtis 		}
16325c28e83SPiotr Jasiukajtis 		m += m;
16425c28e83SPiotr Jasiukajtis 	}
16525c28e83SPiotr Jasiukajtis 	hz = hx - hy;
16625c28e83SPiotr Jasiukajtis 	lz = lx - ly;
16725c28e83SPiotr Jasiukajtis 	if (lx < ly)
16825c28e83SPiotr Jasiukajtis 		hz -= 1;
16925c28e83SPiotr Jasiukajtis 	if (hz >= 0) {
17025c28e83SPiotr Jasiukajtis 		hx = hz;
17125c28e83SPiotr Jasiukajtis 		lx = lz;
17225c28e83SPiotr Jasiukajtis 		m += 1;
17325c28e83SPiotr Jasiukajtis 	}
17425c28e83SPiotr Jasiukajtis 	m &= 0x7fffffff;
17525c28e83SPiotr Jasiukajtis 	*quo = sq >= 0 ? m : -m;
17625c28e83SPiotr Jasiukajtis 
17725c28e83SPiotr Jasiukajtis 	/* convert back to floating value and restore the sign */
17825c28e83SPiotr Jasiukajtis 	if ((hx | lx) == 0) {	/* return sign(x)*0 */
17925c28e83SPiotr Jasiukajtis 		return (Zero[(unsigned) sx >> 31]);
18025c28e83SPiotr Jasiukajtis 	}
18125c28e83SPiotr Jasiukajtis 	while (hx < 0x00100000) {	/* normalize x */
18225c28e83SPiotr Jasiukajtis 		hx = hx + hx + (lx >> 31);
18325c28e83SPiotr Jasiukajtis 		lx = lx + lx;
18425c28e83SPiotr Jasiukajtis 		iy -= 1;
18525c28e83SPiotr Jasiukajtis 	}
18625c28e83SPiotr Jasiukajtis 	if (iy >= -1022) {	/* normalize output */
18725c28e83SPiotr Jasiukajtis 		hx = (hx - 0x00100000) | ((iy + 1023) << 20);
18825c28e83SPiotr Jasiukajtis 		__HI(x) = hx | sx;
18925c28e83SPiotr Jasiukajtis 		__LO(x) = lx;
19025c28e83SPiotr Jasiukajtis 	} else {			/* subnormal output */
19125c28e83SPiotr Jasiukajtis 		n = -1022 - iy;
19225c28e83SPiotr Jasiukajtis 		if (n <= 20) {
19325c28e83SPiotr Jasiukajtis 			lx = (lx >> n) | ((unsigned) hx << (32 - n));
19425c28e83SPiotr Jasiukajtis 			hx >>= n;
19525c28e83SPiotr Jasiukajtis 		} else if (n <= 31) {
19625c28e83SPiotr Jasiukajtis 			lx = (hx << (32 - n)) | (lx >> n);
19725c28e83SPiotr Jasiukajtis 			hx = sx;
19825c28e83SPiotr Jasiukajtis 		} else {
19925c28e83SPiotr Jasiukajtis 			lx = hx >> (n - 32);
20025c28e83SPiotr Jasiukajtis 			hx = sx;
20125c28e83SPiotr Jasiukajtis 		}
20225c28e83SPiotr Jasiukajtis 		__HI(x) = hx | sx;
20325c28e83SPiotr Jasiukajtis 		__LO(x) = lx;
20425c28e83SPiotr Jasiukajtis 		x *= one;	/* create necessary signal */
20525c28e83SPiotr Jasiukajtis 	}
20625c28e83SPiotr Jasiukajtis 	return (x);		/* exact output */
20725c28e83SPiotr Jasiukajtis }
20825c28e83SPiotr Jasiukajtis 
20925c28e83SPiotr Jasiukajtis #define	zero	Zero[0]
21025c28e83SPiotr Jasiukajtis 
21125c28e83SPiotr Jasiukajtis double
remquo(double x,double y,int * quo)21225c28e83SPiotr Jasiukajtis remquo(double x, double y, int *quo) {
21325c28e83SPiotr Jasiukajtis 	int hx, hy, sx, sq;
21425c28e83SPiotr Jasiukajtis 	double v;
21525c28e83SPiotr Jasiukajtis 	unsigned ly;
21625c28e83SPiotr Jasiukajtis 
21725c28e83SPiotr Jasiukajtis 	hx = __HI(x);		/* high word of x */
21825c28e83SPiotr Jasiukajtis 	hy = __HI(y);		/* high word of y */
21925c28e83SPiotr Jasiukajtis 	ly = __LO(y);		/* low  word of y */
22025c28e83SPiotr Jasiukajtis 	sx = hx & 0x80000000;	/* sign of x */
22125c28e83SPiotr Jasiukajtis 	sq = (hx ^ hy) & 0x80000000;	/* sign of x/y */
22225c28e83SPiotr Jasiukajtis 	hx ^= sx;		/* |x| */
22325c28e83SPiotr Jasiukajtis 	hy &= 0x7fffffff;	/* |y| */
22425c28e83SPiotr Jasiukajtis 
22525c28e83SPiotr Jasiukajtis 	/* purge off exception values */
22625c28e83SPiotr Jasiukajtis 	*quo = 0;
22725c28e83SPiotr Jasiukajtis 	if ((hy | ly) == 0 || hx >= 0x7ff00000 ||	/* y=0, or x !finite */
22825c28e83SPiotr Jasiukajtis 	    (hy | ((ly | -ly) >> 31)) > 0x7ff00000)	/* or y is NaN */
22925c28e83SPiotr Jasiukajtis 		return ((x * y) / (x * y));
23025c28e83SPiotr Jasiukajtis 
23125c28e83SPiotr Jasiukajtis 	y = fabs(y);
23225c28e83SPiotr Jasiukajtis 	x = fabs(x);
23325c28e83SPiotr Jasiukajtis 	if (hy <= 0x7fdfffff) {
23425c28e83SPiotr Jasiukajtis 		x = fmodquo(x, y + y, quo);
23525c28e83SPiotr Jasiukajtis 		*quo = ((*quo) & 0x3fffffff) << 1;
23625c28e83SPiotr Jasiukajtis 	}
23725c28e83SPiotr Jasiukajtis 	if (hy < 0x00200000) {
23825c28e83SPiotr Jasiukajtis 		if (x + x > y) {
23925c28e83SPiotr Jasiukajtis 			*quo += 1;
24025c28e83SPiotr Jasiukajtis 			if (x == y)
24125c28e83SPiotr Jasiukajtis 				x = zero;
24225c28e83SPiotr Jasiukajtis 			else
24325c28e83SPiotr Jasiukajtis 				x -= y;
24425c28e83SPiotr Jasiukajtis 			if (x + x >= y) {
24525c28e83SPiotr Jasiukajtis 				x -= y;
24625c28e83SPiotr Jasiukajtis 				*quo += 1;
24725c28e83SPiotr Jasiukajtis 			}
24825c28e83SPiotr Jasiukajtis 		}
24925c28e83SPiotr Jasiukajtis 	} else {
25025c28e83SPiotr Jasiukajtis 		v = 0.5 * y;
25125c28e83SPiotr Jasiukajtis 		if (x > v) {
25225c28e83SPiotr Jasiukajtis 			*quo += 1;
25325c28e83SPiotr Jasiukajtis 			if (x == y)
25425c28e83SPiotr Jasiukajtis 				x = zero;
25525c28e83SPiotr Jasiukajtis 			else
25625c28e83SPiotr Jasiukajtis 				x -= y;
25725c28e83SPiotr Jasiukajtis 			if (x >= v) {
25825c28e83SPiotr Jasiukajtis 				x -= y;
25925c28e83SPiotr Jasiukajtis 				*quo += 1;
26025c28e83SPiotr Jasiukajtis 			}
26125c28e83SPiotr Jasiukajtis 		}
26225c28e83SPiotr Jasiukajtis 	}
26325c28e83SPiotr Jasiukajtis 	if (sq != 0)
26425c28e83SPiotr Jasiukajtis 		*quo = -(*quo);
26525c28e83SPiotr Jasiukajtis 	return (sx == 0 ? x : -x);
26625c28e83SPiotr Jasiukajtis }
267