version 1.6, 2006/10/22 20:45:34
|
version 1.9, 2006/12/31 13:39:17
|
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 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 |
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) { |
|
res.lo = -res.lo; |
|
} else { |
|
if (res.lo == CELL_MIN) |
|
throw(BALL_RESULTRANGE); |
|
} |
|
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; |
|
Cell numsign; |
|
|
|
if (denom < 0) { |
|
denom = -denom; |
|
num = dnegate(num); |
|
} |
|
numsign = num.hi; |
|
if (numsign < 0) |
|
num.hi += denom; |
|
res = UD2D(umdiv(D2UD(num),denom)); |
|
if (numsign < 0) { |
|
if (res.lo < (UCell)CELL_MIN) |
|
throw(BALL_RESULTRANGE); |
|
} else { |
|
if (res.lo >= (UCell)CELL_MIN) |
|
throw(BALL_RESULTRANGE); |
|
} |
|
if (denomsign<0) |
|
res.hi = -res.hi; |
|
return res; |
|
} |
|