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 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 2325c28e83SPiotr Jasiukajtis */ 2425c28e83SPiotr Jasiukajtis /* 2525c28e83SPiotr Jasiukajtis * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 2625c28e83SPiotr Jasiukajtis * Use is subject to license terms. 2725c28e83SPiotr Jasiukajtis */ 2825c28e83SPiotr Jasiukajtis 29*ddc0e0b5SRichard Lowe #pragma weak __fmod = fmod 3025c28e83SPiotr Jasiukajtis 3125c28e83SPiotr Jasiukajtis #include "libm.h" 3225c28e83SPiotr Jasiukajtis 3325c28e83SPiotr Jasiukajtis static const double zero = 0.0; 3425c28e83SPiotr Jasiukajtis 3525c28e83SPiotr Jasiukajtis /* 3625c28e83SPiotr Jasiukajtis * The following implementation assumes fast 64-bit integer arith- 3725c28e83SPiotr Jasiukajtis * metic. This is fine for sparc because we build libm in v8plus 3825c28e83SPiotr Jasiukajtis * mode. It's also fine for sparcv9 and amd64, although we have 3925c28e83SPiotr Jasiukajtis * assembly code on amd64. For x86, it would be better to use 4025c28e83SPiotr Jasiukajtis * 32-bit code, but we have assembly for x86, too. 4125c28e83SPiotr Jasiukajtis */ 4225c28e83SPiotr Jasiukajtis double 4325c28e83SPiotr Jasiukajtis fmod(double x, double y) { 4425c28e83SPiotr Jasiukajtis double w; 4525c28e83SPiotr Jasiukajtis long long hx, ix, iy, iz; 4625c28e83SPiotr Jasiukajtis int nd, k, ny; 4725c28e83SPiotr Jasiukajtis 4825c28e83SPiotr Jasiukajtis hx = *(long long *)&x; 4925c28e83SPiotr Jasiukajtis ix = hx & ~0x8000000000000000ull; 5025c28e83SPiotr Jasiukajtis iy = *(long long *)&y & ~0x8000000000000000ull; 5125c28e83SPiotr Jasiukajtis 5225c28e83SPiotr Jasiukajtis /* handle special cases */ 5325c28e83SPiotr Jasiukajtis if (iy == 0ll) 5425c28e83SPiotr Jasiukajtis return (_SVID_libm_err(x, y, 27)); 5525c28e83SPiotr Jasiukajtis 5625c28e83SPiotr Jasiukajtis if (ix >= 0x7ff0000000000000ll || iy > 0x7ff0000000000000ll) 5725c28e83SPiotr Jasiukajtis return ((x * y) * zero); 5825c28e83SPiotr Jasiukajtis 5925c28e83SPiotr Jasiukajtis if (ix <= iy) 6025c28e83SPiotr Jasiukajtis return ((ix < iy)? x : x * zero); 6125c28e83SPiotr Jasiukajtis 6225c28e83SPiotr Jasiukajtis /* 6325c28e83SPiotr Jasiukajtis * Set: 6425c28e83SPiotr Jasiukajtis * ny = true exponent of y 6525c28e83SPiotr Jasiukajtis * nd = true exponent of x minus true exponent of y 6625c28e83SPiotr Jasiukajtis * ix = normalized significand of x 6725c28e83SPiotr Jasiukajtis * iy = normalized significand of y 6825c28e83SPiotr Jasiukajtis */ 6925c28e83SPiotr Jasiukajtis ny = iy >> 52; 7025c28e83SPiotr Jasiukajtis k = ix >> 52; 7125c28e83SPiotr Jasiukajtis if (ny == 0) { 7225c28e83SPiotr Jasiukajtis /* y is subnormal, x could be normal or subnormal */ 7325c28e83SPiotr Jasiukajtis ny = 1; 7425c28e83SPiotr Jasiukajtis while (iy < 0x0010000000000000ll) { 7525c28e83SPiotr Jasiukajtis ny -= 1; 7625c28e83SPiotr Jasiukajtis iy += iy; 7725c28e83SPiotr Jasiukajtis } 7825c28e83SPiotr Jasiukajtis nd = k - ny; 7925c28e83SPiotr Jasiukajtis if (k == 0) { 8025c28e83SPiotr Jasiukajtis nd += 1; 8125c28e83SPiotr Jasiukajtis while (ix < 0x0010000000000000ll) { 8225c28e83SPiotr Jasiukajtis nd -= 1; 8325c28e83SPiotr Jasiukajtis ix += ix; 8425c28e83SPiotr Jasiukajtis } 8525c28e83SPiotr Jasiukajtis } else { 8625c28e83SPiotr Jasiukajtis ix = 0x0010000000000000ll | (ix & 0x000fffffffffffffll); 8725c28e83SPiotr Jasiukajtis } 8825c28e83SPiotr Jasiukajtis } else { 8925c28e83SPiotr Jasiukajtis /* both x and y are normal */ 9025c28e83SPiotr Jasiukajtis nd = k - ny; 9125c28e83SPiotr Jasiukajtis ix = 0x0010000000000000ll | (ix & 0x000fffffffffffffll); 9225c28e83SPiotr Jasiukajtis iy = 0x0010000000000000ll | (iy & 0x000fffffffffffffll); 9325c28e83SPiotr Jasiukajtis } 9425c28e83SPiotr Jasiukajtis 9525c28e83SPiotr Jasiukajtis /* perform fixed point mod */ 9625c28e83SPiotr Jasiukajtis while (nd--) { 9725c28e83SPiotr Jasiukajtis iz = ix - iy; 9825c28e83SPiotr Jasiukajtis if (iz >= 0) 9925c28e83SPiotr Jasiukajtis ix = iz; 10025c28e83SPiotr Jasiukajtis ix += ix; 10125c28e83SPiotr Jasiukajtis } 10225c28e83SPiotr Jasiukajtis iz = ix - iy; 10325c28e83SPiotr Jasiukajtis if (iz >= 0) 10425c28e83SPiotr Jasiukajtis ix = iz; 10525c28e83SPiotr Jasiukajtis 10625c28e83SPiotr Jasiukajtis /* convert back to floating point and restore the sign */ 10725c28e83SPiotr Jasiukajtis if (ix == 0ll) 10825c28e83SPiotr Jasiukajtis return (x * zero); 10925c28e83SPiotr Jasiukajtis while (ix < 0x0010000000000000ll) { 11025c28e83SPiotr Jasiukajtis ix += ix; 11125c28e83SPiotr Jasiukajtis ny -= 1; 11225c28e83SPiotr Jasiukajtis } 11325c28e83SPiotr Jasiukajtis while (ix > 0x0020000000000000ll) { /* XXX can this ever happen? */ 11425c28e83SPiotr Jasiukajtis ny += 1; 11525c28e83SPiotr Jasiukajtis ix >>= 1; 11625c28e83SPiotr Jasiukajtis } 11725c28e83SPiotr Jasiukajtis if (ny <= 0) { 11825c28e83SPiotr Jasiukajtis /* result is subnormal */ 11925c28e83SPiotr Jasiukajtis k = -ny + 1; 12025c28e83SPiotr Jasiukajtis ix >>= k; 12125c28e83SPiotr Jasiukajtis *(long long *)&w = (hx & 0x8000000000000000ull) | ix; 12225c28e83SPiotr Jasiukajtis return (w); 12325c28e83SPiotr Jasiukajtis } 12425c28e83SPiotr Jasiukajtis *(long long *)&w = (hx & 0x8000000000000000ull) | 12525c28e83SPiotr Jasiukajtis ((long long)ny << 52) | (ix & 0x000fffffffffffffll); 12625c28e83SPiotr Jasiukajtis return (w); 12725c28e83SPiotr Jasiukajtis } 128