⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 big.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "big.h"#include "error.h"#include "bif.h"/*** compare two number vectors** 32OK*/static int I_comp(digit_t* x, dsize_t xl, digit_t* y, dsize_t yl){    if (xl < yl)	return -1;    else if (xl > yl)	return 1;    else {	if (x == y)	    return 0;	x += (xl-1);	y += (yl-1);	while(xl > 0 && (*x == *y)) {	    x--;	    y--;	    xl--;	}	if (xl == 0)	    return 0;	return (*x < *y) ? -1 : 1;    }}/*** Add digits in x and y and store them in r** assumption: (xl >= yl)** 32OK*/static dsize_t I_add(digit_t* x, dsize_t xl, digit_t* y, dsize_t yl, digit_t* r){    dsize_t sz = xl;    register digit_t yr, xr;    register digit_t c = 0;    ASSERT(xl >= yl);    xl -= yl;    do {	xr = *x++ + c;	yr = *y++;	c = (xr < c);	xr = yr + xr;	c += (xr < yr);	*r++ = xr;    } while(--yl);    while(xl--) {	xr = *x++ + c;	c = (xr < c);	*r++ = xr;    }    if (c) {	*r = 1;	return sz+1;    }    return sz;}/*** Add a digits in v1 and store result in vr** 32OK*/static dsize_t D_add(digit_t* x, dsize_t xl, digit_t c, digit_t* r){    dsize_t sz = xl;    register digit_t xr;    while(xl--) {	xr = *x++ + c;	c = (xr < c);	*r++ = xr;    }    if (c) {	*r = 1;	return sz+1;    }    return sz;}/*** Subtract digits v2 from v1 and store result in v3** Assert  I_comp(x, xl, y, yl) >= 0**** 32OK*/static dsize_t I_sub(digit_t* x, dsize_t xl, digit_t* y, dsize_t yl, digit_t* r){    digit_t* r0 = r;    register digit_t yr, xr;    register digit_t c = 0;    ASSERT(I_comp(x, xl, y, yl) >= 0);    xl -= yl;    do {	yr = *y++ + c;	xr = *x++;	c = (yr < c);	yr = xr - yr;	c += (yr > xr);	*r++ = yr;    } while(--yl);    while(xl--) {	xr = *x++;	yr = xr - c;	c = (yr > xr);	*r++ = yr;    }    do {	r--;    } while(*r == 0 && r != r0);    return (r - r0) + 1;}/*** Subtract digit d from v1 and store result in vr** 32OK*/static dsize_t D_sub(digit_t* x, dsize_t xl, digit_t c, digit_t* r){    digit_t* r0 = r;    register digit_t yr, xr;    ASSERT(I_comp(x, xl, x, 1) >= 0);    while(xl--) {	xr = *x++;	yr = xr - c;	c = (yr > xr);	*r++ = yr;    }    do {	r--;    } while(*r == 0 && r != r0);    return (r - r0) + 1;}/*** subtract Z000...0 - y and store result in r, return new size** 32OK*/static dsize_t Z_sub(digit_t* y, dsize_t yl, digit_t* r){    digit_t* r0 = r;    register digit_t yr;    register digit_t c = 0;    while(yl--) {	yr = *y++ + c;	c = (yr < c);	yr = 0 - yr;	c += (yr > 0);	*r++ = yr;    }    do {	r--;    } while(*r == 0 && r != r0);    return (r - r0) + 1;}/*** Multiply digits in x with digits in y and store in r** Assumption: digits in r must be 0 (upto the size of x)** 32UPDATE*/static dsize_t I_mul(digit_t* x, dsize_t xl, digit_t* y, dsize_t yl, digit_t* r){    digit_t* r0 = r;    digit_t* rt = r;    while(xl--) {	digit_t cp = 0;	digit_t c = 0;	dsize_t n = yl;	digit_t* yt = y;	digit_t d;	digit_t p;	d = *x; 	x++;	rt = r;	switch(d) {	case 0:	    rt = rt + n;	    break;	case 1:	    while(n--) {		DSUMc(*yt, *rt, c, p);		*rt++ = p;		yt++;	    }	    break;	case 2:	    while(n--) {		p = *yt;		DSUMc(p, p, cp, p);		DSUMc(p, *rt, c, p);		*rt++ = p;		yt++;	    }	    break;	default:	    while(n--) {		DMULc(d,*yt, cp, p);		DSUMc(p,*rt, c, p);		*rt++ = p;		yt++;	    }	    break;	}	*rt = c + cp;	r++;    }    if (*rt == 0)	return (rt - r0);    else	return (rt - r0) + 1;}/*** Square digits in x store in r (x & r may point into a common area)** Assumption: x is destroyed if common area and digits in r are zero**             to the size of xl+1** 32UPDATE*/static dsize_t I_sqr(digit_t* x, dsize_t xl, digit_t* r){    digit_t d_next = *x;    digit_t d;    digit_t* r0 = r;    digit_t* s = r;    if ((r + xl) == x)	/* "Inline" operation */	*x = 0;    x++;	    while(xl--) {	digit_t* y = x;	digit_t y_0 = 0, y_1 = 0, y_2 = 0, y_3 = 0;	digit_t b0, b1;	digit_t z0, z1, z2;	digit_t t;	dsize_t y_l = xl;			s = r;	d = d_next;	d_next = *x; 	x++;	DMUL(d, d, b1, b0);	DSUMc(*s, b0, y_3, t);	*s++ = t;	z1 = b1;	while(y_l--) {	    DMUL(d, *y, b1, b0);	    y++;	    DSUMc(b0, b0, y_0, z0);	    DSUMc(z0, z1, y_2, z2);	    DSUMc(*s, z2, y_3, t);	    *s++ = t;	    DSUMc(b1, b1, y_1, z1);	}	z0 = y_0;	DSUMc(z0, z1, y_2, z2);	DSUMc(*s, z2, y_3, t);	*s = t;	if (xl != 0) {	    s++;	    t = (y_1+y_2+y_3);	    *s = t;	    r += 2;	}	else {	    ASSERT((y_1+y_2+y_3) == 0);	}    }    if (*s == 0)	return (s - r0);    else	return (s - r0) + 1;}/*** Multiply digits d with digits in x and store in r** 32UPDATE*/static dsize_t D_mul(digit_t* x, dsize_t xl, digit_t d, digit_t* r){    digit_t c = 0;    dsize_t rl = xl;    digit_t p;    switch(d) {    case 0:	ZERO_DIGITS(r, 1);	return 1;    case 1:	if (x != r)	    MOVE_DIGITS(r, x, xl);	return xl;    case 2:	while(xl--) {	    p = *x;	    DSUMc(p, p, c, p);	    *r++ = p;	    x++;	}	break;    default:	while(xl--) {	    DMULc(d, *x, c, p);	    *r++ = p;	    x++;	}	break;    }    if (c == 0)	return rl;    *r = c;    return rl+1;}/*** Multiply and subtract** calculate r(i) = x(i) - d*y(i)** assumption: xl = yl || xl == yl+1**** Return size of r** 0 means borrow** 32UPDATE*/static dsize_t D_mulsub(digit_t* x, dsize_t xl, digit_t d,			digit_t* y, dsize_t yl, digit_t* r){    digit_t c = 0;    digit_t b = 0;    digit_t c0;    digit_t* r0 = r;    digit_t s;    ASSERT(xl == yl || xl == yl+1);    xl -= yl;    while(yl--) {	DMULc(d, *y, c, c0);	DSUBb(*x, c0, b, s);	*r++ = s;	x++;	y++;    }    if (xl == 0) {	if (c != 0 || b != 0)	    return 0;    }    else {			/* xl == 1 */	DSUBb(*x, c, b, s);	*r++ = s;    }    if (b != 0) return 0;    do {	r--;    } while(*r == 0 && r != r0);    return (r - r0) + 1;}/*** Divide digits in x with a digit,** quotient is returned in q and remainder digit in r** x and q may be equal** 32UPDATE*/static dsize_t D_div(digit_t* x, dsize_t xl, digit_t d, digit_t* q, digit_t* r){    digit_t* xp = x + (xl-1);    digit_t* qp = q + (xl-1);    dsize_t qsz = xl;    digit_t a1;	    a1 = *xp;     xp--;    if (d > a1) {	if (xl == 1) {	    *r = a1;	    *qp = 0;	    return 1;	}	qsz--;	qp--;    }    do {	digit_t q0, a0, b1, b0, b;	if (d > a1) {	    a0 = *xp; 	    xp--;	}	else {	    a0 = a1; a1 = 0;	}	DDIV(a1, a0, d, q0);	DMUL(d, q0, b1, b0);	DSUB(a0,b0, b, a1);	*qp = q0;	qp--;    } while (xp >= x);    *r = a1;    return qsz;}/*** Divide digits in x with digits in y and return qutient in q** and remainder in r** assume that integer(x) > integer(y)** Return remainder in x (length int rl)** Return quotient size** 32UPDATE*/static dsize_t I_div(digit_t* x, dsize_t xl, digit_t* y, dsize_t yl,		     digit_t* q, digit_t* r, dsize_t* rlp){    digit_t* rp;    digit_t* qp;    digit_t b1 = y[yl-1];    digit_t b2 = y[yl-2];    digit_t a1;    digit_t a2;    int r_signed = 0;    dsize_t ql;    dsize_t rl;    if (x != r)	MOVE_DIGITS(r, x, xl);    rp = r + (xl-yl);    rl = xl;	    ZERO_DIGITS(q, xl-yl+1);    qp = q + (xl-yl);    ql = 0;	    /* Adjust length */    a1 = rp[yl-1];    a2 = rp[yl-2];    if (b1 < a1 || (b1 == a1 && b2 <= a2))	ql = 1;    do {	digit_t q0;	dsize_t nsz = yl;	dsize_t nnsz;	a1 = rp[yl-1];	a2 = rp[yl-2];	if (b1 < a1)	    DDIV2(a1,a2,b1,b2,q0);	else if (b1 > a1) {	    DDIV(a1,a2,b1,q0);	    nsz++;	    rp--;	    qp--;	    ql++;	}	else {			/* (b1 == a1) */	    if (b2 <= a2)		q0 = 1;	    else {		q0 = D_BASE-1;		nsz++;		rp--;		qp--;		ql++;	    }	}	if (r_signed)	    ql = D_sub(qp, ql, q0, qp);	else	    ql = D_add(qp, ql, q0, qp);	if ((nnsz = D_mulsub(rp, nsz, q0, y, yl, rp)) == 0) {	    nnsz = Z_sub(r, rl, r);	    if (nsz > (rl-nnsz))		nnsz = nsz - (rl-nnsz);	    else		nnsz = 1;	    r_signed = !r_signed;	}			if ((nnsz == 1) && (*rp == 0))	    nnsz = 0;	rp = rp - (yl-nnsz);	rl -= (nsz-nnsz);	qp = qp - (yl-nnsz);	ql += (yl-nnsz);    } while (I_comp(r, rl, y, yl) >= 0);    ql -= (q - qp);    qp = q;    if (rl == 0)	rl = 1;    while(rl > 1 && r[rl-1] == 0) /* Remove "trailing zeroes" */      --rl;    if (r_signed && (rl > 1 || *r != 0)) {	rl = I_sub(y, yl, r, rl, r);	ql = D_sub(qp, ql, 1, qp);    }    *rlp = rl;    return ql;}/*** Remainder of digits in x and a digit d** 32UPDATE*/static digit_t D_rem(digit_t* x, dsize_t xl, digit_t d){    digit_t rem = 0;    x += (xl-1);    do {	if (rem != 0)	    DREM(rem, *x, d, rem);	else	    DREM(0, *x, d, rem);	x--;	xl--;    } while(xl > 0);    return rem;}/*** Remainder of x and y**** Assumtions: xl >= yl, yl > 1**			   r must contain at least xl number of digits** 32UPDATE*/static dsize_t I_rem(digit_t* x, dsize_t xl, digit_t* y, dsize_t yl, digit_t* r){    digit_t* rp;    digit_t b1 = y[yl-1];    digit_t b2 = y[yl-2];    digit_t a1;    digit_t a2;    int r_signed = 0;    dsize_t rl;	    if (x != r)	MOVE_DIGITS(r, x, xl);    rp = r + (xl-yl);    rl = xl;    do {	digit_t q0;	dsize_t nsz = yl;	dsize_t nnsz;			a1 = rp[yl-1];	a2 = rp[yl-2];	if (b1 < a1)	    DDIV2(a1,a2,b1,b2,q0);	else if (b1 > a1) {	    DDIV(a1,a2,b1,q0);	    nsz++;	    rp--;	}	else {			/* (b1 == a1) */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -