xref: /plan9-contrib/sys/src/9/vt4/fpi.c (revision d6dfd9ef91cf0fa8514a249d5f2a550978c19369)
1*d6dfd9efSDavid du Colombier /*
2*d6dfd9efSDavid du Colombier  * Floating Point Interpreter.
3*d6dfd9efSDavid du Colombier  * shamelessly stolen from an original by ark.
4*d6dfd9efSDavid du Colombier  */
5*d6dfd9efSDavid du Colombier #include "u.h"
6*d6dfd9efSDavid du Colombier #include "../port/lib.h"
7*d6dfd9efSDavid du Colombier #include "mem.h"
8*d6dfd9efSDavid du Colombier #include "dat.h"
9*d6dfd9efSDavid du Colombier #include "fpi.h"
10*d6dfd9efSDavid du Colombier 
11*d6dfd9efSDavid du Colombier void
fpiround(Internal * i)12*d6dfd9efSDavid du Colombier fpiround(Internal *i)
13*d6dfd9efSDavid du Colombier {
14*d6dfd9efSDavid du Colombier 	unsigned long guard;
15*d6dfd9efSDavid du Colombier 
16*d6dfd9efSDavid du Colombier 	guard = i->l & GuardMask;
17*d6dfd9efSDavid du Colombier 	i->l &= ~GuardMask;
18*d6dfd9efSDavid du Colombier 	if(guard > (LsBit>>1) || (guard == (LsBit>>1) && (i->l & LsBit))){
19*d6dfd9efSDavid du Colombier 		i->l += LsBit;
20*d6dfd9efSDavid du Colombier 		if(i->l & CarryBit){
21*d6dfd9efSDavid du Colombier 			i->l &= ~CarryBit;
22*d6dfd9efSDavid du Colombier 			i->h++;
23*d6dfd9efSDavid du Colombier 			if(i->h & CarryBit){
24*d6dfd9efSDavid du Colombier 				if (i->h & 0x01)
25*d6dfd9efSDavid du Colombier 					i->l |= CarryBit;
26*d6dfd9efSDavid du Colombier 				i->l >>= 1;
27*d6dfd9efSDavid du Colombier 				i->h >>= 1;
28*d6dfd9efSDavid du Colombier 				i->e++;
29*d6dfd9efSDavid du Colombier 			}
30*d6dfd9efSDavid du Colombier 		}
31*d6dfd9efSDavid du Colombier 	}
32*d6dfd9efSDavid du Colombier }
33*d6dfd9efSDavid du Colombier 
34*d6dfd9efSDavid du Colombier static void
matchexponents(Internal * x,Internal * y)35*d6dfd9efSDavid du Colombier matchexponents(Internal *x, Internal *y)
36*d6dfd9efSDavid du Colombier {
37*d6dfd9efSDavid du Colombier 	int count;
38*d6dfd9efSDavid du Colombier 
39*d6dfd9efSDavid du Colombier 	count = y->e - x->e;
40*d6dfd9efSDavid du Colombier 	x->e = y->e;
41*d6dfd9efSDavid du Colombier 	if(count >= 2*FractBits){
42*d6dfd9efSDavid du Colombier 		x->l = x->l || x->h;
43*d6dfd9efSDavid du Colombier 		x->h = 0;
44*d6dfd9efSDavid du Colombier 		return;
45*d6dfd9efSDavid du Colombier 	}
46*d6dfd9efSDavid du Colombier 	if(count >= FractBits){
47*d6dfd9efSDavid du Colombier 		count -= FractBits;
48*d6dfd9efSDavid du Colombier 		x->l = x->h|(x->l != 0);
49*d6dfd9efSDavid du Colombier 		x->h = 0;
50*d6dfd9efSDavid du Colombier 	}
51*d6dfd9efSDavid du Colombier 	while(count > 0){
52*d6dfd9efSDavid du Colombier 		count--;
53*d6dfd9efSDavid du Colombier 		if(x->h & 0x01)
54*d6dfd9efSDavid du Colombier 			x->l |= CarryBit;
55*d6dfd9efSDavid du Colombier 		if(x->l & 0x01)
56*d6dfd9efSDavid du Colombier 			x->l |= 2;
57*d6dfd9efSDavid du Colombier 		x->l >>= 1;
58*d6dfd9efSDavid du Colombier 		x->h >>= 1;
59*d6dfd9efSDavid du Colombier 	}
60*d6dfd9efSDavid du Colombier }
61*d6dfd9efSDavid du Colombier 
62*d6dfd9efSDavid du Colombier static void
shift(Internal * i)63*d6dfd9efSDavid du Colombier shift(Internal *i)
64*d6dfd9efSDavid du Colombier {
65*d6dfd9efSDavid du Colombier 	i->e--;
66*d6dfd9efSDavid du Colombier 	i->h <<= 1;
67*d6dfd9efSDavid du Colombier 	i->l <<= 1;
68*d6dfd9efSDavid du Colombier 	if(i->l & CarryBit){
69*d6dfd9efSDavid du Colombier 		i->l &= ~CarryBit;
70*d6dfd9efSDavid du Colombier 		i->h |= 0x01;
71*d6dfd9efSDavid du Colombier 	}
72*d6dfd9efSDavid du Colombier }
73*d6dfd9efSDavid du Colombier 
74*d6dfd9efSDavid du Colombier static void
normalise(Internal * i)75*d6dfd9efSDavid du Colombier normalise(Internal *i)
76*d6dfd9efSDavid du Colombier {
77*d6dfd9efSDavid du Colombier 	while((i->h & HiddenBit) == 0)
78*d6dfd9efSDavid du Colombier 		shift(i);
79*d6dfd9efSDavid du Colombier }
80*d6dfd9efSDavid du Colombier 
81*d6dfd9efSDavid du Colombier static void
renormalise(Internal * i)82*d6dfd9efSDavid du Colombier renormalise(Internal *i)
83*d6dfd9efSDavid du Colombier {
84*d6dfd9efSDavid du Colombier 	if(i->e < -2 * FractBits)
85*d6dfd9efSDavid du Colombier 		i->e = -2 * FractBits;
86*d6dfd9efSDavid du Colombier 	while(i->e < 1){
87*d6dfd9efSDavid du Colombier 		i->e++;
88*d6dfd9efSDavid du Colombier 		if(i->h & 0x01)
89*d6dfd9efSDavid du Colombier 			i->l |= CarryBit;
90*d6dfd9efSDavid du Colombier 		i->h >>= 1;
91*d6dfd9efSDavid du Colombier 		i->l = (i->l>>1)|(i->l & 0x01);
92*d6dfd9efSDavid du Colombier 	}
93*d6dfd9efSDavid du Colombier 	if(i->e >= ExpInfinity)
94*d6dfd9efSDavid du Colombier 		SetInfinity(i);
95*d6dfd9efSDavid du Colombier }
96*d6dfd9efSDavid du Colombier 
97*d6dfd9efSDavid du Colombier void
fpinormalise(Internal * x)98*d6dfd9efSDavid du Colombier fpinormalise(Internal *x)
99*d6dfd9efSDavid du Colombier {
100*d6dfd9efSDavid du Colombier 	if(!IsWeird(x) && !IsZero(x))
101*d6dfd9efSDavid du Colombier 		normalise(x);
102*d6dfd9efSDavid du Colombier }
103*d6dfd9efSDavid du Colombier 
104*d6dfd9efSDavid du Colombier void
fpiadd(Internal * x,Internal * y,Internal * i)105*d6dfd9efSDavid du Colombier fpiadd(Internal *x, Internal *y, Internal *i)
106*d6dfd9efSDavid du Colombier {
107*d6dfd9efSDavid du Colombier 	Internal *t;
108*d6dfd9efSDavid du Colombier 
109*d6dfd9efSDavid du Colombier 	i->s = x->s;
110*d6dfd9efSDavid du Colombier 	if(IsWeird(x) || IsWeird(y)){
111*d6dfd9efSDavid du Colombier 		if(IsNaN(x) || IsNaN(y))
112*d6dfd9efSDavid du Colombier 			SetQNaN(i);
113*d6dfd9efSDavid du Colombier 		else
114*d6dfd9efSDavid du Colombier 			SetInfinity(i);
115*d6dfd9efSDavid du Colombier 		return;
116*d6dfd9efSDavid du Colombier 	}
117*d6dfd9efSDavid du Colombier 	if(x->e > y->e){
118*d6dfd9efSDavid du Colombier 		t = x;
119*d6dfd9efSDavid du Colombier 		x = y;
120*d6dfd9efSDavid du Colombier 		y = t;
121*d6dfd9efSDavid du Colombier 	}
122*d6dfd9efSDavid du Colombier 	matchexponents(x, y);
123*d6dfd9efSDavid du Colombier 	i->e = x->e;
124*d6dfd9efSDavid du Colombier 	i->h = x->h + y->h;
125*d6dfd9efSDavid du Colombier 	i->l = x->l + y->l;
126*d6dfd9efSDavid du Colombier 	if(i->l & CarryBit){
127*d6dfd9efSDavid du Colombier 		i->h++;
128*d6dfd9efSDavid du Colombier 		i->l &= ~CarryBit;
129*d6dfd9efSDavid du Colombier 	}
130*d6dfd9efSDavid du Colombier 	if(i->h & (HiddenBit<<1)){
131*d6dfd9efSDavid du Colombier 		if(i->h & 0x01)
132*d6dfd9efSDavid du Colombier 			i->l |= CarryBit;
133*d6dfd9efSDavid du Colombier 		i->l = (i->l>>1)|(i->l & 0x01);
134*d6dfd9efSDavid du Colombier 		i->h >>= 1;
135*d6dfd9efSDavid du Colombier 		i->e++;
136*d6dfd9efSDavid du Colombier 	}
137*d6dfd9efSDavid du Colombier 	if(IsWeird(i))
138*d6dfd9efSDavid du Colombier 		SetInfinity(i);
139*d6dfd9efSDavid du Colombier }
140*d6dfd9efSDavid du Colombier 
141*d6dfd9efSDavid du Colombier void
fpisub(Internal * x,Internal * y,Internal * i)142*d6dfd9efSDavid du Colombier fpisub(Internal *x, Internal *y, Internal *i)
143*d6dfd9efSDavid du Colombier {
144*d6dfd9efSDavid du Colombier 	Internal *t;
145*d6dfd9efSDavid du Colombier 
146*d6dfd9efSDavid du Colombier 	if(y->e < x->e
147*d6dfd9efSDavid du Colombier 	   || (y->e == x->e && (y->h < x->h || (y->h == x->h && y->l < x->l)))){
148*d6dfd9efSDavid du Colombier 		t = x;
149*d6dfd9efSDavid du Colombier 		x = y;
150*d6dfd9efSDavid du Colombier 		y = t;
151*d6dfd9efSDavid du Colombier 	}
152*d6dfd9efSDavid du Colombier 	i->s = y->s;
153*d6dfd9efSDavid du Colombier 	if(IsNaN(y)){
154*d6dfd9efSDavid du Colombier 		SetQNaN(i);
155*d6dfd9efSDavid du Colombier 		return;
156*d6dfd9efSDavid du Colombier 	}
157*d6dfd9efSDavid du Colombier 	if(IsInfinity(y)){
158*d6dfd9efSDavid du Colombier 		if(IsInfinity(x))
159*d6dfd9efSDavid du Colombier 			SetQNaN(i);
160*d6dfd9efSDavid du Colombier 		else
161*d6dfd9efSDavid du Colombier 			SetInfinity(i);
162*d6dfd9efSDavid du Colombier 		return;
163*d6dfd9efSDavid du Colombier 	}
164*d6dfd9efSDavid du Colombier 	matchexponents(x, y);
165*d6dfd9efSDavid du Colombier 	i->e = y->e;
166*d6dfd9efSDavid du Colombier 	i->h = y->h - x->h;
167*d6dfd9efSDavid du Colombier 	i->l = y->l - x->l;
168*d6dfd9efSDavid du Colombier 	if(i->l < 0){
169*d6dfd9efSDavid du Colombier 		i->l += CarryBit;
170*d6dfd9efSDavid du Colombier 		i->h--;
171*d6dfd9efSDavid du Colombier 	}
172*d6dfd9efSDavid du Colombier 	if(i->h == 0 && i->l == 0)
173*d6dfd9efSDavid du Colombier 		SetZero(i);
174*d6dfd9efSDavid du Colombier 	else while(i->e > 1 && (i->h & HiddenBit) == 0)
175*d6dfd9efSDavid du Colombier 		shift(i);
176*d6dfd9efSDavid du Colombier }
177*d6dfd9efSDavid du Colombier 
178*d6dfd9efSDavid du Colombier #define	CHUNK		(FractBits/2)
179*d6dfd9efSDavid du Colombier #define	CMASK		((1<<CHUNK)-1)
180*d6dfd9efSDavid du Colombier #define	HI(x)		((short)((x)>>CHUNK) & CMASK)
181*d6dfd9efSDavid du Colombier #define	LO(x)		((short)(x) & CMASK)
182*d6dfd9efSDavid du Colombier #define	SPILL(x)	((x)>>CHUNK)
183*d6dfd9efSDavid du Colombier #define	M(x, y)		((long)a[x]*(long)b[y])
184*d6dfd9efSDavid du Colombier #define	C(h, l)		(((long)((h) & CMASK)<<CHUNK)|((l) & CMASK))
185*d6dfd9efSDavid du Colombier 
186*d6dfd9efSDavid du Colombier void
fpimul(Internal * x,Internal * y,Internal * i)187*d6dfd9efSDavid du Colombier fpimul(Internal *x, Internal *y, Internal *i)
188*d6dfd9efSDavid du Colombier {
189*d6dfd9efSDavid du Colombier 	long a[4], b[4], c[7], f[4];
190*d6dfd9efSDavid du Colombier 
191*d6dfd9efSDavid du Colombier 	i->s = x->s^y->s;
192*d6dfd9efSDavid du Colombier 	if(IsWeird(x) || IsWeird(y)){
193*d6dfd9efSDavid du Colombier 		if(IsNaN(x) || IsNaN(y) || IsZero(x) || IsZero(y))
194*d6dfd9efSDavid du Colombier 			SetQNaN(i);
195*d6dfd9efSDavid du Colombier 		else
196*d6dfd9efSDavid du Colombier 			SetInfinity(i);
197*d6dfd9efSDavid du Colombier 		return;
198*d6dfd9efSDavid du Colombier 	}
199*d6dfd9efSDavid du Colombier 	else if(IsZero(x) || IsZero(y)){
200*d6dfd9efSDavid du Colombier 		SetZero(i);
201*d6dfd9efSDavid du Colombier 		return;
202*d6dfd9efSDavid du Colombier 	}
203*d6dfd9efSDavid du Colombier 	normalise(x);
204*d6dfd9efSDavid du Colombier 	normalise(y);
205*d6dfd9efSDavid du Colombier 	i->e = x->e + y->e - (ExpBias - 1);
206*d6dfd9efSDavid du Colombier 
207*d6dfd9efSDavid du Colombier 	a[0] = HI(x->h); b[0] = HI(y->h);
208*d6dfd9efSDavid du Colombier 	a[1] = LO(x->h); b[1] = LO(y->h);
209*d6dfd9efSDavid du Colombier 	a[2] = HI(x->l); b[2] = HI(y->l);
210*d6dfd9efSDavid du Colombier 	a[3] = LO(x->l); b[3] = LO(y->l);
211*d6dfd9efSDavid du Colombier 
212*d6dfd9efSDavid du Colombier 	c[6] =                               M(3, 3);
213*d6dfd9efSDavid du Colombier 	c[5] =                     M(2, 3) + M(3, 2) + SPILL(c[6]);
214*d6dfd9efSDavid du Colombier 	c[4] =           M(1, 3) + M(2, 2) + M(3, 1) + SPILL(c[5]);
215*d6dfd9efSDavid du Colombier 	c[3] = M(0, 3) + M(1, 2) + M(2, 1) + M(3, 0) + SPILL(c[4]);
216*d6dfd9efSDavid du Colombier 	c[2] = M(0, 2) + M(1, 1) + M(2, 0)           + SPILL(c[3]);
217*d6dfd9efSDavid du Colombier 	c[1] = M(0, 1) + M(1, 0)                     + SPILL(c[2]);
218*d6dfd9efSDavid du Colombier 	c[0] = M(0, 0)                               + SPILL(c[1]);
219*d6dfd9efSDavid du Colombier 
220*d6dfd9efSDavid du Colombier 	f[0] = c[0];
221*d6dfd9efSDavid du Colombier 	f[1] = C(c[1], c[2]);
222*d6dfd9efSDavid du Colombier 	f[2] = C(c[3], c[4]);
223*d6dfd9efSDavid du Colombier 	f[3] = C(c[5], c[6]);
224*d6dfd9efSDavid du Colombier 
225*d6dfd9efSDavid du Colombier 	if((f[0] & HiddenBit) == 0){
226*d6dfd9efSDavid du Colombier 		f[0] <<= 1;
227*d6dfd9efSDavid du Colombier 		f[1] <<= 1;
228*d6dfd9efSDavid du Colombier 		f[2] <<= 1;
229*d6dfd9efSDavid du Colombier 		f[3] <<= 1;
230*d6dfd9efSDavid du Colombier 		if(f[1] & CarryBit){
231*d6dfd9efSDavid du Colombier 			f[0] |= 1;
232*d6dfd9efSDavid du Colombier 			f[1] &= ~CarryBit;
233*d6dfd9efSDavid du Colombier 		}
234*d6dfd9efSDavid du Colombier 		if(f[2] & CarryBit){
235*d6dfd9efSDavid du Colombier 			f[1] |= 1;
236*d6dfd9efSDavid du Colombier 			f[2] &= ~CarryBit;
237*d6dfd9efSDavid du Colombier 		}
238*d6dfd9efSDavid du Colombier 		if(f[3] & CarryBit){
239*d6dfd9efSDavid du Colombier 			f[2] |= 1;
240*d6dfd9efSDavid du Colombier 			f[3] &= ~CarryBit;
241*d6dfd9efSDavid du Colombier 		}
242*d6dfd9efSDavid du Colombier 		i->e--;
243*d6dfd9efSDavid du Colombier 	}
244*d6dfd9efSDavid du Colombier 	i->h = f[0];
245*d6dfd9efSDavid du Colombier 	i->l = f[1];
246*d6dfd9efSDavid du Colombier 	if(f[2] || f[3])
247*d6dfd9efSDavid du Colombier 		i->l |= 1;
248*d6dfd9efSDavid du Colombier 	renormalise(i);
249*d6dfd9efSDavid du Colombier }
250*d6dfd9efSDavid du Colombier 
251*d6dfd9efSDavid du Colombier void
fpidiv(Internal * x,Internal * y,Internal * i)252*d6dfd9efSDavid du Colombier fpidiv(Internal *x, Internal *y, Internal *i)
253*d6dfd9efSDavid du Colombier {
254*d6dfd9efSDavid du Colombier 	i->s = x->s^y->s;
255*d6dfd9efSDavid du Colombier 	if(IsNaN(x) || IsNaN(y)
256*d6dfd9efSDavid du Colombier 	   || (IsInfinity(x) && IsInfinity(y)) || (IsZero(x) && IsZero(y))){
257*d6dfd9efSDavid du Colombier 		SetQNaN(i);
258*d6dfd9efSDavid du Colombier 		return;
259*d6dfd9efSDavid du Colombier 	}
260*d6dfd9efSDavid du Colombier 	else if(IsZero(x) || IsInfinity(y)){
261*d6dfd9efSDavid du Colombier 		SetInfinity(i);
262*d6dfd9efSDavid du Colombier 		return;
263*d6dfd9efSDavid du Colombier 	}
264*d6dfd9efSDavid du Colombier 	else if(IsInfinity(x) || IsZero(y)){
265*d6dfd9efSDavid du Colombier 		SetZero(i);
266*d6dfd9efSDavid du Colombier 		return;
267*d6dfd9efSDavid du Colombier 	}
268*d6dfd9efSDavid du Colombier 	normalise(x);
269*d6dfd9efSDavid du Colombier 	normalise(y);
270*d6dfd9efSDavid du Colombier 	i->h = 0;
271*d6dfd9efSDavid du Colombier 	i->l = 0;
272*d6dfd9efSDavid du Colombier 	i->e = y->e - x->e + (ExpBias + 2*FractBits - 1);
273*d6dfd9efSDavid du Colombier 	do{
274*d6dfd9efSDavid du Colombier 		if(y->h > x->h || (y->h == x->h && y->l >= x->l)){
275*d6dfd9efSDavid du Colombier 			i->l |= 0x01;
276*d6dfd9efSDavid du Colombier 			y->h -= x->h;
277*d6dfd9efSDavid du Colombier 			y->l -= x->l;
278*d6dfd9efSDavid du Colombier 			if(y->l < 0){
279*d6dfd9efSDavid du Colombier 				y->l += CarryBit;
280*d6dfd9efSDavid du Colombier 				y->h--;
281*d6dfd9efSDavid du Colombier 			}
282*d6dfd9efSDavid du Colombier 		}
283*d6dfd9efSDavid du Colombier 		shift(y);
284*d6dfd9efSDavid du Colombier 		shift(i);
285*d6dfd9efSDavid du Colombier 	}while ((i->h & HiddenBit) == 0);
286*d6dfd9efSDavid du Colombier /*
287*d6dfd9efSDavid du Colombier 	if(y->h > x->h || (y->h == x->h && y->l >= x->l))
288*d6dfd9efSDavid du Colombier 		i->l |= 0x01;
289*d6dfd9efSDavid du Colombier */
290*d6dfd9efSDavid du Colombier 	if(y->h || y->l)
291*d6dfd9efSDavid du Colombier 		i->l |= 0x01;
292*d6dfd9efSDavid du Colombier 	renormalise(i);
293*d6dfd9efSDavid du Colombier }
294*d6dfd9efSDavid du Colombier 
295*d6dfd9efSDavid du Colombier int
fpicmp(Internal * x,Internal * y)296*d6dfd9efSDavid du Colombier fpicmp(Internal *x, Internal *y)
297*d6dfd9efSDavid du Colombier {
298*d6dfd9efSDavid du Colombier 	if(IsNaN(x) && IsNaN(y))
299*d6dfd9efSDavid du Colombier 		return 0;
300*d6dfd9efSDavid du Colombier 	if(IsInfinity(x) && IsInfinity(y))
301*d6dfd9efSDavid du Colombier 		return y->s - x->s;
302*d6dfd9efSDavid du Colombier 	if(x->e == y->e && x->h == y->h && x->l == y->l)
303*d6dfd9efSDavid du Colombier 		return y->s - x->s;
304*d6dfd9efSDavid du Colombier 	if(x->e < y->e
305*d6dfd9efSDavid du Colombier 	   || (x->e == y->e && (x->h < y->h || (x->h == y->h && x->l < y->l))))
306*d6dfd9efSDavid du Colombier 		return y->s ? 1: -1;
307*d6dfd9efSDavid du Colombier 	return x->s ? -1: 1;
308*d6dfd9efSDavid du Colombier }
309