Ejemplo n.º 1
0
void
mpmovefixflt(Mpflt *a, Mpint *b)
{
	a->val = *b;
	a->exp = 0;
	mpnorm(a);
}
Ejemplo n.º 2
0
int
mpmovefltfix(Mpint *a, Mpflt *b)
{
	Mpflt f;
	int i;

	if(mpexactfltfix(a, b) == 0)
		return 0;

	// try rounding down a little
	f = *b;
	f.val.a[0] = 0;
	if(mpexactfltfix(a, &f) == 0)
		return 0;

	// try rounding up a little
	for(i=1; i<Mpprec; i++) {
		f.val.a[i]++;
		if(f.val.a[i] != Mpbase)
			break;
		f.val.a[i] = 0;
	}
	mpnorm(&f);
	if(mpexactfltfix(a, &f) == 0)
		return 0;

	return -1;
}
Ejemplo n.º 3
0
// sum = abs(b1) + abs(b2), i.e., add the magnitudes
void
mpmagadd(mpint *b1, mpint *b2, mpint *sum)
{
	int m, n;
	mpint *t;

	// get the sizes right
	if(b2->top > b1->top){
		t = b1;
		b1 = b2;
		b2 = t;
	}
	n = b1->top;
	m = b2->top;
	if(n == 0){
		mpassign(mpzero, sum);
		return;
	}
	if(m == 0){
		mpassign(b1, sum);
		return;
	}
	mpbits(sum, (n+1)*Dbits);
	sum->top = n+1;

	mpvecadd(b1->p, n, b2->p, m, sum->p);
	sum->sign = 1;

	mpnorm(sum);
}
Ejemplo n.º 4
0
vlong
mptov(mpint *b)
{
	uvlong v;
	int s;

	if(b->top == 0)
		return (vlong) 0;

	mpnorm(b);
	if(b->top > VLDIGITS){
		if(b->sign > 0)
			return (vlong)MAXVLONG;
		else
			return (vlong)MINVLONG;
	}

	v = (uvlong) 0;
	for(s = 0; s < b->top; s++)
		v |= b->p[s]<<(s*sizeof(mpdigit)*8);

	if(b->sign > 0){
		if(v > MAXVLONG)
			v = MAXVLONG;
	} else {
		if(v > MINVLONG)
			v = MINVLONG;
		else
			v = -(vlong)v;
	}

	return (vlong)v;
}
Ejemplo n.º 5
0
// convert (truncate) b to a.
// return -1 (but still convert) if b was non-integer.
int
mpmovefltfix(Mpint *a, Mpflt *b)
{
	Mpflt f;
	*a = b->val;
	mpshiftfix(a, b->exp);
	if(b->exp < 0) {
		f.val = *a;
		f.exp = 0;
		mpnorm(&f);
		if(mpcmpfltflt(b, &f) != 0)
			return -1;
	}
	return 0;
}
Ejemplo n.º 6
0
/*
 * mpbmu_w
 *  computes the Barrett 'mu' coefficient
 *  needs workspace of (6*size+4) words
 */
