picolisp

Unnamed repository; edit this file to name it for gitweb.
git clone https://logand.com/git/picolisp.git/
Log | Files | Refs | README | LICENSE

big.c (27268B)


      1 /* 08sep11abu
      2  * (c) Software Lab. Alexander Burger
      3  */
      4 
      5 #include "pico.h"
      6 
      7 #define MAX    MASK           // Max digit size    0xFFFF....
      8 #define OVFL   ((1<<BITS-1))  // Carry/Overflow    0x8000....
      9 
     10 
     11 static void divErr(any ex) {err(ex,NULL,"Div/0");}
     12 
     13 /* Box double word */
     14 any boxWord2(word2 t) {
     15    cell c1;
     16 
     17    Push(c1, hi(t)? consNum(num(t), box(hi(t))) : box(num(t)));
     18    digMul2(data(c1));
     19    return Pop(c1);
     20 }
     21 
     22 word2 unBoxWord2(any x) {
     23    word2 n = unDig(x);
     24 
     25    if (isNum(x = cdr(numCell(x))))
     26       n = n << BITS + unDig(x);
     27    return n / 2;
     28 }
     29 
     30 /* Bignum copy */
     31 any bigCopy(any x) {
     32    any y;
     33    cell c1, c2;
     34 
     35    Push(c1, x);
     36    Push(c2, y = box(unDig(x)));
     37    while (isNum(x = cdr(numCell(x))))
     38       y = cdr(numCell(y)) = box(unDig(x));
     39    drop(c1);
     40    return data(c2);
     41 }
     42 
     43 /* Remove leading zero words */
     44 void zapZero(any x) {
     45    any r = x;
     46 
     47    while (isNum(x = cdr(numCell(x))))
     48       if (unDig(x))
     49          r = x;
     50    cdr(numCell(r)) = x;
     51 }
     52 
     53 /* Multiply a (positive) bignum by 2 */
     54 void digMul2(any x) {
     55    any y;
     56    word n, carry;
     57 
     58    n = unDig(x),  setDig(x, n + n),  carry = n & OVFL;
     59    while (isNum(x = cdr(numCell(y = x)))) {
     60       n = unDig(x);
     61       setDig(x, n + n + (carry? 1 : 0));
     62       carry = n & OVFL;
     63    }
     64    if (carry)
     65       cdr(numCell(y)) = box(1);
     66 }
     67 
     68 /* Shift right by one bit */
     69 void digDiv2(any x) {
     70    any r, y;
     71 
     72    r = NULL;
     73    setDig(x, unDig(x) / 2);
     74    while (isNum(x = cdr(numCell(y = x)))) {
     75       if (unDig(x) & 1)
     76          setDig(y, unDig(y) | OVFL);
     77       setDig(x, unDig(x) / 2);
     78       r = y;
     79    }
     80    if (r  &&  unDig(y) == 0)
     81       cdr(numCell(r)) = x;
     82 }
     83 
     84 /* Add two (positive) bignums */
     85 void bigAdd(any dst, any src) {
     86    any x;
     87    word n, carry;
     88 
     89    carry = (unDig(src) & ~1) > num(setDig(dst, (unDig(src) & ~1) + (unDig(dst) & ~1)));
     90    src = cdr(numCell(src));
     91    dst = cdr(numCell(x = dst));
     92    for (;;) {
     93       if (!isNum(src)) {
     94          while (isNum(dst)) {
     95             if (!carry)
     96                return;
     97             carry = 0 == num(setDig(dst, 1 + unDig(dst)));
     98             dst = cdr(numCell(x = dst));
     99          }
    100          break;
    101       }
    102       if (!isNum(dst)) {
    103          do {
    104             carry = unDig(src) > (n = carry + unDig(src));
    105             x = cdr(numCell(x)) = box(n);
    106          } while (isNum(src = cdr(numCell(src))));
    107          break;
    108       }
    109       if ((n = carry + unDig(src)) >= carry) {
    110          carry = unDig(dst) > (n += unDig(dst));
    111          setDig(dst,n);
    112       }
    113       src = cdr(numCell(src));
    114       dst = cdr(numCell(x = dst));
    115    }
    116    if (carry)
    117       cdr(numCell(x)) = box(1);
    118 }
    119 
    120 /* Add digit to a (positive) bignum */
    121 void digAdd(any x, word n) {
    122    any y;
    123    word carry;
    124 
    125    carry = n > num(setDig(x, n + unDig(x)));
    126    while (carry) {
    127       if (isNum(x = cdr(numCell(y = x))))
    128          carry = 0 == num(setDig(x, 1 + unDig(x)));
    129       else {
    130          cdr(numCell(y)) = box(1);
    131          break;
    132       }
    133    }
    134 }
    135 
    136 /* Subtract two (positive) bignums */
    137 void bigSub(any dst, any src) {
    138    any x, y;
    139    word n, borrow;
    140 
    141    borrow = MAX - (unDig(src) & ~1) < num(setDig(dst, (unDig(dst) & ~1) - (unDig(src) & ~1)));
    142    y = dst;
    143    for (;;) {
    144       src = cdr(numCell(src));
    145       dst = cdr(numCell(x = dst));
    146       if (!isNum(src)) {
    147          while (isNum(dst)) {
    148             if (!borrow)
    149                return;
    150             borrow = MAX == num(setDig(dst, unDig(dst) - 1));
    151             dst = cdr(numCell(x = dst));
    152          }
    153          break;
    154       }
    155       if (!isNum(dst)) {
    156          do {
    157             if (borrow)
    158                n = MAX - unDig(src);
    159             else
    160                borrow = 0 != (n = -unDig(src));
    161             x = cdr(numCell(x)) = box(n);
    162          } while (isNum(src = cdr(numCell(src))));
    163          break;
    164       }
    165       if ((n = unDig(dst) - borrow) > MAX - borrow)
    166          setDig(dst, MAX - unDig(src));
    167       else
    168          borrow = num(setDig(dst, n - unDig(src))) > MAX - unDig(src);
    169    }
    170    if (borrow) {
    171       dst = y;
    172       borrow = 0 != (n = -unDig(dst));
    173       setDig(dst, n | 1);  /* Negate */
    174       while (dst != x) {
    175          dst = cdr(numCell(dst));
    176          if (borrow)
    177             setDig(dst, MAX - unDig(dst));
    178          else
    179             borrow = 0 != num(setDig(dst, -unDig(dst)));
    180       }
    181    }
    182    if (unDig(x) == 0)
    183       zapZero(y);
    184 }
    185 
    186 /* Subtract 1 from a (positive) bignum */
    187 void digSub1(any x) {
    188    any r, y;
    189    word borrow;
    190 
    191    r = NULL;
    192    borrow = MAX-1 == num(setDig(x, unDig(x) - 2));
    193    while (isNum(x = cdr(numCell(y = x)))) {
    194       if (!borrow)
    195          return;
    196       borrow = MAX == num(setDig(x, unDig(x) - 1));
    197       r = y;
    198    }
    199    if (r  &&  unDig(y) == 0)
    200       cdr(numCell(r)) = x;
    201 }
    202 
    203 /* Multiply two (positive) bignums */
    204 static any bigMul(any x1, any x2) {
    205    any x, y, z;
    206    word n, carry;
    207    word2 t;
    208    cell c1;
    209 
    210    Push(c1, x = y = box(0));
    211    for (;;) {
    212       n = unDig(x2) / 2;
    213       if (isNum(x2 = cdr(numCell(x2)))  &&  unDig(x2) & 1)
    214          n |= OVFL;
    215       t = (word2)n * unDig(z = x1);  // x += n * x1
    216       carry = (lo(t) > num(setDig(y, unDig(y) + lo(t)))) + hi(t);
    217       while (isNum(z = cdr(numCell(z)))) {
    218          if (!isNum(cdr(numCell(y))))
    219             cdr(numCell(y)) = box(0);
    220          y = cdr(numCell(y));
    221          t = (word2)n * unDig(z);
    222          carry = carry > num(setDig(y, carry + unDig(y)));
    223          if (lo(t) > num(setDig(y, unDig(y) + lo(t))))
    224             ++carry;
    225          carry += hi(t);
    226       }
    227       if (carry)
    228          cdr(numCell(y)) = box(carry);
    229       if (!isNum(x2))
    230          break;
    231       if (!isNum(y = cdr(numCell(x))))
    232          y = cdr(numCell(x)) = box(0);
    233       x = y;
    234    } while (isNum(x2));
    235    zapZero(data(c1));
    236    return Pop(c1);
    237 }
    238 
    239 /* Multiply digit with a (positive) bignum */
    240 void digMul(any x, word n) {
    241    word2 t;
    242    any y;
    243 
    244    t = (word2)n * unDig(x);
    245    for (;;) {
    246       setDig(x, num(t));
    247       t = hi(t);
    248       if (!isNum(x = cdr(numCell(y = x))))
    249          break;
    250       t += (word2)n * unDig(x);
    251    }
    252    if (t)
    253       cdr(numCell(y)) = box(num(t));
    254 }
    255 
    256 /* (Positive) Bignum comparison */
    257 static int bigCmp(any x, any y) {
    258    int res;
    259    any x1, y1, x2, y2;
    260 
    261    x1 = y1 = Nil;
    262    for (;;) {
    263       if ((x2 = cdr(numCell(x))) == (y2 = cdr(numCell(y)))) {
    264          for (;;) {
    265             if (unDig(x) < unDig(y)) {
    266                res = -1;
    267                break;
    268             }
    269             if (unDig(x) > unDig(y)) {
    270                res = +1;
    271                break;
    272             }
    273             if (!isNum(x1))
    274                return 0;
    275             x2 = cdr(numCell(x1)),  cdr(numCell(x1)) = x,  x = x1,  x1 = x2;
    276             y2 = cdr(numCell(y1)),  cdr(numCell(y1)) = y,  y = y1,  y1 = y2;
    277          }
    278          break;
    279       }
    280       if (!isNum(x2)) {
    281          res = -1;
    282          break;
    283       }
    284       if (!isNum(y2)) {
    285          res = +1;
    286          break;
    287       }
    288       cdr(numCell(x)) = x1,  x1 = x,  x = x2;
    289       cdr(numCell(y)) = y1,  y1 = y,  y = y2;
    290    }
    291    while (isNum(x1)) {
    292       x2 = cdr(numCell(x1)),  cdr(numCell(x1)) = x,  x = x1,  x1 = x2;
    293       y2 = cdr(numCell(y1)),  cdr(numCell(y1)) = y,  y = y1,  y1 = y2;
    294    }
    295    return res;
    296 }
    297 
    298 /* Divide two (positive) bignums (Knuth Vol.2, p.257) */
    299 static any bigDiv(any u, any v, bool rem) {
    300    int m, n, d, i;
    301    word q, v1, v2, u1, u2, u3, borrow;
    302    word2 t, r;
    303    any x, y, z;
    304    cell c1;
    305 
    306    digDiv2(u),  digDiv2(v);                                 // Normalize
    307    for (m = 0, z = u;  isNum(y = cdr(numCell(z)));  ++m, z = y);
    308    x = v,  y = NULL,  n = 1;
    309    while (isNum(cdr(numCell(x))))
    310       y = x,  x = cdr(numCell(x)),  ++n,  --m;
    311    if (m < 0) {
    312       if (rem)
    313          digMul2(u);
    314       return box(0);
    315    }
    316    cdr(numCell(z)) = box(0);
    317    for (d = 0;  (unDig(x) & OVFL) == 0;  ++d)
    318       digMul2(u),  digMul2(v);
    319    v1 = unDig(x);
    320    v2 = y? unDig(y) : 0;
    321    Push(c1, Nil);
    322    do {
    323       for (i = m, x = u;  --i >= 0;  x = cdr(numCell(x)));  // Index x -> u
    324       i = n;
    325       y = x;
    326       u1 = u2 = 0;
    327       do
    328          u3 = u2,  u2 = u1,  u1 = unDig(y),  y = cdr(numCell(y));
    329       while (--i >= 0);
    330 
    331       t = ((word2)u1 << BITS) + u2;                         // Calculate q
    332       q = u1 == v1? MAX : t / v1;
    333       r = t - (word2)q*v1;
    334       while (r <= MAX  &&  (word2)q*v2 > (r << BITS) + u3)
    335          --q,  r += v1;
    336 
    337       z = x;                                                // x -= q*v
    338       t = (word2)q * unDig(y = v);
    339       borrow = (MAX - lo(t) < num(setDig(z, unDig(z) - lo(t)))) + hi(t);
    340       while (isNum(y = cdr(numCell(y)))) {
    341          z = cdr(numCell(z));
    342          t = (word2)q * unDig(y);
    343          borrow = MAX - borrow < num(setDig(z, unDig(z) - borrow));
    344          if (MAX - lo(t) < num(setDig(z, unDig(z) - lo(t))))
    345             ++borrow;
    346          borrow += hi(t);
    347       }
    348       if (borrow) {
    349          z = cdr(numCell(z));
    350          if (MAX - borrow < num(setDig(z, unDig(z) - borrow))) {
    351             word n, carry;                                  // x += v
    352 
    353             --q;
    354             if (m || rem) {
    355                y = v;
    356                carry = unDig(y) > num(setDig(x, unDig(y) + unDig(x)));
    357                while (x = cdr(numCell(x)),  isNum(y = cdr(numCell(y)))) {
    358                   if ((n = carry + unDig(y)) >= carry) {
    359                      carry = unDig(x) > (n += unDig(x));
    360                      setDig(x,n);
    361                   }
    362                }
    363                setDig(x, carry + unDig(x));
    364             }
    365          }
    366       }
    367       data(c1) = consNum(q, data(c1));                      // Store result
    368    } while (--m >= 0);
    369    if (!rem)
    370       zapZero(data(c1)),  digMul2(data(c1));
    371    else {
    372       zapZero(u);
    373       if (!d)
    374          digMul2(u);
    375       else
    376          while (--d)
    377             digDiv2(u);
    378    }
    379    return Pop(c1);
    380 }
    381 
    382 /* Compare two numbers */
    383 int bigCompare(any x, any y) {
    384    if (isNeg(x)) {
    385       if (!isNeg(y))
    386          return -1;
    387       return bigCmp(y,x);
    388    }
    389    if (isNeg(y))
    390       return +1;
    391    return bigCmp(x,y);
    392 }
    393 
    394 /* Make number from symbol */
    395 any symToNum(any s, int scl, int sep, int ign) {
    396    unsigned c;
    397    bool sign, frac;
    398    cell c1, c2;
    399 
    400    if (!(c = symByte(s)))
    401       return NULL;
    402    while (c <= ' ')  /* Skip white space */
    403       if (!(c = symByte(NULL)))
    404          return NULL;
    405    sign = NO;
    406    if (c == '+'  ||  c == '-' && (sign = YES))
    407       if (!(c = symByte(NULL)))
    408          return NULL;
    409    if ((c -= '0') > 9)
    410       return NULL;
    411    frac = NO;
    412    Push(c1, s);
    413    Push(c2, box(c+c));
    414    while ((c = symChar(NULL))  &&  (!frac || scl)) {
    415       if ((int)c == sep) {
    416          if (frac) {
    417             drop(c1);
    418             return NULL;
    419          }
    420          frac = YES;
    421       }
    422       else if ((int)c != ign) {
    423          if ((c -= '0') > 9) {
    424             drop(c1);
    425             return NULL;
    426          }
    427          digMul(data(c2), 10);
    428          digAdd(data(c2), c+c);
    429          if (frac)
    430             --scl;
    431       }
    432    }
    433    if (c) {
    434       if ((c -= '0') > 9) {
    435          drop(c1);
    436          return NULL;
    437       }
    438       if (c >= 5)
    439          digAdd(data(c2), 1+1);
    440       while (c = symByte(NULL)) {
    441          if ((c -= '0') > 9) {
    442             drop(c1);
    443             return NULL;
    444          }
    445       }
    446    }
    447    if (frac)
    448       while (--scl >= 0)
    449          digMul(data(c2), 10);
    450    if (sign && !IsZero(data(c2)))
    451       neg(data(c2));
    452    drop(c1);
    453    return data(c2);
    454 }
    455 
    456 /* Buffer size calculation */
    457 static inline int numlen(any x) {
    458    int n = 10;
    459    while (isNum(x = cdr(numCell(x))))
    460       n += 10;
    461    return (n + 8) / 9;
    462 }
    463 
    464 /* Make symbol from number */
    465 any numToSym(any x, int scl, int sep, int ign) {
    466    int i;
    467    bool sign;
    468    cell c1;
    469    word n = numlen(x);
    470    word c, *p, *q, *ta, *ti, acc[n], inc[n];
    471    char *b, buf[10];
    472 
    473    sign = isNeg(x);
    474    *(ta = acc) = 0;
    475    *(ti = inc) = 1;
    476    n = 2;
    477    for (;;) {
    478       do {
    479          if (unDig(x) & n) {
    480             c = 0,  p = acc,  q = inc;
    481             do {
    482                if (ta < p)
    483                   *++ta = 0;
    484                if (c = (*p += *q + c) > 999999999)
    485                   *p -= 1000000000;
    486             } while (++p, ++q <= ti);
    487             if (c)
    488                *p = 1,  ++ta;
    489          }
    490          c = 0,  q = inc;
    491          do
    492             if (c = (*q += *q + c) > 999999999)
    493                *q -= 1000000000;
    494          while (++q <= ti);
    495          if (c)
    496             *q = 1,  ++ti;
    497       } while (n <<= 1);
    498       if (!isNum(x = cdr(numCell(x))))
    499          break;
    500       n = 1;
    501    }
    502    n = (ta - acc) * 9;
    503    n += sprintf(b = buf, "%ld", *ta--);
    504    if (sep < 0)
    505       return boxCnt(n + sign);
    506    i = -8,  Push(c1, x = box(0));
    507    if (sign)
    508       byteSym('-', &i, &x);
    509    if ((scl = n - scl - 1) < 0) {
    510       byteSym('0', &i, &x);
    511       charSym(sep, &i, &x);
    512       while (scl < -1)
    513          byteSym('0', &i, &x),  ++scl;
    514    }
    515    for (;;) {
    516       byteSym(*b++, &i, &x);
    517       if (!*b) {
    518          if (ta < acc)
    519             return consStr(Pop(c1));
    520          sprintf(b = buf, "%09ld", *ta--);
    521       }
    522       if (scl == 0)
    523          charSym(sep, &i, &x);
    524       else if (ign  &&  scl > 0  &&  scl % 3 == 0)
    525          charSym(ign, &i, &x);
    526       --scl;
    527    }
    528 }
    529 
    530 #define DMAX ((double)((word2)MASK+1))
    531 
    532 /* Make number from double */
    533 any doubleToNum(double d) {
    534    bool sign;
    535    any x;
    536    cell c1;
    537 
    538    if (isnan(d) || isinf(d) < 0)
    539       return Nil;
    540    if (isinf(d) > 0)
    541       return T;
    542    sign = NO;
    543    if (d < 0.0)
    544       sign = YES,  d = -d;
    545    d += 0.5;
    546    Push(c1, x = box((word)fmod(d,DMAX)));
    547    while (d > DMAX)
    548       x = cdr(numCell(x)) = box((word)fmod(d /= DMAX, DMAX));
    549    digMul2(data(c1));
    550    if (sign && !IsZero(data(c1)))
    551       neg(data(c1));
    552    return Pop(c1);
    553 }
    554 
    555 /* Make double from number */
    556 double numToDouble(any x) {
    557    double d, m;
    558    bool sign;
    559 
    560    sign = isNeg(x);
    561    d = (double)(unDig(x) / 2),  m = DMAX/2.0;
    562    while (isNum(x = cdr(numCell(x))))
    563       d += m * (double)unDig(x),  m *= DMAX;
    564    return sign? -d : d;
    565 }
    566 
    567 // (format 'num ['cnt ['sym1 ['sym2]]]) -> sym
    568 // (format 'sym|lst ['cnt ['sym1 ['sym2]]]) -> num
    569 any doFormat(any ex) {
    570    int scl, sep, ign;
    571    any x, y;
    572    cell c1;
    573 
    574    x = cdr(ex),  Push(c1, EVAL(car(x)));
    575    x = cdr(x),  y = EVAL(car(x));
    576    scl = isNil(y)? 0 : xCnt(ex, y);
    577    sep = '.';
    578    ign = 0;
    579    if (isCell(x = cdr(x))) {
    580       y = EVAL(car(x));
    581       NeedSym(ex,y);
    582       sep = symChar(name(y));
    583       if (isCell(x = cdr(x))) {
    584          y = EVAL(car(x));
    585          NeedSym(ex,y);
    586          ign = symChar(name(y));
    587       }
    588    }
    589    if (isNum(data(c1)))
    590       data(c1) = numToSym(data(c1), scl, sep, ign);
    591    else {
    592       int i;
    593       any nm;
    594       cell c2;
    595 
    596       if (isSym(data(c1)))
    597          nm = name(data(c1));
    598       else {
    599          nm = NULL,  pack(data(c1), &i, &nm, &c2);
    600          nm = nm? data(c2) : Nil;
    601       }
    602       data(c1) = symToNum(nm, scl, sep, ign) ?: Nil;
    603    }
    604    return Pop(c1);
    605 }
    606 
    607 // (+ 'num ..) -> num
    608 any doAdd(any ex) {
    609    any x;
    610    cell c1, c2;
    611 
    612    x = cdr(ex);
    613    if (isNil(data(c1) = EVAL(car(x))))
    614       return Nil;
    615    NeedNum(ex,data(c1));
    616    Push(c1, bigCopy(data(c1)));
    617    while (isCell(x = cdr(x))) {
    618       Push(c2, EVAL(car(x)));
    619       if (isNil(data(c2))) {
    620          drop(c1);
    621          return Nil;
    622       }
    623       NeedNum(ex,data(c2));
    624       if (isNeg(data(c1))) {
    625          if (isNeg(data(c2)))
    626             bigAdd(data(c1),data(c2));
    627          else
    628             bigSub(data(c1),data(c2));
    629          if (!IsZero(data(c1)))
    630             neg(data(c1));
    631       }
    632       else if (isNeg(data(c2)))
    633          bigSub(data(c1),data(c2));
    634       else
    635          bigAdd(data(c1),data(c2));
    636       drop(c2);
    637    }
    638    return Pop(c1);
    639 }
    640 
    641 // (- 'num ..) -> num
    642 any doSub(any ex) {
    643    any x;
    644    cell c1, c2;
    645 
    646    x = cdr(ex);
    647    if (isNil(data(c1) = EVAL(car(x))))
    648       return Nil;
    649    NeedNum(ex,data(c1));
    650    if (!isCell(x = cdr(x)))
    651       return IsZero(data(c1))?
    652             data(c1) : consNum(unDig(data(c1)) ^ 1, cdr(numCell(data(c1))));
    653    Push(c1, bigCopy(data(c1)));
    654    do {
    655       Push(c2, EVAL(car(x)));
    656       if (isNil(data(c2))) {
    657          drop(c1);
    658          return Nil;
    659       }
    660       NeedNum(ex,data(c2));
    661       if (isNeg(data(c1))) {
    662          if (isNeg(data(c2)))
    663             bigSub(data(c1),data(c2));
    664          else
    665             bigAdd(data(c1),data(c2));
    666          if (!IsZero(data(c1)))
    667             neg(data(c1));
    668       }
    669       else if (isNeg(data(c2)))
    670          bigAdd(data(c1),data(c2));
    671       else
    672          bigSub(data(c1),data(c2));
    673       drop(c2);
    674    } while (isCell(x = cdr(x)));
    675    return Pop(c1);
    676 }
    677 
    678 // (inc 'num) -> num
    679 // (inc 'var ['num]) -> num
    680 any doInc(any ex) {
    681    any x;
    682    cell c1, c2;
    683 
    684    x = cdr(ex);
    685    if (isNil(data(c1) = EVAL(car(x))))
    686       return Nil;
    687    if (isNum(data(c1))) {
    688       Push(c1, bigCopy(data(c1)));
    689       if (!isNeg(data(c1)))
    690          digAdd(data(c1), 2);
    691       else {
    692          pos(data(c1)), digSub1(data(c1)), neg(data(c1));
    693          if (unDig(data(c1)) == 1  &&  !isNum(cdr(numCell(data(c1)))))
    694             setDig(data(c1), 0);
    695       }
    696       return Pop(c1);
    697    }
    698    CheckVar(ex,data(c1));
    699    if (isSym(data(c1)))
    700       Touch(ex,data(c1));
    701    if (!isCell(x = cdr(x))) {
    702       if (isNil(val(data(c1))))
    703          return Nil;
    704       NeedNum(ex,val(data(c1)));
    705       Save(c1);
    706       val(data(c1)) = bigCopy(val(data(c1)));
    707       if (!isNeg(val(data(c1))))
    708          digAdd(val(data(c1)), 2);
    709       else {
    710          pos(val(data(c1))), digSub1(val(data(c1))), neg(val(data(c1)));
    711          if (unDig(val(data(c1))) == 1  &&  !isNum(cdr(numCell(val(data(c1))))))
    712             setDig(val(data(c1)), 0);
    713       }
    714    }
    715    else {
    716       Save(c1);
    717       Push(c2, EVAL(car(x)));
    718       if (isNil(val(data(c1))) || isNil(data(c2))) {
    719          drop(c1);
    720          return Nil;
    721       }
    722       NeedNum(ex,val(data(c1)));
    723       val(data(c1)) = bigCopy(val(data(c1)));
    724       NeedNum(ex,data(c2));
    725       if (isNeg(val(data(c1)))) {
    726          if (isNeg(data(c2)))
    727             bigAdd(val(data(c1)),data(c2));
    728          else
    729             bigSub(val(data(c1)),data(c2));
    730          if (!IsZero(val(data(c1))))
    731             neg(val(data(c1)));
    732       }
    733       else if (isNeg(data(c2)))
    734          bigSub(val(data(c1)),data(c2));
    735       else
    736          bigAdd(val(data(c1)),data(c2));
    737    }
    738    return val(Pop(c1));
    739 }
    740 
    741 // (dec 'num) -> num
    742 // (dec 'var ['num]) -> num
    743 any doDec(any ex) {
    744    any x;
    745    cell c1, c2;
    746 
    747    x = cdr(ex);
    748    if (isNil(data(c1) = EVAL(car(x))))
    749       return Nil;
    750    if (isNum(data(c1))) {
    751       Push(c1, bigCopy(data(c1)));
    752       if (isNeg(data(c1)))
    753          digAdd(data(c1), 2);
    754       else if (IsZero(data(c1)))
    755          setDig(data(c1), 3);
    756       else
    757          digSub1(data(c1));
    758       return Pop(c1);
    759    }
    760    CheckVar(ex,data(c1));
    761    if (isSym(data(c1)))
    762       Touch(ex,data(c1));
    763    if (!isCell(x = cdr(x))) {
    764       if (isNil(val(data(c1))))
    765          return Nil;
    766       NeedNum(ex,val(data(c1)));
    767       Save(c1);
    768       val(data(c1)) = bigCopy(val(data(c1)));
    769       if (isNeg(val(data(c1))))
    770          digAdd(val(data(c1)), 2);
    771       else if (IsZero(val(data(c1))))
    772          setDig(val(data(c1)), 3);
    773       else
    774          digSub1(val(data(c1)));
    775    }
    776    else {
    777       Save(c1);
    778       Push(c2, EVAL(car(x)));
    779       if (isNil(val(data(c1))) || isNil(data(c2))) {
    780          drop(c1);
    781          return Nil;
    782       }
    783       NeedNum(ex,val(data(c1)));
    784       val(data(c1)) = bigCopy(val(data(c1)));
    785       NeedNum(ex,data(c2));
    786       if (isNeg(val(data(c1)))) {
    787          if (isNeg(data(c2)))
    788             bigSub(val(data(c1)),data(c2));
    789          else
    790             bigAdd(val(data(c1)),data(c2));
    791          if (!IsZero(val(data(c1))))
    792             neg(val(data(c1)));
    793       }
    794       else if (isNeg(data(c2)))
    795          bigAdd(val(data(c1)),data(c2));
    796       else
    797          bigSub(val(data(c1)),data(c2));
    798    }
    799    return val(Pop(c1));
    800 }
    801 
    802 // (* 'num ..) -> num
    803 any doMul(any ex) {
    804    any x;
    805    bool sign;
    806    cell c1, c2;
    807 
    808    x = cdr(ex);
    809    if (isNil(data(c1) = EVAL(car(x))))
    810       return Nil;
    811    NeedNum(ex,data(c1));
    812    Push(c1, bigCopy(data(c1)));
    813    sign = isNeg(data(c1)),  pos(data(c1));
    814    while (isCell(x = cdr(x))) {
    815       Push(c2, EVAL(car(x)));
    816       if (isNil(data(c2))) {
    817          drop(c1);
    818          return Nil;
    819       }
    820       NeedNum(ex,data(c2));
    821       sign ^= isNeg(data(c2));
    822       data(c1) = bigMul(data(c1),data(c2));
    823       drop(c2);
    824    }
    825    if (sign && !IsZero(data(c1)))
    826       neg(data(c1));
    827    return Pop(c1);
    828 }
    829 
    830 // (*/ 'num1 ['num2 ..] 'num3) -> num
    831 any doMulDiv(any ex) {
    832    any x;
    833    bool sign;
    834    cell c1, c2, c3;
    835 
    836    x = cdr(ex);
    837    if (isNil(data(c1) = EVAL(car(x))))
    838       return Nil;
    839    NeedNum(ex,data(c1));
    840    Push(c1, bigCopy(data(c1)));
    841    sign = isNeg(data(c1)),  pos(data(c1));
    842    Push(c2, Nil);
    843    for (;;) {
    844       x = cdr(x),  data(c2) = EVAL(car(x));
    845       if (isNil(data(c2))) {
    846          drop(c1);
    847          return Nil;
    848       }
    849       NeedNum(ex,data(c2));
    850       sign ^= isNeg(data(c2));
    851       if (!isCell(cdr(x)))
    852          break;
    853       data(c1) = bigMul(data(c1),data(c2));
    854    }
    855    if (IsZero(data(c2)))
    856       divErr(ex);
    857    Push(c3, bigCopy(data(c2)));
    858    digDiv2(data(c3));
    859    bigAdd(data(c1),data(c3));
    860    data(c2) = bigCopy(data(c2));
    861    data(c1) = bigDiv(data(c1),data(c2),NO);
    862    if (sign && !IsZero(data(c1)))
    863       neg(data(c1));
    864    return Pop(c1);
    865 }
    866 
    867 // (/ 'num ..) -> num
    868 any doDiv(any ex) {
    869    any x;
    870    bool sign;
    871    cell c1, c2;
    872 
    873    x = cdr(ex);
    874    if (isNil(data(c1) = EVAL(car(x))))
    875       return Nil;
    876    NeedNum(ex,data(c1));
    877    Push(c1, bigCopy(data(c1)));
    878    sign = isNeg(data(c1)),  pos(data(c1));
    879    while (isCell(x = cdr(x))) {
    880       Push(c2, EVAL(car(x)));
    881       if (isNil(data(c2))) {
    882          drop(c1);
    883          return Nil;
    884       }
    885       NeedNum(ex,data(c2));
    886       sign ^= isNeg(data(c2));
    887       if (IsZero(data(c2)))
    888          divErr(ex);
    889       data(c2) = bigCopy(data(c2));
    890       data(c1) = bigDiv(data(c1),data(c2),NO);
    891       drop(c2);
    892    }
    893    if (sign && !IsZero(data(c1)))
    894       neg(data(c1));
    895    return Pop(c1);
    896 }
    897 
    898 // (% 'num ..) -> num
    899 any doRem(any ex) {
    900    any x;
    901    bool sign;
    902    cell c1, c2;
    903 
    904    x = cdr(ex);
    905    if (isNil(data(c1) = EVAL(car(x))))
    906       return Nil;
    907    NeedNum(ex,data(c1));
    908    Push(c1, bigCopy(data(c1)));
    909    sign = isNeg(data(c1)),  pos(data(c1));
    910    while (isCell(x = cdr(x))) {
    911       Push(c2, EVAL(car(x)));
    912       if (isNil(data(c2))) {
    913          drop(c1);
    914          return Nil;
    915       }
    916       NeedNum(ex,data(c2));
    917       if (IsZero(data(c2)))
    918          divErr(ex);
    919       data(c2) = bigCopy(data(c2));
    920       bigDiv(data(c1),data(c2),YES);
    921       drop(c2);
    922    }
    923    if (sign && !IsZero(data(c1)))
    924       neg(data(c1));
    925    return Pop(c1);
    926 }
    927 
    928 // (>> 'cnt 'num) -> num
    929 any doShift(any ex) {
    930    any x;
    931    long n;
    932    bool sign;
    933    cell c1;
    934 
    935    x = cdr(ex),  n = evCnt(ex,x);
    936    x = cdr(x);
    937    if (isNil(data(c1) = EVAL(car(x))))
    938       return Nil;
    939    NeedNum(ex,data(c1));
    940    Push(c1, bigCopy(data(c1)));
    941    sign = isNeg(data(c1));
    942    if (n > 0) {
    943       do
    944          digDiv2(data(c1));
    945       while (--n);
    946       pos(data(c1));
    947    }
    948    else if (n < 0) {
    949       pos(data(c1));
    950       do
    951          digMul2(data(c1));
    952       while (++n);
    953    }
    954    if (sign && !IsZero(data(c1)))
    955       neg(data(c1));
    956    return Pop(c1);
    957 }
    958 
    959 // (lt0 'any) -> num | NIL
    960 any doLt0(any x) {
    961    x = cdr(x);
    962    return isNum(x = EVAL(car(x))) && isNeg(x)? x : Nil;
    963 }
    964 
    965 // (le0 'any) -> num | NIL
    966 any doLe0(any x) {
    967    x = cdr(x);
    968    return isNum(x = EVAL(car(x))) && (isNeg(x) || IsZero(x))? x : Nil;
    969 }
    970 
    971 // (ge0 'any) -> num | NIL
    972 any doGe0(any x) {
    973    x = cdr(x);
    974    return isNum(x = EVAL(car(x))) && !isNeg(x)? x : Nil;
    975 }
    976 
    977 // (gt0 'any) -> num | NIL
    978 any doGt0(any x) {
    979    x = cdr(x);
    980    return isNum(x = EVAL(car(x))) && !isNeg(x) && !IsZero(x)? x : Nil;
    981 }
    982 
    983 // (abs 'num) -> num
    984 any doAbs(any ex) {
    985    any x;
    986 
    987    x = cdr(ex);
    988    if (isNil(x = EVAL(car(x))))
    989       return Nil;
    990    NeedNum(ex,x);
    991    if (!isNeg(x))
    992       return x;
    993    return consNum(unDig(x) & ~1, cdr(numCell(x)));
    994 }
    995 
    996 // (bit? 'num ..) -> num | NIL
    997 any doBitQ(any ex) {
    998    any x, y, z;
    999    cell c1;
   1000 
   1001    x = cdr(ex),  Push(c1, EVAL(car(x)));
   1002    NeedNum(ex,data(c1));
   1003    while (isCell(x = cdr(x))) {
   1004       if (isNil(z = EVAL(car(x)))) {
   1005          drop(c1);
   1006          return Nil;
   1007       }
   1008       NeedNum(ex,z);
   1009       y = data(c1);
   1010       for (;;) {
   1011          if ((unDig(y) & unDig(z)) != unDig(y)) {
   1012             drop(c1);
   1013             return Nil;
   1014          }
   1015          if (!isNum(y = cdr(numCell(y))))
   1016             break;
   1017          if (!isNum(z = cdr(numCell(z)))) {
   1018             drop(c1);
   1019             return Nil;
   1020          }
   1021       }
   1022    }
   1023    return Pop(c1);
   1024 }
   1025 
   1026 // (& 'num ..) -> num
   1027 any doBitAnd(any ex) {
   1028    any x, y, z;
   1029    cell c1;
   1030 
   1031    x = cdr(ex);
   1032    if (isNil(data(c1) = EVAL(car(x))))
   1033       return Nil;
   1034    NeedNum(ex,data(c1));
   1035    Push(c1, bigCopy(data(c1)));
   1036    while (isCell(x = cdr(x))) {
   1037       if (isNil(z = EVAL(car(x)))) {
   1038          drop(c1);
   1039          return Nil;
   1040       }
   1041       NeedNum(ex,z);
   1042       y = data(c1);
   1043       for (;;) {
   1044          setDig(y, unDig(y) & unDig(z));
   1045          if (!isNum(z = cdr(numCell(z)))) {
   1046             cdr(numCell(y)) = Nil;
   1047             break;
   1048          }
   1049          if (!isNum(y = cdr(numCell(y))))
   1050             break;
   1051       }
   1052    }
   1053    zapZero(data(c1));
   1054    return Pop(c1);
   1055 }
   1056 
   1057 // (| 'num ..) -> num
   1058 any doBitOr(any ex) {
   1059    any x, y;
   1060    cell c1, c2;
   1061 
   1062    x = cdr(ex);
   1063    if (isNil(data(c1) = EVAL(car(x))))
   1064       return Nil;
   1065    NeedNum(ex,data(c1));
   1066    Push(c1, bigCopy(data(c1)));
   1067    while (isCell(x = cdr(x))) {
   1068       if (isNil(data(c2) = EVAL(car(x)))) {
   1069          drop(c1);
   1070          return Nil;
   1071       }
   1072       NeedNum(ex,data(c2));
   1073       y = data(c1);
   1074       Save(c2);
   1075       for (;;) {
   1076          setDig(y, unDig(y) | unDig(data(c2)));
   1077          if (!isNum(data(c2) = cdr(numCell(data(c2)))))
   1078             break;
   1079          if (!isNum(cdr(numCell(y))))
   1080             cdr(numCell(y)) = box(0);
   1081          y = cdr(numCell(y));
   1082       }
   1083       drop(c2);
   1084    }
   1085    return Pop(c1);
   1086 }
   1087 
   1088 // (x| 'num ..) -> num
   1089 any doBitXor(any ex) {
   1090    any x, y;
   1091    cell c1, c2;
   1092 
   1093    x = cdr(ex);
   1094    if (isNil(data(c1) = EVAL(car(x))))
   1095       return Nil;
   1096    NeedNum(ex,data(c1));
   1097    Push(c1, bigCopy(data(c1)));
   1098    while (isCell(x = cdr(x))) {
   1099       if (isNil(data(c2) = EVAL(car(x)))) {
   1100          drop(c1);
   1101          return Nil;
   1102       }
   1103       NeedNum(ex,data(c2));
   1104       y = data(c1);
   1105       Save(c2);
   1106       for (;;) {
   1107          setDig(y, unDig(y) ^ unDig(data(c2)));
   1108          if (!isNum(data(c2) = cdr(numCell(data(c2)))))
   1109             break;
   1110          if (!isNum(cdr(numCell(y))))
   1111             cdr(numCell(y)) = box(0);
   1112          y = cdr(numCell(y));
   1113       }
   1114       drop(c2);
   1115    }
   1116    zapZero(data(c1));
   1117    return Pop(c1);
   1118 }
   1119 
   1120 /* Random numbers */
   1121 static uint64_t Seed;
   1122 
   1123 static uint64_t initSeed(any x) {
   1124    uint64_t n;
   1125 
   1126    for (n = 0; isCell(x); x = cdr(x))
   1127       n += initSeed(car(x));
   1128    if (!isNil(x)) {
   1129       if (isSym(x))
   1130          x = name(x);
   1131       do
   1132          n += unDig(x);
   1133       while (isNum(x = cdr(numCell(x))));
   1134    }
   1135    return n;
   1136 }
   1137 
   1138 // (seed 'any) -> cnt
   1139 any doSeed(any ex) {
   1140    return box(hi(Seed = initSeed(EVAL(cadr(ex))) * 6364136223846793005LL));
   1141 }
   1142 
   1143 // (hash 'any) -> cnt
   1144 any doHash(any ex) {
   1145    word2 n = initSeed(EVAL(cadr(ex)));
   1146    int i = 64;
   1147    int j = 0;
   1148 
   1149    do {
   1150       if (((int)n ^ j) & 1)
   1151          j ^= 0x14002;  /* CRC Polynom x**16 + x**15 + x**2 + 1 */
   1152       n >>= 1,  j >>= 1;
   1153    } while (--i);
   1154    return box(2 * (j + 1));
   1155 }
   1156 
   1157 // (rand ['cnt1 'cnt2] | ['T]) -> cnt | flg
   1158 any doRand(any ex) {
   1159    any x;
   1160    long n;
   1161 
   1162    x = cdr(ex);
   1163    Seed = Seed * 6364136223846793005LL + 1;
   1164    if (isNil(x = EVAL(car(x))))
   1165       return box(hi(Seed));
   1166    if (x == T)
   1167       return hi(Seed) & 1 ? T : Nil;
   1168    n = xCnt(ex,x);
   1169    return boxCnt(n + hi(Seed) % (evCnt(ex, cddr(ex)) + 1 - n));
   1170 }