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 /* 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma weak __fmod = fmod 32 33 #include "libm.h" 34 35 static const double zero = 0.0; 36 37 /* 38 * The following implementation assumes fast 64-bit integer arith- 39 * metic. This is fine for sparc because we build libm in v8plus 40 * mode. It's also fine for sparcv9 and amd64, although we have 41 * assembly code on amd64. For x86, it would be better to use 42 * 32-bit code, but we have assembly for x86, too. 43 */ 44 double 45 fmod(double x, double y) 46 { 47 double w; 48 long long hx, ix, iy, iz; 49 int nd, k, ny; 50 51 hx = *(long long *)&x; 52 ix = hx & ~0x8000000000000000ull; 53 iy = *(long long *)&y & ~0x8000000000000000ull; 54 55 /* handle special cases */ 56 if (iy == 0ll) 57 return (_SVID_libm_err(x, y, 27)); 58 59 if (ix >= 0x7ff0000000000000ll || iy > 0x7ff0000000000000ll) 60 return ((x * y) * zero); 61 62 if (ix <= iy) 63 return ((ix < iy) ? x : x *zero); 64 65 /* 66 * Set: 67 * ny = true exponent of y 68 * nd = true exponent of x minus true exponent of y 69 * ix = normalized significand of x 70 * iy = normalized significand of y 71 */ 72 ny = iy >> 52; 73 k = ix >> 52; 74 75 if (ny == 0) { 76 /* y is subnormal, x could be normal or subnormal */ 77 ny = 1; 78 79 while (iy < 0x0010000000000000ll) { 80 ny -= 1; 81 iy += iy; 82 } 83 84 nd = k - ny; 85 86 if (k == 0) { 87 nd += 1; 88 89 while (ix < 0x0010000000000000ll) { 90 nd -= 1; 91 ix += ix; 92 } 93 } else { 94 ix = 0x0010000000000000ll | (ix & 0x000fffffffffffffll); 95 } 96 } else { 97 /* both x and y are normal */ 98 nd = k - ny; 99 ix = 0x0010000000000000ll | (ix & 0x000fffffffffffffll); 100 iy = 0x0010000000000000ll | (iy & 0x000fffffffffffffll); 101 } 102 103 /* perform fixed point mod */ 104 while (nd--) { 105 iz = ix - iy; 106 107 if (iz >= 0) 108 ix = iz; 109 110 ix += ix; 111 } 112 113 iz = ix - iy; 114 115 if (iz >= 0) 116 ix = iz; 117 118 /* convert back to floating point and restore the sign */ 119 if (ix == 0ll) 120 return (x * zero); 121 122 while (ix < 0x0010000000000000ll) { 123 ix += ix; 124 ny -= 1; 125 } 126 127 while (ix > 0x0020000000000000ll) { /* XXX can this ever happen? */ 128 ny += 1; 129 ix >>= 1; 130 } 131 132 if (ny <= 0) { 133 /* result is subnormal */ 134 k = -ny + 1; 135 ix >>= k; 136 *(long long *) &w = (hx & 0x8000000000000000ull) | ix; 137 return (w); 138 } 139 140 *(long long *) &w = (hx & 0x8000000000000000ull) | ((long long)ny << 141 52) | (ix & 0x000fffffffffffffll); 142 return (w); 143 }