blob: f0a3742bcd2d66d4fa0c932f9e1caec1b0b9c023 [file] [log] [blame]
Russ Cox8c195bd2015-02-13 14:40:36 -05001// 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
5package gc
6
7//
8// return the significant
9// words of the argument
10//
Robert Griesemer888767f2015-03-18 14:10:22 -070011func mplen(a *Mpfix) int {
Russ Cox382b44e2015-02-23 16:07:24 -050012 n := -1
13 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -050014 if a.A[i] != 0 {
15 n = i
16 }
17 }
18
19 return n + 1
20}
21
22//
23// left shift mpint by one
24// ignores sign
25//
Robert Griesemer888767f2015-03-18 14:10:22 -070026func mplsh(a *Mpfix, quiet int) {
Russ Cox8c195bd2015-02-13 14:40:36 -050027 var x int
Russ Cox8c195bd2015-02-13 14:40:36 -050028
Russ Cox382b44e2015-02-23 16:07:24 -050029 c := 0
30 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -050031 x = (a.A[i] << 1) + c
32 c = 0
33 if x >= Mpbase {
34 x -= Mpbase
35 c = 1
36 }
37
38 a.A[i] = x
39 }
40
41 a.Ovf = uint8(c)
Russ Coxdc7b54b2015-02-17 22:13:49 -050042 if a.Ovf != 0 && quiet == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -050043 Yyerror("constant shift overflow")
44 }
45}
46
47//
48// left shift mpint by Mpscale
49// ignores sign
50//
Robert Griesemer888767f2015-03-18 14:10:22 -070051func mplshw(a *Mpfix, quiet int) {
Russ Cox382b44e2015-02-23 16:07:24 -050052 i := Mpprec - 1
Russ Cox8c195bd2015-02-13 14:40:36 -050053 if a.A[i] != 0 {
54 a.Ovf = 1
Russ Coxdc7b54b2015-02-17 22:13:49 -050055 if quiet == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -050056 Yyerror("constant shift overflow")
57 }
58 }
59
60 for ; i > 0; i-- {
61 a.A[i] = a.A[i-1]
62 }
63 a.A[i] = 0
64}
65
66//
67// right shift mpint by one
68// ignores sign and overflow
69//
Robert Griesemer888767f2015-03-18 14:10:22 -070070func mprsh(a *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -050071 var x int
Russ Cox8c195bd2015-02-13 14:40:36 -050072
Russ Cox382b44e2015-02-23 16:07:24 -050073 c := 0
74 lo := a.A[0] & 1
75 for i := Mpprec - 1; i >= 0; i-- {
Russ Cox8c195bd2015-02-13 14:40:36 -050076 x = a.A[i]
77 a.A[i] = (x + c) >> 1
78 c = 0
79 if x&1 != 0 {
80 c = Mpbase
81 }
82 }
83
84 if a.Neg != 0 && lo != 0 {
85 mpaddcfix(a, -1)
86 }
87}
88
89//
90// right shift mpint by Mpscale
91// ignores sign and overflow
92//
Robert Griesemer888767f2015-03-18 14:10:22 -070093func mprshw(a *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -050094 var i int
95
Russ Cox382b44e2015-02-23 16:07:24 -050096 lo := a.A[0]
Russ Cox8c195bd2015-02-13 14:40:36 -050097 for i = 0; i < Mpprec-1; i++ {
98 a.A[i] = a.A[i+1]
99 }
100
101 a.A[i] = 0
102 if a.Neg != 0 && lo != 0 {
103 mpaddcfix(a, -1)
104 }
105}
106
107//
108// return the sign of (abs(a)-abs(b))
109//
Robert Griesemer888767f2015-03-18 14:10:22 -0700110func mpcmp(a *Mpfix, b *Mpfix) int {
Russ Cox8c195bd2015-02-13 14:40:36 -0500111 if a.Ovf != 0 || b.Ovf != 0 {
112 if nsavederrors+nerrors == 0 {
113 Yyerror("ovf in cmp")
114 }
115 return 0
116 }
117
Russ Cox382b44e2015-02-23 16:07:24 -0500118 var x int
119 for i := Mpprec - 1; i >= 0; i-- {
Russ Cox8c195bd2015-02-13 14:40:36 -0500120 x = a.A[i] - b.A[i]
121 if x > 0 {
122 return +1
123 }
124 if x < 0 {
125 return -1
126 }
127 }
128
129 return 0
130}
131
132//
133// negate a
134// ignore sign and ovf
135//
Robert Griesemer888767f2015-03-18 14:10:22 -0700136func mpneg(a *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500137 var x int
Russ Cox8c195bd2015-02-13 14:40:36 -0500138
Russ Cox382b44e2015-02-23 16:07:24 -0500139 c := 0
140 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500141 x = -a.A[i] - c
142 c = 0
143 if x < 0 {
144 x += Mpbase
145 c = 1
146 }
147
148 a.A[i] = x
149 }
150}
151
Russ Cox8c195bd2015-02-13 14:40:36 -0500152func Mpshiftfix(a *Mpint, s int) {
Robert Griesemer888767f2015-03-18 14:10:22 -0700153 switch {
154 case s > 0:
155 if mptestovf(a, s) {
156 Yyerror("constant shift overflow")
157 return
158 }
159 a.Val.Lsh(&a.Val, uint(s))
160 case s < 0:
161 a.Val.Rsh(&a.Val, uint(-s))
162 }
163}
164
165// shift left by s (or right by -s)
166func _Mpshiftfix(a *Mpfix, s int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500167 if s >= 0 {
168 for s >= Mpscale {
169 mplshw(a, 0)
170 s -= Mpscale
171 }
172
173 for s > 0 {
174 mplsh(a, 0)
175 s--
176 }
177 } else {
178 s = -s
179 for s >= Mpscale {
180 mprshw(a)
181 s -= Mpscale
182 }
183
184 for s > 0 {
185 mprsh(a)
186 s--
187 }
188 }
189}
190
Robert Griesemer888767f2015-03-18 14:10:22 -0700191/// implements fix arithmetic
Russ Cox8c195bd2015-02-13 14:40:36 -0500192
Robert Griesemer888767f2015-03-18 14:10:22 -0700193func mpsetovf(a *Mpint) {
194 a.Val.SetUint64(0)
195 a.Ovf = true
196}
197
198func mptestovf(a *Mpint, extra int) bool {
199 // We don't need to be precise here, any reasonable upper limit would do.
200 // For now, use existing limit so we pass all the tests unchanged.
201 const limit = Mpscale * Mpprec
202 if a.Val.BitLen()+extra > limit {
203 mpsetovf(a)
204 }
205 return a.Ovf
206}
207
208func mpaddfixfix(a, b *Mpint, quiet int) {
209 if a.Ovf || b.Ovf {
210 if nsavederrors+nerrors == 0 {
211 Yyerror("ovf in mpaddxx")
212 }
213 mpsetovf(a)
214 return
215 }
216
217 a.Val.Add(&a.Val, &b.Val)
218
219 if mptestovf(a, 0) && quiet == 0 {
220 Yyerror("constant addition overflow")
221 }
222}
223
224func _mpaddfixfix(a *Mpfix, b *Mpfix, quiet int) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500225 if a.Ovf != 0 || b.Ovf != 0 {
226 if nsavederrors+nerrors == 0 {
227 Yyerror("ovf in mpaddxx")
228 }
229 a.Ovf = 1
230 return
231 }
232
Russ Cox382b44e2015-02-23 16:07:24 -0500233 c := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500234 if a.Neg != b.Neg {
Russ Cox79f727a2015-03-02 12:35:15 -0500235 // perform a-b
236 switch mpcmp(a, b) {
237 case 0:
Robert Griesemer888767f2015-03-18 14:10:22 -0700238 _Mpmovecfix(a, 0)
Russ Cox79f727a2015-03-02 12:35:15 -0500239
240 case 1:
241 var x int
242 for i := 0; i < Mpprec; i++ {
243 x = a.A[i] - b.A[i] - c
244 c = 0
245 if x < 0 {
246 x += Mpbase
247 c = 1
248 }
249
250 a.A[i] = x
251 }
252
253 case -1:
254 a.Neg ^= 1
255 var x int
256 for i := 0; i < Mpprec; i++ {
257 x = b.A[i] - a.A[i] - c
258 c = 0
259 if x < 0 {
260 x += Mpbase
261 c = 1
262 }
263
264 a.A[i] = x
265 }
266 }
267 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500268 }
269
270 // perform a+b
Russ Cox79f727a2015-03-02 12:35:15 -0500271 var x int
Russ Cox382b44e2015-02-23 16:07:24 -0500272 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500273 x = a.A[i] + b.A[i] + c
274 c = 0
275 if x >= Mpbase {
276 x -= Mpbase
277 c = 1
278 }
279
280 a.A[i] = x
281 }
282
283 a.Ovf = uint8(c)
Russ Coxdc7b54b2015-02-17 22:13:49 -0500284 if a.Ovf != 0 && quiet == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500285 Yyerror("constant addition overflow")
286 }
287
288 return
Russ Cox8c195bd2015-02-13 14:40:36 -0500289}
290
Robert Griesemer888767f2015-03-18 14:10:22 -0700291func mpmulfixfix(a, b *Mpint) {
292 if a.Ovf || b.Ovf {
293 if nsavederrors+nerrors == 0 {
294 Yyerror("ovf in mpmulfixfix")
295 }
296 mpsetovf(a)
297 return
298 }
299
300 a.Val.Mul(&a.Val, &b.Val)
301
302 if mptestovf(a, 0) {
303 Yyerror("constant multiplication overflow")
304 }
305}
306
307func _mpmulfixfix(a *Mpfix, b *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500308 if a.Ovf != 0 || b.Ovf != 0 {
309 if nsavederrors+nerrors == 0 {
310 Yyerror("ovf in mpmulfixfix")
311 }
312 a.Ovf = 1
313 return
314 }
315
316 // pick the smaller
317 // to test for bits
Russ Cox382b44e2015-02-23 16:07:24 -0500318 na := mplen(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500319
Russ Cox382b44e2015-02-23 16:07:24 -0500320 nb := mplen(b)
Robert Griesemer888767f2015-03-18 14:10:22 -0700321 var s Mpfix
322 var c *Mpfix
Russ Cox8c195bd2015-02-13 14:40:36 -0500323 if na > nb {
Robert Griesemer888767f2015-03-18 14:10:22 -0700324 _mpmovefixfix(&s, a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500325 c = b
326 na = nb
327 } else {
Robert Griesemer888767f2015-03-18 14:10:22 -0700328 _mpmovefixfix(&s, b)
Russ Cox8c195bd2015-02-13 14:40:36 -0500329 c = a
330 }
331
332 s.Neg = 0
333
Robert Griesemer888767f2015-03-18 14:10:22 -0700334 var q Mpfix
335 _Mpmovecfix(&q, 0)
Russ Cox382b44e2015-02-23 16:07:24 -0500336 var j int
337 var x int
338 for i := 0; i < na; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500339 x = c.A[i]
340 for j = 0; j < Mpscale; j++ {
341 if x&1 != 0 {
342 if s.Ovf != 0 {
343 q.Ovf = 1
344 goto out
345 }
346
Robert Griesemer888767f2015-03-18 14:10:22 -0700347 _mpaddfixfix(&q, &s, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500348 if q.Ovf != 0 {
349 goto out
350 }
351 }
352
353 mplsh(&s, 1)
354 x >>= 1
355 }
356 }
357
358out:
359 q.Neg = a.Neg ^ b.Neg
Robert Griesemer888767f2015-03-18 14:10:22 -0700360 _mpmovefixfix(a, &q)
Russ Cox8c195bd2015-02-13 14:40:36 -0500361 if a.Ovf != 0 {
362 Yyerror("constant multiplication overflow")
363 }
364}
365
Robert Griesemer888767f2015-03-18 14:10:22 -0700366func mpmulfract(a *Mpfix, b *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500367 if a.Ovf != 0 || b.Ovf != 0 {
368 if nsavederrors+nerrors == 0 {
369 Yyerror("ovf in mpmulflt")
370 }
371 a.Ovf = 1
372 return
373 }
374
Robert Griesemer888767f2015-03-18 14:10:22 -0700375 var s Mpfix
376 _mpmovefixfix(&s, b)
Russ Cox8c195bd2015-02-13 14:40:36 -0500377 s.Neg = 0
Robert Griesemer888767f2015-03-18 14:10:22 -0700378 var q Mpfix
379 _Mpmovecfix(&q, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500380
Russ Cox382b44e2015-02-23 16:07:24 -0500381 i := Mpprec - 1
382 x := a.A[i]
Russ Cox8c195bd2015-02-13 14:40:36 -0500383 if x != 0 {
384 Yyerror("mpmulfract not normal")
385 }
386
Russ Cox382b44e2015-02-23 16:07:24 -0500387 var j int
Russ Cox8c195bd2015-02-13 14:40:36 -0500388 for i--; i >= 0; i-- {
389 x = a.A[i]
390 if x == 0 {
391 mprshw(&s)
392 continue
393 }
394
395 for j = 0; j < Mpscale; j++ {
396 x <<= 1
397 if x&Mpbase != 0 {
Robert Griesemer888767f2015-03-18 14:10:22 -0700398 _mpaddfixfix(&q, &s, 1)
Russ Cox8c195bd2015-02-13 14:40:36 -0500399 }
400 mprsh(&s)
401 }
402 }
403
404 q.Neg = a.Neg ^ b.Neg
Robert Griesemer888767f2015-03-18 14:10:22 -0700405 _mpmovefixfix(a, &q)
Russ Cox8c195bd2015-02-13 14:40:36 -0500406 if a.Ovf != 0 {
407 Yyerror("constant multiplication overflow")
408 }
409}
410
Robert Griesemer888767f2015-03-18 14:10:22 -0700411func mporfixfix(a, b *Mpint) {
412 if a.Ovf || b.Ovf {
413 if nsavederrors+nerrors == 0 {
414 Yyerror("ovf in mporfixfix")
415 }
416 mpsetovf(a)
417 return
418 }
419
420 a.Val.Or(&a.Val, &b.Val)
421}
422
423func _mporfixfix(a *Mpfix, b *Mpfix) {
Russ Cox382b44e2015-02-23 16:07:24 -0500424 x := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500425 if a.Ovf != 0 || b.Ovf != 0 {
426 if nsavederrors+nerrors == 0 {
427 Yyerror("ovf in mporfixfix")
428 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700429 _Mpmovecfix(a, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500430 a.Ovf = 1
431 return
432 }
433
434 if a.Neg != 0 {
435 a.Neg = 0
436 mpneg(a)
437 }
438
439 if b.Neg != 0 {
440 mpneg(b)
441 }
442
Russ Cox382b44e2015-02-23 16:07:24 -0500443 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500444 x = a.A[i] | b.A[i]
445 a.A[i] = x
446 }
447
448 if b.Neg != 0 {
449 mpneg(b)
450 }
451 if x&Mpsign != 0 {
452 a.Neg = 1
453 mpneg(a)
454 }
455}
456
Robert Griesemer888767f2015-03-18 14:10:22 -0700457func mpandfixfix(a, b *Mpint) {
458 if a.Ovf || b.Ovf {
459 if nsavederrors+nerrors == 0 {
460 Yyerror("ovf in mpandfixfix")
461 }
462 mpsetovf(a)
463 return
464 }
465
466 a.Val.And(&a.Val, &b.Val)
467}
468
469func _mpandfixfix(a *Mpfix, b *Mpfix) {
Russ Cox382b44e2015-02-23 16:07:24 -0500470 x := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500471 if a.Ovf != 0 || b.Ovf != 0 {
472 if nsavederrors+nerrors == 0 {
473 Yyerror("ovf in mpandfixfix")
474 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700475 _Mpmovecfix(a, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500476 a.Ovf = 1
477 return
478 }
479
480 if a.Neg != 0 {
481 a.Neg = 0
482 mpneg(a)
483 }
484
485 if b.Neg != 0 {
486 mpneg(b)
487 }
488
Russ Cox382b44e2015-02-23 16:07:24 -0500489 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500490 x = a.A[i] & b.A[i]
491 a.A[i] = x
492 }
493
494 if b.Neg != 0 {
495 mpneg(b)
496 }
497 if x&Mpsign != 0 {
498 a.Neg = 1
499 mpneg(a)
500 }
501}
502
Robert Griesemer888767f2015-03-18 14:10:22 -0700503func mpandnotfixfix(a, b *Mpint) {
504 if a.Ovf || b.Ovf {
505 if nsavederrors+nerrors == 0 {
506 Yyerror("ovf in mpandnotfixfix")
507 }
508 mpsetovf(a)
509 return
510 }
511
512 a.Val.AndNot(&a.Val, &b.Val)
513}
514
515func _mpandnotfixfix(a *Mpfix, b *Mpfix) {
Russ Cox382b44e2015-02-23 16:07:24 -0500516 x := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500517 if a.Ovf != 0 || b.Ovf != 0 {
518 if nsavederrors+nerrors == 0 {
519 Yyerror("ovf in mpandnotfixfix")
520 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700521 _Mpmovecfix(a, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500522 a.Ovf = 1
523 return
524 }
525
526 if a.Neg != 0 {
527 a.Neg = 0
528 mpneg(a)
529 }
530
531 if b.Neg != 0 {
532 mpneg(b)
533 }
534
Russ Cox382b44e2015-02-23 16:07:24 -0500535 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500536 x = a.A[i] &^ b.A[i]
537 a.A[i] = x
538 }
539
540 if b.Neg != 0 {
541 mpneg(b)
542 }
543 if x&Mpsign != 0 {
544 a.Neg = 1
545 mpneg(a)
546 }
547}
548
Robert Griesemer888767f2015-03-18 14:10:22 -0700549func mpxorfixfix(a, b *Mpint) {
550 if a.Ovf || b.Ovf {
551 if nsavederrors+nerrors == 0 {
552 Yyerror("ovf in mpxorfixfix")
553 }
554 mpsetovf(a)
555 return
556 }
557
558 a.Val.Xor(&a.Val, &b.Val)
559}
560
561func _mpxorfixfix(a *Mpfix, b *Mpfix) {
Russ Cox382b44e2015-02-23 16:07:24 -0500562 x := 0
Russ Cox8c195bd2015-02-13 14:40:36 -0500563 if a.Ovf != 0 || b.Ovf != 0 {
564 if nsavederrors+nerrors == 0 {
565 Yyerror("ovf in mporfixfix")
566 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700567 _Mpmovecfix(a, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500568 a.Ovf = 1
569 return
570 }
571
572 if a.Neg != 0 {
573 a.Neg = 0
574 mpneg(a)
575 }
576
577 if b.Neg != 0 {
578 mpneg(b)
579 }
580
Russ Cox382b44e2015-02-23 16:07:24 -0500581 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500582 x = a.A[i] ^ b.A[i]
583 a.A[i] = x
584 }
585
586 if b.Neg != 0 {
587 mpneg(b)
588 }
589 if x&Mpsign != 0 {
590 a.Neg = 1
591 mpneg(a)
592 }
593}
594
Robert Griesemer888767f2015-03-18 14:10:22 -0700595func mplshfixfix(a, b *Mpint) {
596 if a.Ovf || b.Ovf {
Russ Cox8c195bd2015-02-13 14:40:36 -0500597 if nsavederrors+nerrors == 0 {
Robert Griesemer888767f2015-03-18 14:10:22 -0700598 Yyerror("ovf in mplshfixfix")
Russ Cox8c195bd2015-02-13 14:40:36 -0500599 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700600 mpsetovf(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500601 return
602 }
603
Russ Cox382b44e2015-02-23 16:07:24 -0500604 s := Mpgetfix(b)
Russ Cox8c195bd2015-02-13 14:40:36 -0500605 if s < 0 || s >= Mpprec*Mpscale {
606 Yyerror("stupid shift: %d", s)
607 Mpmovecfix(a, 0)
608 return
609 }
610
611 Mpshiftfix(a, int(s))
612}
613
Robert Griesemer888767f2015-03-18 14:10:22 -0700614func _mplshfixfix(a *Mpfix, b *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500615 if a.Ovf != 0 || b.Ovf != 0 {
616 if nsavederrors+nerrors == 0 {
Robert Griesemer888767f2015-03-18 14:10:22 -0700617 Yyerror("ovf in mplshfixfix")
618 }
619 _Mpmovecfix(a, 0)
620 a.Ovf = 1
621 return
622 }
623
624 s := _Mpgetfix(b)
625 if s < 0 || s >= Mpprec*Mpscale {
626 Yyerror("stupid shift: %d", s)
627 _Mpmovecfix(a, 0)
628 return
629 }
630
631 _Mpshiftfix(a, int(s))
632}
633
634func mprshfixfix(a, b *Mpint) {
635 if a.Ovf || b.Ovf {
636 if nsavederrors+nerrors == 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500637 Yyerror("ovf in mprshfixfix")
638 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700639 mpsetovf(a)
Russ Cox8c195bd2015-02-13 14:40:36 -0500640 return
641 }
642
Russ Cox382b44e2015-02-23 16:07:24 -0500643 s := Mpgetfix(b)
Russ Cox8c195bd2015-02-13 14:40:36 -0500644 if s < 0 || s >= Mpprec*Mpscale {
645 Yyerror("stupid shift: %d", s)
Robert Griesemer888767f2015-03-18 14:10:22 -0700646 if a.Val.Sign() < 0 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500647 Mpmovecfix(a, -1)
648 } else {
649 Mpmovecfix(a, 0)
650 }
651 return
652 }
653
654 Mpshiftfix(a, int(-s))
655}
656
Robert Griesemer888767f2015-03-18 14:10:22 -0700657func _mprshfixfix(a *Mpfix, b *Mpfix) {
658 if a.Ovf != 0 || b.Ovf != 0 {
659 if nsavederrors+nerrors == 0 {
660 Yyerror("ovf in mprshfixfix")
661 }
662 _Mpmovecfix(a, 0)
663 a.Ovf = 1
664 return
665 }
666
667 s := _Mpgetfix(b)
668 if s < 0 || s >= Mpprec*Mpscale {
669 Yyerror("stupid shift: %d", s)
670 if a.Neg != 0 {
671 _Mpmovecfix(a, -1)
672 } else {
673 _Mpmovecfix(a, 0)
674 }
675 return
676 }
677
678 _Mpshiftfix(a, int(-s))
679}
680
Russ Cox8c195bd2015-02-13 14:40:36 -0500681func mpnegfix(a *Mpint) {
Robert Griesemer888767f2015-03-18 14:10:22 -0700682 a.Val.Neg(&a.Val)
683}
684
685func _mpnegfix(a *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500686 a.Neg ^= 1
687}
688
689func Mpgetfix(a *Mpint) int64 {
Robert Griesemer888767f2015-03-18 14:10:22 -0700690 if a.Ovf {
691 if nsavederrors+nerrors == 0 {
692 Yyerror("constant overflow")
693 }
694 return 0
695 }
696
697 return a.Val.Int64()
698}
699
700func _Mpgetfix(a *Mpfix) int64 {
Russ Cox8c195bd2015-02-13 14:40:36 -0500701 if a.Ovf != 0 {
702 if nsavederrors+nerrors == 0 {
703 Yyerror("constant overflow")
704 }
705 return 0
706 }
707
Russ Cox382b44e2015-02-23 16:07:24 -0500708 v := int64(uint64(a.A[0]))
Russ Cox8c195bd2015-02-13 14:40:36 -0500709 v |= int64(uint64(a.A[1]) << Mpscale)
710 v |= int64(uint64(a.A[2]) << (Mpscale + Mpscale))
711 if a.Neg != 0 {
712 v = int64(-uint64(v))
713 }
714 return v
715}
716
717func Mpmovecfix(a *Mpint, c int64) {
Robert Griesemer888767f2015-03-18 14:10:22 -0700718 a.Val.SetInt64(c)
719}
720
721func _Mpmovecfix(a *Mpfix, c int64) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500722 a.Neg = 0
723 a.Ovf = 0
724
Russ Cox382b44e2015-02-23 16:07:24 -0500725 x := c
Russ Cox8c195bd2015-02-13 14:40:36 -0500726 if x < 0 {
727 a.Neg = 1
728 x = int64(-uint64(x))
729 }
730
Russ Cox382b44e2015-02-23 16:07:24 -0500731 for i := 0; i < Mpprec; i++ {
Russ Cox8c195bd2015-02-13 14:40:36 -0500732 a.A[i] = int(x & Mpmask)
733 x >>= Mpscale
734 }
735}
736
Robert Griesemer888767f2015-03-18 14:10:22 -0700737func mpdivmodfixfix(q *Mpfix, r *Mpfix, n *Mpfix, d *Mpfix) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500738 var i int
Russ Cox8c195bd2015-02-13 14:40:36 -0500739
Russ Cox382b44e2015-02-23 16:07:24 -0500740 ns := int(n.Neg)
741 ds := int(d.Neg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500742 n.Neg = 0
743 d.Neg = 0
744
Robert Griesemer888767f2015-03-18 14:10:22 -0700745 _mpmovefixfix(r, n)
746 _Mpmovecfix(q, 0)
Russ Cox8c195bd2015-02-13 14:40:36 -0500747
748 // shift denominator until it
749 // is larger than numerator
750 for i = 0; i < Mpprec*Mpscale; i++ {
751 if mpcmp(d, r) > 0 {
752 break
753 }
754 mplsh(d, 1)
755 }
756
757 // if it never happens
758 // denominator is probably zero
759 if i >= Mpprec*Mpscale {
760 q.Ovf = 1
761 r.Ovf = 1
762 n.Neg = uint8(ns)
763 d.Neg = uint8(ds)
764 Yyerror("constant division overflow")
765 return
766 }
767
768 // shift denominator back creating
769 // quotient a bit at a time
770 // when done the remaining numerator
771 // will be the remainder
772 for ; i > 0; i-- {
773 mplsh(q, 1)
774 mprsh(d)
775 if mpcmp(d, r) <= 0 {
776 mpaddcfix(q, 1)
Robert Griesemer888767f2015-03-18 14:10:22 -0700777 _mpsubfixfix(r, d)
Russ Cox8c195bd2015-02-13 14:40:36 -0500778 }
779 }
780
781 n.Neg = uint8(ns)
782 d.Neg = uint8(ds)
783 r.Neg = uint8(ns)
784 q.Neg = uint8(ns ^ ds)
785}
786
Robert Griesemer888767f2015-03-18 14:10:22 -0700787func mpiszero(a *Mpfix) bool {
Russ Cox382b44e2015-02-23 16:07:24 -0500788 for i := Mpprec - 1; i >= 0; i-- {
Russ Cox8c195bd2015-02-13 14:40:36 -0500789 if a.A[i] != 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500790 return false
Russ Cox8c195bd2015-02-13 14:40:36 -0500791 }
792 }
Russ Coxdc7b54b2015-02-17 22:13:49 -0500793 return true
Russ Cox8c195bd2015-02-13 14:40:36 -0500794}
795
Robert Griesemer888767f2015-03-18 14:10:22 -0700796func mpdivfract(a *Mpfix, b *Mpfix) {
797 var n Mpfix
798 var d Mpfix
Russ Cox8c195bd2015-02-13 14:40:36 -0500799 var j int
Russ Cox8c195bd2015-02-13 14:40:36 -0500800 var x int
801
Robert Griesemer888767f2015-03-18 14:10:22 -0700802 _mpmovefixfix(&n, a) // numerator
803 _mpmovefixfix(&d, b) // denominator
Russ Cox8c195bd2015-02-13 14:40:36 -0500804
Russ Cox382b44e2015-02-23 16:07:24 -0500805 neg := int(n.Neg) ^ int(d.Neg)
Russ Cox8c195bd2015-02-13 14:40:36 -0500806
807 n.Neg = 0
808 d.Neg = 0
Russ Cox382b44e2015-02-23 16:07:24 -0500809 for i := Mpprec - 1; i >= 0; i-- {
Russ Cox8c195bd2015-02-13 14:40:36 -0500810 x = 0
811 for j = 0; j < Mpscale; j++ {
812 x <<= 1
813 if mpcmp(&d, &n) <= 0 {
Russ Coxdc7b54b2015-02-17 22:13:49 -0500814 if !mpiszero(&d) {
Russ Cox8c195bd2015-02-13 14:40:36 -0500815 x |= 1
816 }
Robert Griesemer888767f2015-03-18 14:10:22 -0700817 _mpsubfixfix(&n, &d)
Russ Cox8c195bd2015-02-13 14:40:36 -0500818 }
819
820 mprsh(&d)
821 }
822
823 a.A[i] = x
824 }
825
826 a.Neg = uint8(neg)
827}
828
Robert Griesemer888767f2015-03-18 14:10:22 -0700829func mptestfix(a *Mpfix) int {
830 var b Mpfix
Russ Cox8c195bd2015-02-13 14:40:36 -0500831
Robert Griesemer888767f2015-03-18 14:10:22 -0700832 _Mpmovecfix(&b, 0)
Russ Cox382b44e2015-02-23 16:07:24 -0500833 r := mpcmp(a, &b)
Russ Cox8c195bd2015-02-13 14:40:36 -0500834 if a.Neg != 0 {
835 if r > 0 {
836 return -1
837 }
838 if r < 0 {
839 return +1
840 }
841 }
842
843 return r
844}