version 1.4, 2003/08/25 14:17:51
|
version 1.8, 2006/10/30 15:29:48
|
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; |
|
|
|
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 ((numsign^denomsign)<0) |
|
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 (denomsign<0) |
|
res.hi = -res.hi; |
|
return res; |
|
} |
|