1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 23 */ 24 /* 25 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #pragma weak __fmod = fmod 30 31 #include "libm.h" 32 33 static const double zero = 0.0; 34 35 /* 36 * The following implementation assumes fast 64-bit integer arith- 37 * metic. This is fine for sparc because we build libm in v8plus 38 * mode. It's also fine for sparcv9 and amd64, although we have 39 * assembly code on amd64. For x86, it would be better to use 40 * 32-bit code, but we have assembly for x86, too. 41 */ 42 double 43 fmod(double x, double y) { 44 double w; 45 long long hx, ix, iy, iz; 46 int nd, k, ny; 47 48 hx = *(long long *)&x; 49 ix = hx & ~0x8000000000000000ull; 50 iy = *(long long *)&y & ~0x8000000000000000ull; 51 52 /* handle special cases */ 53 if (iy == 0ll) 54 return (_SVID_libm_err(x, y, 27)); 55 56 if (ix >= 0x7ff0000000000000ll || iy > 0x7ff0000000000000ll) 57 return ((x * y) * zero); 58 59 if (ix <= iy) 60 return ((ix < iy)? x : x * zero); 61 62 /* 63 * Set: 64 * ny = true exponent of y 65 * nd = true exponent of x minus true exponent of y 66 * ix = normalized significand of x 67 * iy = normalized significand of y 68 */ 69 ny = iy >> 52; 70 k = ix >> 52; 71 if (ny == 0) { 72 /* y is subnormal, x could be normal or subnormal */ 73 ny = 1; 74 while (iy < 0x0010000000000000ll) { 75 ny -= 1; 76 iy += iy; 77 } 78 nd = k - ny; 79 if (k == 0) { 80 nd += 1; 81 while (ix < 0x0010000000000000ll) { 82 nd -= 1; 83 ix += ix; 84 } 85 } else { 86 ix = 0x0010000000000000ll | (ix & 0x000fffffffffffffll); 87 } 88 } else { 89 /* both x and y are normal */ 90 nd = k - ny; 91 ix = 0x0010000000000000ll | (ix & 0x000fffffffffffffll); 92 iy = 0x0010000000000000ll | (iy & 0x000fffffffffffffll); 93 } 94 95 /* perform fixed point mod */ 96 while (nd--) { 97 iz = ix - iy; 98 if (iz >= 0) 99 ix = iz; 100 ix += ix; 101 } 102 iz = ix - iy; 103 if (iz >= 0) 104 ix = iz; 105 106 /* convert back to floating point and restore the sign */ 107 if (ix == 0ll) 108 return (x * zero); 109 while (ix < 0x0010000000000000ll) { 110 ix += ix; 111 ny -= 1; 112 } 113 while (ix > 0x0020000000000000ll) { /* XXX can this ever happen? */ 114 ny += 1; 115 ix >>= 1; 116 } 117 if (ny <= 0) { 118 /* result is subnormal */ 119 k = -ny + 1; 120 ix >>= k; 121 *(long long *)&w = (hx & 0x8000000000000000ull) | ix; 122 return (w); 123 } 124 *(long long *)&w = (hx & 0x8000000000000000ull) | 125 ((long long)ny << 52) | (ix & 0x000fffffffffffffll); 126 return (w); 127 }