syscons util remove use kbdcontrol & vidcontrol instead
[unix-history] / lib / msun / src / e_fmod.c
CommitLineData
4acf9396
GCI
1/* @(#)e_fmod.c 5.1 93/09/24 */
2/*
3 * ====================================================
4 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5 *
6 * Developed at SunPro, a Sun Microsystems, Inc. business.
7 * Permission to use, copy, modify, and distribute this
8 * software is freely granted, provided that this notice
9 * is preserved.
10 * ====================================================
11 */
12
13#ifndef lint
14static char rcsid[] = "$Id: e_fmod.c,v 1.4 1994/03/03 17:04:11 jtc Exp $";
15#endif
16
17/*
18 * __ieee754_fmod(x,y)
19 * Return x mod y in exact arithmetic
20 * Method: shift and subtract
21 */
22
23#include "math.h"
24#include <machine/endian.h>
25
26#if BYTE_ORDER == LITTLE_ENDIAN
27#define n0 1
28#define n1 0
29#else
30#define n0 0
31#define n1 1
32#endif
33
34#ifdef __STDC__
35static const double one = 1.0, Zero[] = {0.0, -0.0,};
36#else
37static double one = 1.0, Zero[] = {0.0, -0.0,};
38#endif
39
40#ifdef __STDC__
41 double __ieee754_fmod(double x, double y)
42#else
43 double __ieee754_fmod(x,y)
44 double x,y ;
45#endif
46{
47 int n,hx,hy,hz,ix,iy,sx,i;
48 int *px = (int*)&x, *py = (int*)&y;
49 unsigned lx,ly,lz;
50
51 hx = *( n0 + px); /* high word of x */
52 lx = *( n1 + px); /* low word of x */
53 hy = *( n0 + py); /* high word of y */
54 ly = *( n1 + py); /* low word of y */
55 sx = hx&0x80000000; /* sign of x */
56 hx ^=sx; /* |x| */
57 hy &= 0x7fffffff; /* |y| */
58
59 /* purge off exception values */
60 if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */
61 ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */
62 return (x*y)/(x*y);
63 if(hx<=hy) {
64 if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
65 if(lx==ly)
66 return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/
67 }
68
69 /* determine ix = ilogb(x) */
70 if(hx<0x00100000) { /* subnormal x */
71 if(hx==0) {
72 for (ix = -1043, i=lx; i>0; i<<=1) ix -=1;
73 } else {
74 for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1;
75 }
76 } else ix = (hx>>20)-1023;
77
78 /* determine iy = ilogb(y) */
79 if(hy<0x00100000) { /* subnormal y */
80 if(hy==0) {
81 for (iy = -1043, i=ly; i>0; i<<=1) iy -=1;
82 } else {
83 for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1;
84 }
85 } else iy = (hy>>20)-1023;
86
87 /* set up {hx,lx}, {hy,ly} and align y to x */
88 if(ix >= -1022)
89 hx = 0x00100000|(0x000fffff&hx);
90 else { /* subnormal x, shift x to normal */
91 n = -1022-ix;
92 if(n<=31) {
93 hx = (hx<<n)|(lx>>(32-n));
94 lx <<= n;
95 } else {
96 hx = lx<<(n-32);
97 lx = 0;
98 }
99 }
100 if(iy >= -1022)
101 hy = 0x00100000|(0x000fffff&hy);
102 else { /* subnormal y, shift y to normal */
103 n = -1022-iy;
104 if(n<=31) {
105 hy = (hy<<n)|(ly>>(32-n));
106 ly <<= n;
107 } else {
108 hy = ly<<(n-32);
109 ly = 0;
110 }
111 }
112
113 /* fix point fmod */
114 n = ix - iy;
115 while(n--) {
116 hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
117 if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;}
118 else {
119 if((hz|lz)==0) /* return sign(x)*0 */
120 return Zero[(unsigned)sx>>31];
121 hx = hz+hz+(lz>>31); lx = lz+lz;
122 }
123 }
124 hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
125 if(hz>=0) {hx=hz;lx=lz;}
126
127 /* convert back to floating value and restore the sign */
128 if((hx|lx)==0) /* return sign(x)*0 */
129 return Zero[(unsigned)sx>>31];
130 while(hx<0x00100000) { /* normalize x */
131 hx = hx+hx+(lx>>31); lx = lx+lx;
132 iy -= 1;
133 }
134 if(iy>= -1022) { /* normalize output */
135 hx = ((hx-0x00100000)|((iy+1023)<<20));
136 *(n0+px) = hx|sx;
137 *(n1+px) = lx;
138 } else { /* subnormal output */
139 n = -1022 - iy;
140 if(n<=20) {
141 lx = (lx>>n)|((unsigned)hx<<(32-n));
142 hx >>= n;
143 } else if (n<=31) {
144 lx = (hx<<(32-n))|(lx>>n); hx = sx;
145 } else {
146 lx = hx>>(n-32); hx = sx;
147 }
148 *(n0+px) = hx|sx;
149 *(n1+px) = lx;
150 x *= one; /* create necessary signal */
151 }
152 return x; /* exact output */
153}