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