xref: /inferno-os/libkern/frexp-power.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
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	ms;
13  		long	ls;
14  	};
15  } Cheat;
16  
17  double
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
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
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