2008-08-09 18:33:35 -06:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2011-08-25 14:25:10 -06:00
|
|
|
#include <u.h>
|
|
|
|
#include <libc.h>
|
2008-12-01 18:22:05 -07:00
|
|
|
#include "go.h"
|
2008-08-09 18:33:35 -06:00
|
|
|
|
|
|
|
//
|
|
|
|
// return the significant
|
|
|
|
// words of the argument
|
|
|
|
//
|
|
|
|
static int
|
|
|
|
mplen(Mpint *a)
|
|
|
|
{
|
|
|
|
int i, n;
|
|
|
|
long *a1;
|
|
|
|
|
|
|
|
n = -1;
|
|
|
|
a1 = &a->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
if(*a1++ != 0)
|
|
|
|
n = i;
|
|
|
|
}
|
|
|
|
return n+1;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// left shift mpint by one
|
2012-02-15 16:19:42 -07:00
|
|
|
// ignores sign
|
2008-08-09 18:33:35 -06:00
|
|
|
//
|
|
|
|
static void
|
2012-02-15 16:19:42 -07:00
|
|
|
mplsh(Mpint *a, int quiet)
|
2008-08-09 18:33:35 -06:00
|
|
|
{
|
|
|
|
long *a1, x;
|
|
|
|
int i, c;
|
|
|
|
|
|
|
|
c = 0;
|
|
|
|
a1 = &a->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = (*a1 << 1) + c;
|
|
|
|
c = 0;
|
|
|
|
if(x >= Mpbase) {
|
|
|
|
x -= Mpbase;
|
|
|
|
c = 1;
|
|
|
|
}
|
|
|
|
*a1++ = x;
|
|
|
|
}
|
2012-02-15 16:19:42 -07:00
|
|
|
a->ovf = c;
|
|
|
|
if(a->ovf && !quiet)
|
|
|
|
yyerror("constant shift overflow");
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// left shift mpint by Mpscale
|
2012-02-15 16:19:42 -07:00
|
|
|
// ignores sign
|
2008-08-09 18:33:35 -06:00
|
|
|
//
|
|
|
|
static void
|
2012-02-15 16:19:42 -07:00
|
|
|
mplshw(Mpint *a, int quiet)
|
2008-08-09 18:33:35 -06:00
|
|
|
{
|
|
|
|
long *a1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
a1 = &a->a[Mpprec-1];
|
2012-02-15 16:19:42 -07:00
|
|
|
if(*a1) {
|
|
|
|
a->ovf = 1;
|
|
|
|
if(!quiet)
|
|
|
|
yyerror("constant shift overflow");
|
|
|
|
}
|
2008-08-09 18:33:35 -06:00
|
|
|
for(i=1; i<Mpprec; i++) {
|
|
|
|
a1[0] = a1[-1];
|
2008-10-04 03:54:19 -06:00
|
|
|
a1--;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
a1[0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// right shift mpint by one
|
|
|
|
// ignores sign and overflow
|
|
|
|
//
|
|
|
|
static void
|
|
|
|
mprsh(Mpint *a)
|
|
|
|
{
|
2008-08-28 20:59:42 -06:00
|
|
|
long *a1, x, lo;
|
2008-08-09 18:33:35 -06:00
|
|
|
int i, c;
|
|
|
|
|
|
|
|
c = 0;
|
2008-08-28 20:59:42 -06:00
|
|
|
lo = a->a[0] & 1;
|
2008-08-09 18:33:35 -06:00
|
|
|
a1 = &a->a[Mpprec];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = *--a1;
|
|
|
|
*a1 = (x + c) >> 1;
|
|
|
|
c = 0;
|
|
|
|
if(x & 1)
|
|
|
|
c = Mpbase;
|
|
|
|
}
|
2008-10-29 21:25:34 -06:00
|
|
|
if(a->neg && lo != 0)
|
2008-08-28 20:59:42 -06:00
|
|
|
mpaddcfix(a, -1);
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// right shift mpint by Mpscale
|
|
|
|
// ignores sign and overflow
|
|
|
|
//
|
|
|
|
static void
|
|
|
|
mprshw(Mpint *a)
|
|
|
|
{
|
2008-08-28 20:59:42 -06:00
|
|
|
long *a1, lo;
|
2008-08-09 18:33:35 -06:00
|
|
|
int i;
|
|
|
|
|
2008-08-28 20:59:42 -06:00
|
|
|
lo = a->a[0];
|
2008-08-09 18:33:35 -06:00
|
|
|
a1 = &a->a[0];
|
|
|
|
for(i=1; i<Mpprec; i++) {
|
|
|
|
a1[0] = a1[1];
|
2008-10-04 03:54:19 -06:00
|
|
|
a1++;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
a1[0] = 0;
|
2008-10-29 21:25:34 -06:00
|
|
|
if(a->neg && lo != 0)
|
2008-08-28 20:59:42 -06:00
|
|
|
mpaddcfix(a, -1);
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// return the sign of (abs(a)-abs(b))
|
|
|
|
//
|
|
|
|
static int
|
|
|
|
mpcmp(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
long x, *a1, *b1;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in cmp");
|
2008-08-09 18:33:35 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
a1 = &a->a[0] + Mpprec;
|
|
|
|
b1 = &b->a[0] + Mpprec;
|
|
|
|
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = *--a1 - *--b1;
|
|
|
|
if(x > 0)
|
|
|
|
return +1;
|
|
|
|
if(x < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// negate a
|
|
|
|
// ignore sign and ovf
|
|
|
|
//
|
|
|
|
static void
|
|
|
|
mpneg(Mpint *a)
|
|
|
|
{
|
|
|
|
long x, *a1;
|
|
|
|
int i, c;
|
|
|
|
|
|
|
|
a1 = &a->a[0];
|
|
|
|
c = 0;
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
2008-10-29 17:38:23 -06:00
|
|
|
x = -*a1 -c;
|
2008-08-09 18:33:35 -06:00
|
|
|
c = 0;
|
2008-10-29 17:38:23 -06:00
|
|
|
if(x < 0) {
|
|
|
|
x += Mpbase;
|
2008-08-09 18:33:35 -06:00
|
|
|
c = 1;
|
2008-10-29 17:38:23 -06:00
|
|
|
}
|
|
|
|
*a1++ = x;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-12 20:04:38 -06:00
|
|
|
// shift left by s (or right by -s)
|
2008-12-01 18:22:05 -07:00
|
|
|
void
|
|
|
|
mpshiftfix(Mpint *a, int s)
|
|
|
|
{
|
|
|
|
if(s >= 0) {
|
|
|
|
while(s >= Mpscale) {
|
2012-02-15 16:19:42 -07:00
|
|
|
mplshw(a, 0);
|
2008-12-01 18:22:05 -07:00
|
|
|
s -= Mpscale;
|
|
|
|
}
|
|
|
|
while(s > 0) {
|
2012-02-15 16:19:42 -07:00
|
|
|
mplsh(a, 0);
|
2008-12-01 18:22:05 -07:00
|
|
|
s--;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
s = -s;
|
|
|
|
while(s >= Mpscale) {
|
|
|
|
mprshw(a);
|
|
|
|
s -= Mpscale;
|
|
|
|
}
|
|
|
|
while(s > 0) {
|
|
|
|
mprsh(a);
|
|
|
|
s--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
/// implements fix arihmetic
|
|
|
|
|
|
|
|
void
|
2012-02-10 22:50:56 -07:00
|
|
|
mpaddfixfix(Mpint *a, Mpint *b, int quiet)
|
2008-08-09 18:33:35 -06:00
|
|
|
{
|
|
|
|
int i, c;
|
|
|
|
long x, *a1, *b1;
|
|
|
|
|
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mpaddxx");
|
2008-08-09 18:33:35 -06:00
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
c = 0;
|
|
|
|
a1 = &a->a[0];
|
|
|
|
b1 = &b->a[0];
|
|
|
|
if(a->neg != b->neg)
|
|
|
|
goto sub;
|
|
|
|
|
|
|
|
// perform a+b
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = *a1 + *b1++ + c;
|
|
|
|
c = 0;
|
|
|
|
if(x >= Mpbase) {
|
|
|
|
x -= Mpbase;
|
|
|
|
c = 1;
|
|
|
|
}
|
|
|
|
*a1++ = x;
|
|
|
|
}
|
|
|
|
a->ovf = c;
|
2012-02-10 22:50:56 -07:00
|
|
|
if(a->ovf && !quiet)
|
|
|
|
yyerror("constant addition overflow");
|
2008-08-09 18:33:35 -06:00
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
sub:
|
|
|
|
// perform a-b
|
|
|
|
switch(mpcmp(a, b)) {
|
|
|
|
case 0:
|
|
|
|
mpmovecfix(a, 0);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 1:
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = *a1 - *b1++ - c;
|
|
|
|
c = 0;
|
|
|
|
if(x < 0) {
|
|
|
|
x += Mpbase;
|
|
|
|
c = 1;
|
|
|
|
}
|
|
|
|
*a1++ = x;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case -1:
|
|
|
|
a->neg ^= 1;
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = *b1++ - *a1 - c;
|
|
|
|
c = 0;
|
|
|
|
if(x < 0) {
|
|
|
|
x += Mpbase;
|
|
|
|
c = 1;
|
|
|
|
}
|
|
|
|
*a1++ = x;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpmulfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
|
|
|
|
int i, j, na, nb;
|
|
|
|
long *a1, x;
|
|
|
|
Mpint s, q;
|
|
|
|
|
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mpmulfixfix");
|
2008-08-09 18:33:35 -06:00
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// pick the smaller
|
|
|
|
// to test for bits
|
|
|
|
na = mplen(a);
|
|
|
|
nb = mplen(b);
|
|
|
|
if(na > nb) {
|
|
|
|
mpmovefixfix(&s, a);
|
|
|
|
a1 = &b->a[0];
|
|
|
|
na = nb;
|
|
|
|
} else {
|
|
|
|
mpmovefixfix(&s, b);
|
|
|
|
a1 = &a->a[0];
|
|
|
|
}
|
|
|
|
s.neg = 0;
|
|
|
|
|
|
|
|
mpmovecfix(&q, 0);
|
|
|
|
for(i=0; i<na; i++) {
|
|
|
|
x = *a1++;
|
|
|
|
for(j=0; j<Mpscale; j++) {
|
|
|
|
if(x & 1)
|
2012-02-10 22:50:56 -07:00
|
|
|
mpaddfixfix(&q, &s, 1);
|
2012-02-15 16:19:42 -07:00
|
|
|
mplsh(&s, 1);
|
2008-08-09 18:33:35 -06:00
|
|
|
x >>= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
q.neg = a->neg ^ b->neg;
|
|
|
|
mpmovefixfix(a, &q);
|
|
|
|
if(a->ovf)
|
2012-02-10 22:50:56 -07:00
|
|
|
yyerror("constant multiplication overflow");
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
2008-12-01 18:22:05 -07:00
|
|
|
void
|
|
|
|
mpmulfract(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
|
|
|
|
int i, j;
|
|
|
|
long *a1, x;
|
|
|
|
Mpint s, q;
|
|
|
|
|
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mpmulflt");
|
2008-12-01 18:22:05 -07:00
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
mpmovefixfix(&s, b);
|
|
|
|
a1 = &a->a[Mpprec];
|
|
|
|
s.neg = 0;
|
|
|
|
mpmovecfix(&q, 0);
|
|
|
|
|
2010-07-17 17:32:40 -06:00
|
|
|
x = *--a1;
|
|
|
|
if(x != 0)
|
|
|
|
yyerror("mpmulfract not normal");
|
|
|
|
|
|
|
|
for(i=0; i<Mpprec-1; i++) {
|
2008-12-01 18:22:05 -07:00
|
|
|
x = *--a1;
|
|
|
|
if(x == 0) {
|
|
|
|
mprshw(&s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for(j=0; j<Mpscale; j++) {
|
|
|
|
x <<= 1;
|
|
|
|
if(x & Mpbase)
|
2012-02-10 22:50:56 -07:00
|
|
|
mpaddfixfix(&q, &s, 1);
|
2008-12-01 18:22:05 -07:00
|
|
|
mprsh(&s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
q.neg = a->neg ^ b->neg;
|
|
|
|
mpmovefixfix(a, &q);
|
|
|
|
if(a->ovf)
|
2012-02-10 22:50:56 -07:00
|
|
|
yyerror("constant multiplication overflow");
|
2008-12-01 18:22:05 -07:00
|
|
|
}
|
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
void
|
|
|
|
mporfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
long x, *a1, *b1;
|
|
|
|
|
2011-08-29 07:35:04 -06:00
|
|
|
x = 0;
|
2008-08-09 18:33:35 -06:00
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mporfixfix");
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(a->neg) {
|
|
|
|
a->neg = 0;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
|
|
|
|
a1 = &a->a[0];
|
|
|
|
b1 = &b->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
2008-10-29 17:38:23 -06:00
|
|
|
x = *a1 | *b1++;
|
|
|
|
*a1++ = x;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
if(x & Mpsign) {
|
|
|
|
a->neg = 1;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpandfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
long x, *a1, *b1;
|
|
|
|
|
2011-08-29 07:35:04 -06:00
|
|
|
x = 0;
|
2008-08-09 18:33:35 -06:00
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mpandfixfix");
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(a->neg) {
|
|
|
|
a->neg = 0;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
|
|
|
|
a1 = &a->a[0];
|
|
|
|
b1 = &b->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
2008-10-29 17:38:23 -06:00
|
|
|
x = *a1 & *b1++;
|
|
|
|
*a1++ = x;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
if(x & Mpsign) {
|
|
|
|
a->neg = 1;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-11 20:59:35 -06:00
|
|
|
void
|
|
|
|
mpandnotfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
long x, *a1, *b1;
|
|
|
|
|
2011-08-29 07:35:04 -06:00
|
|
|
x = 0;
|
2009-03-11 20:59:35 -06:00
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mpandnotfixfix");
|
2009-03-11 20:59:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(a->neg) {
|
|
|
|
a->neg = 0;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
|
|
|
|
a1 = &a->a[0];
|
|
|
|
b1 = &b->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = *a1 & ~*b1++;
|
|
|
|
*a1++ = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
if(x & Mpsign) {
|
|
|
|
a->neg = 1;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
void
|
|
|
|
mpxorfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
long x, *a1, *b1;
|
|
|
|
|
2011-08-29 07:35:04 -06:00
|
|
|
x = 0;
|
2008-08-09 18:33:35 -06:00
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mporfixfix");
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(a->neg) {
|
|
|
|
a->neg = 0;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
|
|
|
|
a1 = &a->a[0];
|
|
|
|
b1 = &b->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
2008-10-29 17:38:23 -06:00
|
|
|
x = *a1 ^ *b1++;
|
|
|
|
*a1++ = x;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
if(b->neg)
|
|
|
|
mpneg(b);
|
|
|
|
if(x & Mpsign) {
|
|
|
|
a->neg = 1;
|
|
|
|
mpneg(a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mplshfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
vlong s;
|
|
|
|
|
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mporfixfix");
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s = mpgetfix(b);
|
|
|
|
if(s < 0 || s >= Mpprec*Mpscale) {
|
2009-03-12 20:57:30 -06:00
|
|
|
yyerror("stupid shift: %lld", s);
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-12-01 18:22:05 -07:00
|
|
|
mpshiftfix(a, s);
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mprshfixfix(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
vlong s;
|
|
|
|
|
|
|
|
if(a->ovf || b->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("ovf in mprshfixfix");
|
2008-08-09 18:33:35 -06:00
|
|
|
mpmovecfix(a, 0);
|
|
|
|
a->ovf = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
s = mpgetfix(b);
|
|
|
|
if(s < 0 || s >= Mpprec*Mpscale) {
|
2009-03-12 20:57:30 -06:00
|
|
|
yyerror("stupid shift: %lld", s);
|
2008-08-28 20:59:42 -06:00
|
|
|
if(a->neg)
|
|
|
|
mpmovecfix(a, -1);
|
|
|
|
else
|
|
|
|
mpmovecfix(a, 0);
|
2008-08-09 18:33:35 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2008-12-01 18:22:05 -07:00
|
|
|
mpshiftfix(a, -s);
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpnegfix(Mpint *a)
|
|
|
|
{
|
|
|
|
a->neg ^= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
vlong
|
|
|
|
mpgetfix(Mpint *a)
|
|
|
|
{
|
|
|
|
vlong v;
|
|
|
|
|
|
|
|
if(a->ovf) {
|
2012-02-10 22:50:56 -07:00
|
|
|
if(nsavederrors+nerrors == 0)
|
|
|
|
yyerror("constant overflow");
|
2008-08-09 18:33:35 -06:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
v = (vlong)a->a[0];
|
|
|
|
v |= (vlong)a->a[1] << Mpscale;
|
|
|
|
v |= (vlong)a->a[2] << (Mpscale+Mpscale);
|
|
|
|
if(a->neg)
|
|
|
|
v = -v;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpmovecfix(Mpint *a, vlong c)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
long *a1;
|
|
|
|
vlong x;
|
|
|
|
|
|
|
|
a->neg = 0;
|
|
|
|
a->ovf = 0;
|
|
|
|
|
|
|
|
x = c;
|
|
|
|
if(x < 0) {
|
|
|
|
a->neg = 1;
|
|
|
|
x = -x;
|
|
|
|
}
|
|
|
|
|
|
|
|
a1 = &a->a[0];
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
*a1++ = x&Mpmask;
|
|
|
|
x >>= Mpscale;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
mpdivmodfixfix(Mpint *q, Mpint *r, Mpint *n, Mpint *d)
|
|
|
|
{
|
2009-05-05 22:19:58 -06:00
|
|
|
int i, ns, ds;
|
|
|
|
|
|
|
|
ns = n->neg;
|
|
|
|
ds = d->neg;
|
|
|
|
n->neg = 0;
|
|
|
|
d->neg = 0;
|
2008-08-09 18:33:35 -06:00
|
|
|
|
|
|
|
mpmovefixfix(r, n);
|
|
|
|
mpmovecfix(q, 0);
|
|
|
|
|
|
|
|
// shift denominator until it
|
|
|
|
// is larger than numerator
|
|
|
|
for(i=0; i<Mpprec*Mpscale; i++) {
|
|
|
|
if(mpcmp(d, r) > 0)
|
|
|
|
break;
|
2012-02-15 16:19:42 -07:00
|
|
|
mplsh(d, 1);
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// if it never happens
|
|
|
|
// denominator is probably zero
|
|
|
|
if(i >= Mpprec*Mpscale) {
|
|
|
|
q->ovf = 1;
|
|
|
|
r->ovf = 1;
|
2009-05-05 22:19:58 -06:00
|
|
|
n->neg = ns;
|
|
|
|
d->neg = ds;
|
2012-02-10 22:50:56 -07:00
|
|
|
yyerror("constant division overflow");
|
2008-08-09 18:33:35 -06:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// shift denominator back creating
|
|
|
|
// quotient a bit at a time
|
|
|
|
// when done the remaining numerator
|
|
|
|
// will be the remainder
|
|
|
|
for(; i>0; i--) {
|
2012-02-15 16:19:42 -07:00
|
|
|
mplsh(q, 1);
|
2008-08-09 18:33:35 -06:00
|
|
|
mprsh(d);
|
|
|
|
if(mpcmp(d, r) <= 0) {
|
|
|
|
mpaddcfix(q, 1);
|
|
|
|
mpsubfixfix(r, d);
|
|
|
|
}
|
|
|
|
}
|
2009-05-05 22:19:58 -06:00
|
|
|
|
|
|
|
n->neg = ns;
|
|
|
|
d->neg = ds;
|
|
|
|
r->neg = ns;
|
|
|
|
q->neg = ns^ds;
|
2008-08-09 18:33:35 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 12:24:51 -06:00
|
|
|
static int
|
2010-02-05 16:18:32 -07:00
|
|
|
iszero(Mpint *a)
|
|
|
|
{
|
|
|
|
long *a1;
|
|
|
|
int i;
|
|
|
|
a1 = &a->a[0] + Mpprec;
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
if(*--a1 != 0)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2008-12-01 18:22:05 -07:00
|
|
|
void
|
|
|
|
mpdivfract(Mpint *a, Mpint *b)
|
|
|
|
{
|
|
|
|
Mpint n, d;
|
|
|
|
int i, j, neg;
|
|
|
|
long *a1, x;
|
|
|
|
|
|
|
|
mpmovefixfix(&n, a); // numerator
|
|
|
|
mpmovefixfix(&d, b); // denominator
|
|
|
|
a1 = &a->a[Mpprec]; // quotient
|
|
|
|
|
|
|
|
neg = n.neg ^ d.neg;
|
|
|
|
n.neg = 0;
|
|
|
|
d.neg = 0;
|
|
|
|
for(i=0; i<Mpprec; i++) {
|
|
|
|
x = 0;
|
|
|
|
for(j=0; j<Mpscale; j++) {
|
|
|
|
x <<= 1;
|
|
|
|
if(mpcmp(&d, &n) <= 0) {
|
2010-02-05 16:18:32 -07:00
|
|
|
if(!iszero(&d))
|
|
|
|
x |= 1;
|
2008-12-01 18:22:05 -07:00
|
|
|
mpsubfixfix(&n, &d);
|
|
|
|
}
|
|
|
|
mprsh(&d);
|
|
|
|
}
|
|
|
|
*--a1 = x;
|
|
|
|
}
|
|
|
|
a->neg = neg;
|
|
|
|
}
|
|
|
|
|
2008-08-09 18:33:35 -06:00
|
|
|
int
|
|
|
|
mptestfix(Mpint *a)
|
|
|
|
{
|
|
|
|
Mpint b;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
mpmovecfix(&b, 0);
|
|
|
|
r = mpcmp(a, &b);
|
|
|
|
if(a->neg) {
|
|
|
|
if(r > 0)
|
|
|
|
return -1;
|
|
|
|
if(r < 0)
|
|
|
|
return +1;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|