📄 big.c
字号:
/* ``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 + -