void mpbmu_w(mpbarrett* b, mpw* wksp)
{
	register size_t size = b->size;
	register size_t shift;
	register mpw* divmod = wksp;
	register mpw* dividend = divmod+(size*2+2);
	register mpw* workspace = dividend+(size*2+1);

	/* normalize modulus before division */
	shift = mpnorm(size, b->modl);
	/* make the dividend, initialize first word to 1 (shifted); the rest is zero */
	*dividend = ((mpw) MP_LSBMASK << shift);
	mpzero(size*2, dividend+1);
	mpndivmod(divmod, size*2+1, dividend, size, b->modl, workspace);
	mpcopy(size+1, b->mu, divmod+1);
	/* de-normalize */
	mprshift(size, b->modl, shift);
}
Ejemplo n.º 7
0
uint64_t
mptouv(mpint *b)
{
	uint64_t v;
	int s;

	if(b->top == 0)
		return 0LL;

	mpnorm(b);
	if(b->top > VLDIGITS)
		return MAXVLONG;

	v = 0ULL;
	for(s = 0; s < b->top; s++)
		v |= (uint64_t)b->p[s]<<(s*sizeof(mpdigit)*8);

	return v;
}
Ejemplo n.º 8
0
void
mpmul(mpint *b1, mpint *b2, mpint *prod)
{
	mpint *oprod;

	oprod = nil;
	if(prod == b1 || prod == b2){
		oprod = prod;
		prod = mpnew(0);
	}

	prod->top = 0;
	mpbits(prod, (b1->top+b2->top+1)*Dbits);
	mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p);
	prod->top = b1->top+b2->top+1;
	prod->sign = b1->sign*b2->sign;
	mpnorm(prod);

	if(oprod != nil){
		mpassign(prod, oprod);
		mpfree(prod);
	}
}
Ejemplo n.º 9
0
//
// floating point input
// required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
//
void
mpatoflt(Mpflt *a, char *as)
{
	Mpflt b;
	int dp, c, f, ef, ex, eb, base;
	char *s, *start;

	while(*as == ' ' || *as == '\t')
		as++;

	/* determine base */
	s = as;
	base = -1;
	while(base == -1) {
		switch(*s++) {
		case '-':
		case '+':
			break;

		case '0':
			if(*s == 'x')
				base = 16;
			else
				base = 10;
			break;

		default:
			base = 10;
		}
	}

	s = as;
	dp = 0;		/* digits after decimal point */
	f = 0;		/* sign */
	ex = 0;		/* exponent */
	eb = 0;		/* binary point */

	mpmovecflt(a, 0.0);
	if(base == 16) {
		start = nil;
		for(;;) {
			c = *s;
			if(c == '-') {
				f = 1;
				s++;
			}
			else if(c == '+') {
				s++;
			}
			else if(c == '0' && s[1] == 'x') {
				s += 2;
				start = s;
			}
			else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
				s++;
			}
			else {
				break;
			}
		}
		if(start == nil)
			goto bad;

		mphextofix(&a->val, start, s-start);
		if(a->val.ovf)
			goto bad;
		a->exp = 0;
		mpnorm(a);
	}
	for(;;) {
		switch(c = *s++) {
		default:
			goto bad;

		case '-':
			f = 1;

		case ' ':
		case '\t':
		case '+':
			continue;

		case '.':
			if(base == 16)
				goto bad;
			dp = 1;
			continue;

		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '0':
			mpmulcflt(a, 10);
			mpaddcflt(a, c-'0');
			if(dp)
				dp++;
			continue;

		case 'P':
		case 'p':
			eb = 1;

		case 'E':
		case 'e':
			ex = 0;
			ef = 0;
			for(;;) {
				c = *s++;
				if(c == '+' || c == ' ' || c == '\t')
					continue;
				if(c == '-') {
					ef = 1;
					continue;
				}
				if(c >= '0' && c <= '9') {
					ex = ex*10 + (c-'0');
					if(ex > 1e8) {
						yyerror("constant exponent out of range: %s", as);
						errorexit();
					}
					continue;
				}
				break;
			}
			if(ef)
				ex = -ex;

		case 0:
			break;
		}
		break;
	}

	if(eb) {
		if(dp)
			goto bad;
		mpsetexp(a, a->exp+ex);
		goto out;
	}

	if(dp)
		dp--;
	if(mpcmpfltc(a, 0.0) != 0) {
		if(ex >= dp) {
			mppow10flt(&b, ex-dp);
			mpmulfltflt(a, &b);
		} else {
			// 4 approximates least_upper_bound(log2(10)).
			if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) {
				mpmovecflt(a, 0.0);
			}
			else {
				mppow10flt(&b, dp-ex);
				mpdivfltflt(a, &b);
			}
		}
	}

out:
	if(f)
		mpnegflt(a);
	return;

