version 1.5, 2006/10/22 16:54:00
|
version 1.11, 2007/12/31 20:35:21
|
Line 1
|
Line 1
|
/* some routines for double-cell arithmetic |
/* some routines for double-cell arithmetic |
only used if BUGGY_LONG_LONG |
only used if BUGGY_LONG_LONG |
|
|
Copyright (C) 1996,2000,2003 Free Software Foundation, Inc. |
Copyright (C) 1996,2000,2003,2006,2007 Free Software Foundation, Inc. |
* Copyright (C) 1995 Dirk Uwe Zoller |
* Copyright (C) 1995 Dirk Uwe Zoller |
* |
* |
* This library is free software; you can redistribute it and/or |
* This library is free software; you can redistribute it and/or |
* modify it under the terms of the GNU Library General Public |
* modify it under the terms of the GNU Lesser General Public |
* License as published by the Free Software Foundation; either |
* License as published by the Free Software Foundation; either |
* version 2 of the License, or (at your option) any later version. |
* version 3 of the License, or (at your option) any later version. |
* |
* |
* This library is distributed in the hope that it will be useful, |
* This library is distributed in the hope that it will be useful, |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
* See the GNU Library General Public License for more details. |
* See the GNU Lesser General Public License for more details. |
* |
* |
* You should have received a copy of the GNU Library General Public |
* You should have received a copy of the GNU Lesser General Public |
* License along with this library; if not, write to the Free |
* License along with this library; if not, write to the Free |
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. |
|
|
Line 24
|
Line 24
|
#include "config.h" |
#include "config.h" |
#include "forth.h" |
#include "forth.h" |
|
|
/* !! a bit machine dependent */ |
|
#define HALFCELL_BITS (CELL_BITS/2) |
|
#define UH(x) (((UCell)(x))>>HALFCELL_BITS) |
|
#define LH(x) ((x)&((~(UCell)0)>>HALFCELL_BITS)) |
|
#define L2U(x) (((UCell)(x))<<HALFCELL_BITS) |
|
#define HIGHBIT(x) (((UCell)(x))>>(CELL_BITS-1)) |
|
#define UD2D(ud) ({UDCell _ud=(ud); (DCell){_ud.hi,_ud.lo};}) |
|
#define D2UD(d) ({DCell _d=(d); (UDCell){_d.hi,_d.lo};}) |
|
|
|
DCell dnegate(DCell d1) |
DCell dnegate(DCell d1) |
{ |
{ |
DCell res; |
DCell res; |
Line 72 DCell mmul (Cell a, Cell b) /* signed m
|
Line 63 DCell mmul (Cell a, Cell b) /* signed m
|
res.hi -= a; |
res.hi -= a; |
return res; |
return res; |
} |
} |
|
|
UDCell umdiv (UDCell u, UCell v) |
|
/* Divide unsigned double by single precision using shifts and subtracts. |
|
Return quotient in lo, remainder in hi. */ |
|
{ |
|
int i = CELL_BITS, c = 0; |
|
UCell q = 0, h = u.hi, l = u.lo; |
|
UDCell res; |
|
|
|
if (v==0) |
|
throw(BALL_DIVZERO); |
|
if (h>=v) |
|
throw(BALL_RESULTRANGE); |
|
for (;;) |
|
{ |
|
if (c || h >= v) |
|
{ |
|
q++; |
|
h -= v; |
|
} |
|
if (--i < 0) |
|
break; |
|
c = HIGHBIT (h); |
|
h <<= 1; |
|
h += HIGHBIT (l); |
|
l <<= 1; |
|
q <<= 1; |
|
} |
|
res.hi = h; |
|
res.lo = q; |
|
return res; |
|
} |
|
|
|
DCell smdiv (DCell num, Cell denom) /* symmetric divide procedure, mixed prec */ |
|
{ |
|
DCell res; |
|
Cell numsign=num.hi; |
|
Cell denomsign=denom; |
|
|
|
if (numsign < 0) |
|
num = dnegate (num); |
|
if (denomsign < 0) |
|
denom = -denom; |
|
res = UD2D(umdiv (D2UD(num), denom)); |
|
if (res.lo >= (UCell)CELL_MIN) |
|
throw(BALL_RESULTRANGE); |
|
if ((numsign^denomsign)<0) { |
|
if (res.lo == CELL_MIN) |
|
throw(BALL_RESULTRANGE); |
|
res.lo = -res.lo; |
|
} |
|
if (numsign<0) |
|
res.hi = -res.hi; |
|
return res; |
|
} |
|
|
|
DCell fmdiv (DCell num, Cell denom) /* floored divide procedure, mixed prec */ |
|
{ |
|
/* I have this technique from Andrew Haley */ |
|
DCell res; |
|
Cell denomsign=denom; |
|
|
|
if (denom < 0) { |
|
denom = -denom; |
|
num = dnegate(num); |
|
} |
|
if (num.hi < 0) |
|
num.hi += denom; |
|
res = UD2D(umdiv(D2UD(num),denom)); |
|
if (res.lo >= (UCell)CELL_MIN) |
|
throw(BALL_RESULTRANGE); |
|
if (denomsign<0) |
|
res.hi = -res.hi; |
|
return res; |
|
} |
|