diff options
Diffstat (limited to 'usr/src/lib/libbc/libc/gen/common/fmod.c')
-rw-r--r-- | usr/src/lib/libbc/libc/gen/common/fmod.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/usr/src/lib/libbc/libc/gen/common/fmod.c b/usr/src/lib/libbc/libc/gen/common/fmod.c new file mode 100644 index 0000000000..2c071a4ccb --- /dev/null +++ b/usr/src/lib/libbc/libc/gen/common/fmod.c @@ -0,0 +1,163 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License, Version 1.0 only + * (the "License"). You may not use this file except in compliance + * with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +#pragma ident "%Z%%M% %I% %E% SMI" + +/* + * Copyright (c) 1988 by Sun Microsystems, Inc. + */ + +/* Special version adapted from libm for use in libc. */ + +#ifdef i386 +static n0 = 1, n1 = 0; +#else +static n0 = 0, n1 = 1; +#endif + +static double two52 = 4.503599627370496000E+15; +static double twom52 = 2.220446049250313081E-16; + +static double +setexception(n, x) + int n; + double x; +{ +} + +double +copysign(x, y) + double x, y; +{ + long *px = (long *) &x; + long *py = (long *) &y; + px[n0] = (px[n0] & 0x7fffffff) | (py[n0] & 0x80000000); + return x; +} + +static double +fabs(x) + double x; +{ + long *px = (long *) &x; +#ifdef i386 + px[1] &= 0x7fffffff; +#else + px[0] &= 0x7fffffff; +#endif + return x; +} + +static int +finite(x) + double x; +{ + long *px = (long *) &x; + return ((px[n0] & 0x7ff00000) != 0x7ff00000); +} + +static int +ilogb(x) + double x; +{ + long *px = (long *) &x, k; + k = px[n0] & 0x7ff00000; + if (k == 0) { + if ((px[n1] | (px[n0] & 0x7fffffff)) == 0) + return 0x80000001; + else { + x *= two52; + return ((px[n0] & 0x7ff00000) >> 20) - 1075; + } + } else if (k != 0x7ff00000) + return (k >> 20) - 1023; + else + return 0x7fffffff; +} + +static double +scalbn(x, n) + double x; + int n; +{ + long *px = (long *) &x, k; + double twom54 = twom52 * 0.25; + k = (px[n0] & 0x7ff00000) >> 20; + if (k == 0x7ff) + return x + x; + if ((px[n1] | (px[n0] & 0x7fffffff)) == 0) + return x; + if (k == 0) { + x *= two52; + k = ((px[n0] & 0x7ff00000) >> 20) - 52; + } + k = k + n; + if (n > 5000) + return setexception(2, x); + if (n < -5000) + return setexception(1, x); + if (k > 0x7fe) + return setexception(2, x); + if (k <= -54) + return setexception(1, x); + if (k > 0) { + px[n0] = (px[n0] & 0x800fffff) | (k << 20); + return x; + } + k += 54; + px[n0] = (px[n0] & 0x800fffff) | (k << 20); + return x * twom54; +} + +double +fmod(x, y) + double x, y; +{ + int ny, nr; + double r, z, w; +int finite(), ilogb(); +double fabs(), scalbn(), copysign(); + + /* purge off exception values */ + if (!finite(x) || y != y || y == 0.0) { + return (x * y) / (x * y); + } + /* scale and subtract to get the remainder */ + r = fabs(x); + y = fabs(y); + ny = ilogb(y); + while (r >= y) { + nr = ilogb(r); + if (nr == ny) + w = y; + else { + z = scalbn(y, nr - ny - 1); + w = z + z; + } + if (r >= w) + r -= w; + else + r -= z; + } + + /* restore sign */ + return copysign(r, x); +} |