blob: 6afd75c0238f6e5f4dbc7335ea54521e94cc312c [file] [log] [blame]
Colin Cross7bb052a2015-02-03 12:59:37 -08001// Copyright 2009 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5#include <u.h>
6#include <libc.h>
7#include "go.h"
8
9/*
10 * returns the leading non-zero
11 * word of the number
12 */
13int
14sigfig(Mpflt *a)
15{
16 int i;
17
18 for(i=Mpprec-1; i>=0; i--)
19 if(a->val.a[i] != 0)
20 break;
21//print("sigfig %d %d\n", i-z+1, z);
22 return i+1;
23}
24
25/*
26 * sets the exponent.
27 * a too large exponent is an error.
28 * a too small exponent rounds the number to zero.
29 */
30void
31mpsetexp(Mpflt *a, int exp) {
32 if((short)exp != exp) {
33 if(exp > 0) {
34 yyerror("float constant is too large");
35 a->exp = 0x7fff;
36 }
37 else {
38 mpmovecflt(a, 0);
39 }
40 }
41 else {
42 a->exp = exp;
43 }
44}
45
46/*
47 * shifts the leading non-zero
48 * word of the number to Mpnorm
49 */
50void
51mpnorm(Mpflt *a)
52{
53 int s, os;
54 long x;
55
56 os = sigfig(a);
57 if(os == 0) {
58 // zero
59 a->exp = 0;
60 a->val.neg = 0;
61 return;
62 }
63
64 // this will normalize to the nearest word
65 x = a->val.a[os-1];
66 s = (Mpnorm-os) * Mpscale;
67
68 // further normalize to the nearest bit
69 for(;;) {
70 x <<= 1;
71 if(x & Mpbase)
72 break;
73 s++;
74 if(x == 0) {
75 // this error comes from trying to
76 // convert an Inf or something
77 // where the initial x=0x80000000
78 s = (Mpnorm-os) * Mpscale;
79 break;
80 }
81 }
82
83 mpshiftfix(&a->val, s);
84 mpsetexp(a, a->exp-s);
85}
86
87/// implements float arihmetic
88
89void
90mpaddfltflt(Mpflt *a, Mpflt *b)
91{
92 int sa, sb, s;
93 Mpflt c;
94
95 if(Mpdebug)
96 print("\n%F + %F", a, b);
97
98 sa = sigfig(a);
99 if(sa == 0) {
100 mpmovefltflt(a, b);
101 goto out;
102 }
103
104 sb = sigfig(b);
105 if(sb == 0)
106 goto out;
107
108 s = a->exp - b->exp;
109 if(s > 0) {
110 // a is larger, shift b right
111 mpmovefltflt(&c, b);
112 mpshiftfix(&c.val, -s);
113 mpaddfixfix(&a->val, &c.val, 0);
114 goto out;
115 }
116 if(s < 0) {
117 // b is larger, shift a right
118 mpshiftfix(&a->val, s);
119 mpsetexp(a, a->exp-s);
120 mpaddfixfix(&a->val, &b->val, 0);
121 goto out;
122 }
123 mpaddfixfix(&a->val, &b->val, 0);
124
125out:
126 mpnorm(a);
127 if(Mpdebug)
128 print(" = %F\n\n", a);
129}
130
131void
132mpmulfltflt(Mpflt *a, Mpflt *b)
133{
134 int sa, sb;
135
136 if(Mpdebug)
137 print("%F\n * %F\n", a, b);
138
139 sa = sigfig(a);
140 if(sa == 0) {
141 // zero
142 a->exp = 0;
143 a->val.neg = 0;
144 return;
145 }
146
147 sb = sigfig(b);
148 if(sb == 0) {
149 // zero
150 mpmovefltflt(a, b);
151 return;
152 }
153
154 mpmulfract(&a->val, &b->val);
155 mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
156
157 mpnorm(a);
158 if(Mpdebug)
159 print(" = %F\n\n", a);
160}
161
162void
163mpdivfltflt(Mpflt *a, Mpflt *b)
164{
165 int sa, sb;
166 Mpflt c;
167
168 if(Mpdebug)
169 print("%F\n / %F\n", a, b);
170
171 sb = sigfig(b);
172 if(sb == 0) {
173 // zero and ovfl
174 a->exp = 0;
175 a->val.neg = 0;
176 a->val.ovf = 1;
177 yyerror("constant division by zero");
178 return;
179 }
180
181 sa = sigfig(a);
182 if(sa == 0) {
183 // zero
184 a->exp = 0;
185 a->val.neg = 0;
186 return;
187 }
188
189 // adjust b to top
190 mpmovefltflt(&c, b);
191 mpshiftfix(&c.val, Mpscale);
192
193 // divide
194 mpdivfract(&a->val, &c.val);
195 mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
196
197 mpnorm(a);
198 if(Mpdebug)
199 print(" = %F\n\n", a);
200}
201
202static double
203mpgetfltN(Mpflt *a, int prec, int bias)
204{
205 int s, i, e, minexp;
206 uvlong v;
207 double f;
208
209 if(a->val.ovf && nsavederrors+nerrors == 0)
210 yyerror("mpgetflt ovf");
211
212 s = sigfig(a);
213 if(s == 0)
214 return 0;
215
216 if(s != Mpnorm) {
217 yyerror("mpgetflt norm");
218 mpnorm(a);
219 }
220
221 while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
222 mpshiftfix(&a->val, 1);
223 mpsetexp(a, a->exp-1); // can set 'a' to zero
224 s = sigfig(a);
225 if(s == 0)
226 return 0;
227 }
228
229 // pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
230 s = prec+2;
231 v = 0;
232 for(i=Mpnorm-1; s>=Mpscale; i--) {
233 v = (v<<Mpscale) | a->val.a[i];
234 s -= Mpscale;
235 }
236 if(s > 0) {
237 v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
238 if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0)
239 v |= 1;
240 i--;
241 }
242 for(; i >= 0; i--) {
243 if(a->val.a[i] != 0)
244 v |= 1;
245 }
246
247 // gradual underflow
248 e = Mpnorm*Mpscale + a->exp - prec;
249 minexp = bias+1-prec+1;
250 if(e < minexp) {
251 s = minexp - e;
252 if(s > prec+1)
253 s = prec+1;
254 if((v & ((1ULL<<s)-1)) != 0)
255 v |= 1ULL<<s;
256 v >>= s;
257 e = minexp;
258 }
259
260 // round to even
261 v |= (v&4)>>2;
262 v += v&1;
263 v >>= 2;
264
265 f = (double)(v);
266 f = ldexp(f, e);
267
268 if(a->val.neg)
269 f = -f;
270
271 return f;
272}
273
274double
275mpgetflt(Mpflt *a)
276{
277 return mpgetfltN(a, 53, -1023);
278}
279
280double
281mpgetflt32(Mpflt *a)
282{
283 return mpgetfltN(a, 24, -127);
284}
285
286void
287mpmovecflt(Mpflt *a, double c)
288{
289 int i;
290 double f;
291 long l;
292
293 if(Mpdebug)
294 print("\nconst %g", c);
295 mpmovecfix(&a->val, 0);
296 a->exp = 0;
297 if(c == 0)
298 goto out;
299 if(c < 0) {
300 a->val.neg = 1;
301 c = -c;
302 }
303
304 f = frexp(c, &i);
305 a->exp = i;
306
307 for(i=0; i<10; i++) {
308 f = f*Mpbase;
309 l = floor(f);
310 f = f - l;
311 a->exp -= Mpscale;
312 a->val.a[0] = l;
313 if(f == 0)
314 break;
315 mpshiftfix(&a->val, Mpscale);
316 }
317
318out:
319 mpnorm(a);
320 if(Mpdebug)
321 print(" = %F\n", a);
322}
323
324void
325mpnegflt(Mpflt *a)
326{
327 a->val.neg ^= 1;
328}
329
330int
331mptestflt(Mpflt *a)
332{
333 int s;
334
335 if(Mpdebug)
336 print("\n%F?", a);
337 s = sigfig(a);
338 if(s != 0) {
339 s = +1;
340 if(a->val.neg)
341 s = -1;
342 }
343 if(Mpdebug)
344 print(" = %d\n", s);
345 return s;
346}