xref: /inferno-os/libkern/frexp-spim.c (revision 4eb166cf184c1f102fb79e31b1465ea3e2021c39)
1 #include <lib9.h>
2 
3 #define	MASK	0x7ffL
4 #define	SHIFT	20
5 #define	BIAS	1022L
6 
7 typedef	union
8 {
9 	double	d;
10 	struct
11 	{
12 		long	ls;
13 		long	ms;
14 	};
15 } Cheat;
16 
17 double
frexp(double d,int * ep)18 frexp(double d, int *ep)
19 {
20 	Cheat x;
21 
22 	if(d == 0) {
23 		*ep = 0;
24 		return 0;
25 	}
26 	x.d = d;
27 	*ep = ((x.ms >> SHIFT) & MASK) - BIAS;
28 	x.ms &= ~(MASK << SHIFT);
29 	x.ms |= BIAS << SHIFT;
30 	return x.d;
31 }
32 
33 double
ldexp(double d,int e)34 ldexp(double d, int e)
35 {
36 	Cheat x;
37 
38 	if(d == 0)
39 		return 0;
40 	x.d = d;
41 	e += (x.ms >> SHIFT) & MASK;
42 	if(e <= 0)
43 		return 0;	/* underflow */
44 	if(e >= MASK){		/* overflow */
45 		if(d < 0)
46 			return Inf(-1);
47 		return Inf(1);
48 	}
49 	x.ms &= ~(MASK << SHIFT);
50 	x.ms |= (long)e << SHIFT;
51 	return x.d;
52 }
53 
54 double
modf(double d,double * ip)55 modf(double d, double *ip)
56 {
57 	Cheat x;
58 	int e;
59 
60 	if(d < 1) {
61 		if(d < 0) {
62 			x.d = modf(-d, ip);
63 			*ip = -*ip;
64 			return -x.d;
65 		}
66 		*ip = 0;
67 		return d;
68 	}
69 	x.d = d;
70 	e = ((x.ms >> SHIFT) & MASK) - BIAS;
71 	if(e <= SHIFT+1) {
72 		x.ms &= ~(0x1fffffL >> e);
73 		x.ls = 0;
74 	} else
75 	if(e <= SHIFT+33)
76 		x.ls &= ~(0x7fffffffL >> (e-SHIFT-2));
77 	*ip = x.d;
78 	return d - x.d;
79 }
80