home *** CD-ROM | disk | FTP | other *** search
- /*
- * This file is part of the portable Forth environment written in ANSI C.
- * Copyright (C) 1995 Dirk Uwe Zoller
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This file is version 0.9.13 of 17-July-95
- * Check for the latest version of this package via anonymous ftp at
- * roxi.rz.fht-mannheim.de:/pub/languages/forth/pfe-VERSION.tar.gz
- * or sunsite.unc.edu:/pub/languages/forth/pfe-VERSION.tar.gz
- * or ftp.cygnus.com:/pub/forth/pfe-VERSION.tar.gz
- *
- * Please direct any comments via internet to
- * duz@roxi.rz.fht-mannheim.de.
- * Thank You.
- */
- /*
- * dblsub.c --- Subroutines for double number (64 Bit) arithmetics.
- * (duz 16Jul93)
- */
-
- #include "forth.h"
- #include "dblsub.h"
-
- void
- dasl (dCell *a, int n) /* left shift of *a by n positions */
- {
- while (--n >= 0)
- {
- a->hi <<= 1;
- a->hi += HIGHBIT (a->lo);
- a->lo <<= 1;
- }
- }
-
- void
- dasr (dCell *a, int n) /* arithm. right shift of *a by n positions */
- {
- while (--n >= 0)
- {
- a->lo >>= 1;
- a->lo += a->hi << (CELLBITS - 1);
- a->hi >>= 1;
- }
- }
- /* *INDENT-OFF* */
- void
- madd (dCell * a, Cell b) /* add b to a */
- {
- uCell c; /* carry */
-
- D3 (*a) = c = (uCell) D3 (*a) + W1 (b); c >>= HALFCELL;
- D2 (*a) = c += (uCell) D2 (*a) + W0 (b); c >>= HALFCELL;
- D1 (*a) = c += (uCell) D1 (*a); c >>= HALFCELL;
- D0 (*a) = c + (uCell) D0 (*a);
- }
-
- void
- dadd (dCell * a, dCell * b) /* add b to a */
- {
- uCell c; /* carry */
-
- D3 (*a) = c = (uCell) D3 (*a) + D3 (*b); c >>= HALFCELL;
- D2 (*a) = c += (uCell) D2 (*a) + D2 (*b); c >>= HALFCELL;
- D1 (*a) = c += (uCell) D1 (*a) + D1 (*b); c >>= HALFCELL;
- D0 (*a) = c + (uCell) D0 (*a) + D0 (*b);
- }
-
- void
- dsub (dCell * a, dCell * b) /* subtract b from a */
- {
- Cell c; /* carry */
-
- D3 (*a) = c = (Cell) D3 (*a) - (Cell) D3 (*b); c >>= HALFCELL;
- D2 (*a) = c += (Cell) D2 (*a) - (Cell) D2 (*b); c >>= HALFCELL;
- D1 (*a) = c += (Cell) D1 (*a) - (Cell) D1 (*b); c >>= HALFCELL;
- D0 (*a) = c + (Cell) D0 (*a) - (Cell) D0 (*b);
- }
-
- void
- dnegate (dCell * a) /* negate a */
- {
- Cell c; /* carry */
-
- D3 (*a) = c = -(Cell) D3 (*a); c >>= HALFCELL;
- D2 (*a) = c -= (Cell) D2 (*a); c >>= HALFCELL;
- D1 (*a) = c -= (Cell) D1 (*a); c >>= HALFCELL;
- D0 (*a) = c - (Cell) D0 (*a);
- }
- /* *INDENT-ON */
-
- int
- dless (dCell * a, dCell * b) /* result: a < b */
- {
- return a->hi != b->hi
- ? a->hi < b->hi
- : a->lo < b->lo;
- }
-
- int
- duless (udCell * a, udCell * b) /* result: a < b */
- {
- return a->hi != b->hi ? a->hi < b->hi : a->lo < b->lo;
- }
-
- udCell
- ummul (uCell a, uCell b) /* unsigned multiply, mixed precision */
- {
- udCell res;
- uCell c, p;
-
- res.lo = (uCell) W1 (a) * W1 (b);
- if (W0 (a))
- {
- p = (uCell) W0 (a) * W1 (b);
- if (W0 (b))
- {
- uCell q = (uCell) W1 (a) * W0 (b);
- res.hi = (uCell) W0 (a) * W0 (b);
- /* *INDENT-OFF* */
- D2 (res) = c = (uCell) D2 (res) + W1 (p) + W1 (q); c >>= HALFCELL;
- D1 (res) = c += (uCell) D1 (res) + W0 (p) + W0 (q); c >>= HALFCELL;
- /* *INDENT-ON */
- D0 (res) += c;
- }
- else
- goto three;
- }
- else
- {
- if (W0 (b))
- {
- p = (uCell) W1 (a) * W0 (b);
- three:
- D2 (res) = c = (uCell) D2 (res) + W1 (p); c >>= HALFCELL;
- D1 (res) = c + W0 (p);
- D0 (res) = 0;
- }
- else
- res.hi = 0;
- }
- return res;
- }
-
- dCell
- mmul (Cell a, Cell b) /* signed multiply, mixed precision */
- {
- dCell res;
- int s = 0;
-
- if (a < 0)
- a = -a, s ^= 1;
- if (b < 0)
- b = -b, s ^= 1;
- *(udCell *) & res = ummul (a, b);
- if (s)
- dnegate (&res);
- return res;
- }
-
- static void
- shift_subtract (udCell * u, uCell v)
- /* Divide unsigned double by single precision using shifts and subtracts.
- Return quotient in u->lo, remainder in u->hi. */
- {
- int i = CELLBITS, c = 0;
- uCell q = 0, h = u->hi, l = u->lo;
-
- for (;;)
- {
- if (c || h >= v)
- {
- q++;
- h -= v;
- }
- if (--i < 0)
- break;
- c = HIGHBIT (h);
- h <<= 1;
- h += HIGHBIT (l);
- l <<= 1;
- q <<= 1;
- }
- u->hi = h;
- u->lo = q;
- }
-
- udiv_t
- umdiv (udCell num, uCell denom) /* unsigned divide procedure, mixed prec */
- {
- udiv_t res;
-
- if (num.hi == 0)
- {
- res.quot = num.lo / denom;
- res.rem = num.lo % denom;
- }
- else
- {
- shift_subtract (&num, denom);
- res.quot = num.lo;
- res.rem = num.hi;
- }
- return res;
- }
-
- fdiv_t
- smdiv (dCell num, Cell denom) /* symmetric divide procedure, mixed prec */
- {
- fdiv_t res;
- int sq = 0, sr = 0;
-
- if (num.hi < 0)
- {
- if (num.hi == -1 && (Cell) num.lo < 0)
- goto simple;
- dnegate (&num);
- sq ^= 1;
- sr ^= 1;
- }
- else if (num.hi == 0 && (Cell) num.lo > 0)
- {
- simple:
- res.quot = (Cell) num.lo / denom;
- res.rem = (Cell) num.lo % denom;
- return res;
- }
- if (denom < 0)
- {
- denom = -denom;
- sq ^= 1;
- }
- shift_subtract ((udCell *) & num, denom);
- res.quot = sq ? -num.lo : num.lo;
- res.rem = sr ? -num.hi : num.hi;
- return res;
- }
-
- fdiv_t
- fmdiv (dCell num, Cell denom) /* floored divide procedure, mixed prec */
- {
- fdiv_t res = smdiv (num, denom);
- if (res.rem && (num.hi ^ denom) < 0)
- res.quot--, res.rem += denom;
- return res;
- }
-