bad:
	yyerror("constant too large: %s", as);
	mpmovecflt(a, 0.0);
}
Ejemplo n.º 10
0
mpint*
mpfactorial(ulong n)
{
    int i;
    ulong k;
    unsigned cnt;
    int max, mmax;
    mpdigit p, pp[2];
    mpint *r, *s, *stk[31];

    cnt = 0;
    max = mmax = -1;
    p = 1;
    r = mpnew(0);
    for(k=2; k<=n; k++) {
        pp[0] = 0;
        pp[1] = 0;
        mpvecdigmuladd(&p, 1, (mpdigit)k, pp);
        if(pp[1] == 0)	/* !overflow */
            p = pp[0];
        else {
            cnt++;
            if((cnt & 1) == 0) {
                s = stk[max];
                mpbits(r, Dbits*(s->top+1+1));
                memset(r->p, 0, Dbytes*(s->top+1+1));
                mpvecmul(s->p, s->top, &p, 1, r->p);
                r->sign = 1;
                r->top = s->top+1+1;		/* XXX: norm */
                mpassign(r, s);
                for(i=4; (cnt & (i-1)) == 0; i=i<<1) {
                    mpmul(stk[max], stk[max-1], r);
                    mpassign(r, stk[max-1]);
                    max--;
                }
            } else {
                max++;
                if(max > mmax) {
                    mmax++;
                    if(max > nelem(stk))
                        abort();
                    stk[max] = mpnew(Dbits);
                }
                stk[max]->top = 1;
                stk[max]->p[0] = p;
            }
            p = (mpdigit)k;
        }
    }
    if(max < 0) {
        mpbits(r, Dbits);
        r->top = 1;
        r->sign = 1;
        r->p[0] = p;
    } else {
        s = stk[max--];
        mpbits(r, Dbits*(s->top+1+1));
        memset(r->p, 0, Dbytes*(s->top+1+1));
        mpvecmul(s->p, s->top, &p, 1, r->p);
        r->sign = 1;
        r->top = s->top+1+1;		/* XXX: norm */
    }

    while(max >= 0)
        mpmul(r, stk[max--], r);
    for(max=mmax; max>=0; max--)
        mpfree(stk[max]);
    mpnorm(r);
    return r;
}
Ejemplo n.º 11
0
void mp_real::mpadd(const mp_real &a, const mp_real &b, mp_real& c, int prec_words)
{
  /**
   * This routine adds MP numbers A and B to yield the MP sum C. It attempts
   * to include all significance of A and B in the result, up to the maximum
   * mantissa length MPNW.  Debug output starts with debug_level = 9. 
   * This is a new simplified version.
   *
   * D contains the intermediate results of addition before normalization.
   * The first 3 words of D have special meanings:
   *     d[0] : not accessed
   *     d[1] : sign and number of words in D
   *     d[2] : exponent
   * Before normalization, each word of D may have up to 53 bits and may be
   * negative. After normalization, each word is in [0, 2^mpnbt-1]
   */
  double db;
  int i, ia, ib, ish, ixa, ixb, ixd, na, nb;
  int m1, m2, m3, m4, m5, nsh;
  double *d;
  int nd; // number of actual words in d[]

  if (error_no != 0) {
    zero(c);
    return;
  }

  if (debug_level >= 9) {
    print_mpreal("MPADD a ", a);
    print_mpreal("MPADD b ", b);
  }
  
  ia = a[1] >= 0 ? 1 : -1;
  ib = b[1] >= 0 ? 1 : -1;
  na = std::min (static_cast<int>(std::abs(a[1])), prec_words); // number of words in A
  nb = std::min (static_cast<int>(std::abs(b[1])), prec_words); // number of words in B

  /* Check for zero inputs. */

  if (na == 0) {
    /* A is zero -- the result is B. */
    int num_words = std::min(nb, int(c[0])-FST_M);
    c[1] = ib > 0 ? num_words : -num_words;
    for (i = 2; i < num_words + FST_M; ++i) c[i] = b[i];
    return;
  } else if (nb == 0) {
    /* B is zero -- the result is A. */
    int num_words = std::min(na, int(c[0])-FST_M);
    c[1] = ia >= 0 ? num_words : -num_words; 
    for (i = 2; i < num_words + FST_M; ++i) c[i] = a[i];
    return;
  }

  // get ready for main part of routine.
  d = new double[prec_words+7];

  if (ia == ib) db = 1.0; //same signs - add
  else db = -1.0; // different signs - subtract

  ixa = static_cast<int>(a[2]);
  ixb = static_cast<int>(b[2]);
  ish = ixa - ixb;

  d[1] = 0.0;
  d[2] = 0.0;

  if (ish >= 0) { // |A| >= |B|
    // A has greater exponent than B, so B must be shifted to the right
    // to line up the radix point.
    
    m1 = std::min (na, ish);
    m2 = std::min (na, nb + ish);
    m3 = na;
    m4 = std::min (std::max (na, ish), prec_words + 1);
    m5 = std::min (std::max (na, nb + ish), prec_words + 1);
    //assert(m1<=m2 && m2<=m3 && m3<=m4 && m4<=m5);
    
    for (i = FST_M; i < m1 + FST_M; ++i)
      d[i] = a[i];
    
    if(db > 0) {//Addition
      for (i = m1 + FST_M; i < m2 + FST_M; ++i)
        d[i] = a[i] + b[i-ish];
      
      for (i = m2 + FST_M; i < m3 + FST_M; ++i)
        d[i] = a[i];
    
      for (i = m3 + FST_M; i < m4 + FST_M; ++i)
        d[i] = 0.0;
      
      for (i = m4 + FST_M; i < m5 + FST_M; ++i)
        d[i] = b[i-ish];
    } else {//Subtraction
      for (i = m1 + FST_M; i < m2 + FST_M; ++i)
        d[i] = a[i] - b[i-ish];
      
      for (i = m2 + FST_M; i < m3 + FST_M; ++i)
        d[i] = a[i];
    
      for (i = m3 + FST_M; i < m4 + FST_M; ++i)
        d[i] = 0.0;
      
      for (i = m4 + FST_M; i < m5 + FST_M; ++i)
        d[i] = - b[i-ish];
    }
    nd = m5;
    ixd = ixa;
    d[nd+3] = 0.0;
    d[nd+4] = 0.0;

  } else {
    // B has greater exponent than A, so A must be shifted to the right
    // to line up the radix point.
    
    nsh = -ish;
    m1 = std::min (nb, nsh);
    m2 = std::min (nb, na + nsh);
    m3 = nb;
    m4 = std::min (std::max (nb, nsh), prec_words + 1);
    m5 = std::min (std::max (nb, na + nsh), prec_words + 1);
    //assert(m1<=m2 && m2<=m3 && m3<=m4 && m4<=m5);
    
    if(db > 0) {//Addition
      for (i = FST_M; i < m1 + FST_M; ++i)
        d[i] = b[i];
      
      for (i = m1 + FST_M; i < m2 + FST_M; ++i)
        d[i] = a[i-nsh] + b[i];
      
      for (i = m2 + FST_M; i < m3 + FST_M; ++i)
        d[i] = b[i];

    } else {//Subtraction
      for (i = FST_M; i < m1 + FST_M; ++i)
        d[i] = - b[i];
      
      for (i = m1 + FST_M; i < m2 + FST_M; ++i)
        d[i] = a[i-nsh]  - b[i];
      
      for (i = m2 + FST_M; i < m3 + FST_M; ++i)
        d[i] = - b[i];
    }

    for (i = m3 + FST_M; i < m4 + FST_M; ++i)
      d[i] = 0.0;
    
    for (i = m4 + FST_M; i < m5 + FST_M; ++i)
      d[i] = a[i-nsh];
    
    nd = m5;
    ixd = ixb;
    d[nd+3] = 0.0;
    d[nd+4] = 0.0;
  }
  

  // Call mpnorm to fix up result and store in c.
  d[1] = ia >= 0 ? nd : -nd;
  d[2] = ixd;
  mpnorm(d, c, prec_words);

  delete [] (d);

  if (debug_level >= 9) print_mpreal("MPADD O: c ", c);
  return;
}
Ejemplo n.º 12
0
Archivo: mpdiv.c Proyecto: 8l/inferno
void
mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder)
{
	int j, s, vn, sign;
	mpdigit qd, *up, *vp, *qp;
	mpint *u, *v, *t;

	// divide bv zero
	if(divisor->top == 0)
		sysfatal("mpdiv: divide by zero");

	// quick check
	if(mpmagcmp(dividend, divisor) < 0){
		if(remainder != nil)
			mpassign(dividend, remainder);
		if(quotient != nil)
			mpassign(mpzero, quotient);
		return;
	}

	// D1: shift until divisor, v, has hi bit set (needed to make trial
	//     divisor accurate)
	qd = divisor->p[divisor->top-1];
	for(s = 0; (qd & mpdighi) == 0; s++)
		qd <<= 1;
	u = mpnew((dividend->top+2)*Dbits + s);
	if(s == 0 && divisor != quotient && divisor != remainder) {
		mpassign(dividend, u);
		v = divisor;
	} else {
		mpleft(dividend, s, u);
		v = mpnew(divisor->top*Dbits);
		mpleft(divisor, s, v);
	}
	up = u->p+u->top-1;
	vp = v->p+v->top-1;
	vn = v->top;

	// D1a: make sure high digit of dividend is less than high digit of divisor
	if(*up >= *vp){
		*++up = 0;
		u->top++;
	}

	// storage for multiplies
	t = mpnew(4*Dbits);

	qp = nil;
	if(quotient != nil){
		mpbits(quotient, (u->top - v->top)*Dbits);
		quotient->top = u->top - v->top;
		qp = quotient->p+quotient->top-1;
	}

	// D2, D7: loop on length of dividend
	for(j = u->top; j > vn; j--){

		// D3: calculate trial divisor
		mpdigdiv(up-1, *vp, &qd);

		// D3a: rule out trial divisors 2 greater than real divisor
		if(vn > 1) for(;;){
			memset(t->p, 0, 3*Dbytes);	// mpvecdigmuladd adds to what's there
			mpvecdigmuladd(vp-1, 2, qd, t->p);
			if(mpveccmp(t->p, 3, up-2, 3) > 0)
				qd--;
			else
				break;
		}

		// D4: u -= v*qd << j*Dbits
		sign = mpvecdigmulsub(v->p, vn, qd, up-vn);
		if(sign < 0){

			// D6: trial divisor was too high, add back borrowed
			//     value and decrease divisor
			mpvecadd(up-vn, vn+1, v->p, vn, up-vn);
			qd--;
		}

		// D5: save quotient digit
		if(qp != nil)
			*qp-- = qd;

		// push top of u down one
		u->top--;
		*up-- = 0;
	}
	if(qp != nil){
		mpnorm(quotient);
		if(dividend->sign != divisor->sign)
			quotient->sign = -1;
	}

	if(remainder != nil){
		mpright(u, s, remainder);	// u is the remainder shifted
		remainder->sign = dividend->sign;
	}

	mpfree(t);
	mpfree(u);
	if(v != divisor)
		mpfree(v);
}