640 lines
10 KiB
C
640 lines
10 KiB
C
|
/*
|
||
|
* Sources of the "FLOATING POINT ARITHMETIC" group instructions
|
||
|
*/
|
||
|
|
||
|
/* $Header$ */
|
||
|
|
||
|
#include <em_abs.h>
|
||
|
#include "nofloat.h"
|
||
|
#include "global.h"
|
||
|
#include "log.h"
|
||
|
#include "mem.h"
|
||
|
#include "trap.h"
|
||
|
#include "text.h"
|
||
|
#include "fra.h"
|
||
|
#include "warn.h"
|
||
|
|
||
|
#ifndef NOFLOAT
|
||
|
|
||
|
extern double fpop();
|
||
|
|
||
|
#define MAXDOUBLE 99.e999 /* IEEE infinity */ /*???*/
|
||
|
#define SMALL (1.0/MAXDOUBLE)
|
||
|
|
||
|
PRIVATE double adf(), sbf(), mlf(), dvf();
|
||
|
PRIVATE double ttttp();
|
||
|
PRIVATE double floor(), fabs();
|
||
|
PRIVATE fef(), fif();
|
||
|
|
||
|
#endif NOFLOAT
|
||
|
|
||
|
DoADFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* ADF w: Floating add (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoADFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(adf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoADFs(hob, wfac)
|
||
|
long hob;
|
||
|
size wfac;
|
||
|
{
|
||
|
/* ADF w: Floating add (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (S_arg(hob) * wfac);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoADFs(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(adf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
hob = hob;
|
||
|
wfac = wfac;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoADFz()
|
||
|
{
|
||
|
/* ADF w: Floating add (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoADFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(adf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoSBFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* SBF w: Floating subtract (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoSBFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(sbf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoSBFs(hob, wfac)
|
||
|
long hob;
|
||
|
size wfac;
|
||
|
{
|
||
|
/* SBF w: Floating subtract (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (S_arg(hob) * wfac);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoSBFs(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(sbf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
hob = hob;
|
||
|
wfac = wfac;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoSBFz()
|
||
|
{
|
||
|
/* SBF w: Floating subtract (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoSBFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(sbf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoMLFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* MLF w: Floating multiply (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoMLFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(mlf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoMLFs(hob, wfac)
|
||
|
long hob;
|
||
|
size wfac;
|
||
|
{
|
||
|
/* MLF w: Floating multiply (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (S_arg(hob) * wfac);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoMLFs(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(mlf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
hob = hob;
|
||
|
wfac = wfac;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoMLFz()
|
||
|
{
|
||
|
/* MLF w: Floating multiply (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoMLFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(mlf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoDVFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* DVF w: Floating divide (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoDVFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(dvf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoDVFs(hob, wfac)
|
||
|
long hob;
|
||
|
size wfac;
|
||
|
{
|
||
|
/* DVF w: Floating divide (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (S_arg(hob) * wfac);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoDVFs(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(dvf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
hob = hob;
|
||
|
wfac = wfac;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoDVFz()
|
||
|
{
|
||
|
/* DVF w: Floating divide (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoDVFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(dvf(fpop(l), t), l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoNGFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* NGF w: Floating negate (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoNGFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(-t, l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoNGFz()
|
||
|
{
|
||
|
/* NGF w: Floating negate (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoNGFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fpush(-t, l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoFIFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* FIF w: Floating multiply and split integer and fraction part (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoFIFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fif(fpop(l), t, l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoFIFz()
|
||
|
{
|
||
|
/* FIF w: Floating multiply and split integer and fraction part (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
double t = fpop(arg_wf(l));
|
||
|
|
||
|
LOG(("@F6 DoFIFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fif(fpop(l), t, l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoFEFl2(arg)
|
||
|
size arg;
|
||
|
{
|
||
|
/* FEF w: Split floating number in exponent and fraction part (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = (L_arg_2() * arg);
|
||
|
|
||
|
LOG(("@F6 DoFEFl2(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fef(fpop(arg_wf(l)), l);
|
||
|
#else NOFLOAT
|
||
|
arg = arg;
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
DoFEFz()
|
||
|
{
|
||
|
/* FEF w: Split floating number in exponent and fraction part (*) */
|
||
|
#ifndef NOFLOAT
|
||
|
register size l = upop(wsize);
|
||
|
|
||
|
LOG(("@F6 DoFEFz(%ld)", l));
|
||
|
spoilFRA();
|
||
|
fef(fpop(arg_wf(l)), l);
|
||
|
#else NOFLOAT
|
||
|
nofloat();
|
||
|
#endif NOFLOAT
|
||
|
}
|
||
|
|
||
|
#ifndef NOFLOAT
|
||
|
|
||
|
/* Service routines */
|
||
|
|
||
|
PRIVATE double adf(f1, f2) /* returns f1 + f2 */
|
||
|
double f1, f2;
|
||
|
{
|
||
|
if (must_test && !(IgnMask&BIT(EFOVFL))) {
|
||
|
if (f1 > 0.0 && f2 > 0.0) {
|
||
|
if (MAXDOUBLE - f1 < f2) {
|
||
|
trap(EFOVFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
}
|
||
|
else if (f1 < 0.0 && f2 < 0.0) {
|
||
|
if (-(MAXDOUBLE + f1) > f2) {
|
||
|
trap(EFOVFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (f1 + f2);
|
||
|
}
|
||
|
|
||
|
PRIVATE double sbf(f1, f2) /* returns f1 - f2 */
|
||
|
double f1, f2;
|
||
|
{
|
||
|
if (must_test && !(IgnMask&BIT(EFOVFL))) {
|
||
|
if (f2 < 0.0 && f1 > 0.0) {
|
||
|
if (MAXDOUBLE - f1 < -f2) {
|
||
|
trap(EFOVFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
}
|
||
|
else if (f2 > 0.0 && f1 < 0.0) {
|
||
|
if (f2 - MAXDOUBLE > f1) {
|
||
|
trap(EFOVFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (f1 - f2);
|
||
|
}
|
||
|
|
||
|
PRIVATE double mlf(f1, f2) /* returns f1 * f2 */
|
||
|
double f1, f2;
|
||
|
{
|
||
|
double ff1 = fabs(f1), ff2 = fabs(f2);
|
||
|
|
||
|
if (f1 == 0.0 || f2 == 0.0)
|
||
|
return (0.0);
|
||
|
|
||
|
if ((ff1 >= 1.0 && ff2 <= 1.0) || (ff2 >= 1.0 && ff1 <= 1.0))
|
||
|
return (f1 * f2);
|
||
|
|
||
|
if (must_test && !(IgnMask&BIT(EFUNFL))) {
|
||
|
if (ff1 < 1.0 && ff2 < 1.0) {
|
||
|
if (SMALL / ff1 > ff2) {
|
||
|
trap(EFUNFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
return (f1 * f2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (must_test && !(IgnMask&BIT(EFOVFL))) {
|
||
|
if (MAXDOUBLE / ff1 < ff2) {
|
||
|
trap(EFOVFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
}
|
||
|
return (f1 * f2);
|
||
|
}
|
||
|
|
||
|
PRIVATE double dvf(f1, f2) /* returns f1 / f2 */
|
||
|
double f1, f2;
|
||
|
{
|
||
|
double ff1 = fabs(f1), ff2 = fabs(f2);
|
||
|
|
||
|
if (f2 == 0.0) {
|
||
|
if (!(IgnMask&BIT(EFDIVZ))) {
|
||
|
trap(EFDIVZ);
|
||
|
}
|
||
|
else return (0.0);
|
||
|
}
|
||
|
|
||
|
if (f1 == 0.0)
|
||
|
return (0.0);
|
||
|
|
||
|
if ((ff2 >= 1.0 && ff1 >= 1.0) || (ff1 <= 1.0 && ff2 <= 1.0))
|
||
|
return (f1 / f2);
|
||
|
|
||
|
if (must_test && !(IgnMask&BIT(EFUNFL))) {
|
||
|
if (ff2 > 1.0 && ff1 < 1.0) {
|
||
|
if (SMALL / ff2 > ff1) {
|
||
|
trap(EFUNFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
return (f1 / f2);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (must_test && !(IgnMask&BIT(EFOVFL))) {
|
||
|
if (MAXDOUBLE * ff2 < ff1) {
|
||
|
trap(EFOVFL);
|
||
|
return (0.0);
|
||
|
}
|
||
|
}
|
||
|
return (f1 / f2);
|
||
|
}
|
||
|
|
||
|
PRIVATE fif(f1, f2, n)
|
||
|
double f1, f2;
|
||
|
size n;
|
||
|
{
|
||
|
double f = mlf(f1, f2);
|
||
|
double fl = floor(fabs(f));
|
||
|
|
||
|
fpush(fabs(f) - fl, n); /* push fraction */
|
||
|
fpush((f < 0.0) ? -fl : fl, n); /* push integer-part */
|
||
|
}
|
||
|
|
||
|
PRIVATE fef(f, n)
|
||
|
double f;
|
||
|
size n;
|
||
|
{
|
||
|
register long exponent, sign = (long) (f < 0.0);
|
||
|
|
||
|
for (f = fabs(f), exponent = 0; f >= 1.0; exponent++)
|
||
|
f /= 2.0;
|
||
|
|
||
|
for (; f < 0.5; exponent--)
|
||
|
f *= 2.0;
|
||
|
|
||
|
fpush((sign) ? -f : f, n); /* push mantissa */
|
||
|
npush(exponent, wsize); /* push exponent */
|
||
|
}
|
||
|
|
||
|
/* floating point service routines, to avoid having to use -lm */
|
||
|
|
||
|
PRIVATE double fabs(f)
|
||
|
double f;
|
||
|
{
|
||
|
return (f < 0.0 ? -f : f);
|
||
|
}
|
||
|
|
||
|
PRIVATE double floor(f)
|
||
|
double f;
|
||
|
{
|
||
|
double res, d;
|
||
|
register int sign = 1;
|
||
|
|
||
|
/* eliminate the sign */
|
||
|
if (f < 0) {
|
||
|
sign = -1, f = -f;
|
||
|
}
|
||
|
|
||
|
/* get the largest power of 2 <= f */
|
||
|
d = 1.0;
|
||
|
while (f - d >= d) {
|
||
|
d *= 2.0;
|
||
|
}
|
||
|
|
||
|
/* reconstruct f by deminishing powers of 2 */
|
||
|
res = 0.0;
|
||
|
while (d >= 1.0) {
|
||
|
if (res + d <= f)
|
||
|
res += d;
|
||
|
d /= 2.0;
|
||
|
}
|
||
|
|
||
|
/* undo the sign elimination */
|
||
|
if (sign == -1) {
|
||
|
res = -res, f = -f;
|
||
|
if (res > f)
|
||
|
res -= 1.0;
|
||
|
}
|
||
|
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PRIVATE double ttttp(f, n) /* times ten to the power */
|
||
|
double f;
|
||
|
{
|
||
|
while (n > 0) {
|
||
|
f = mlf(f, 10.0);
|
||
|
n--;
|
||
|
}
|
||
|
while (n < 0) {
|
||
|
f = dvf(f, 10.0);
|
||
|
n++;
|
||
|
}
|
||
|
return f;
|
||
|
}
|
||
|
|
||
|
/* Str2double is used to initialize the global data area with floats;
|
||
|
we do not use, e.g., sscanf(), to be able to check the grammar of
|
||
|
the string and to give warnings.
|
||
|
*/
|
||
|
|
||
|
double str2double(str)
|
||
|
char *str;
|
||
|
{
|
||
|
register char b;
|
||
|
register int sign = 1; /* either +1 or -1 */
|
||
|
register int frac = 0; /* how far in fraction part ? */
|
||
|
register int ex; /* to store exponent */
|
||
|
double mantissa = 0.0; /* to store mantissa */
|
||
|
double d; /* double to be returned */
|
||
|
|
||
|
b = *str++;
|
||
|
if (b == '-') {
|
||
|
sign = -1;
|
||
|
b = *str++;
|
||
|
}
|
||
|
else if (b == '+') {
|
||
|
sign = 1;
|
||
|
b = *str++;
|
||
|
}
|
||
|
|
||
|
if ('0' <= b && b <= '9') {
|
||
|
mantissa = (double) (b-'0');
|
||
|
}
|
||
|
else if (b == '.') {
|
||
|
/* part before dot cannot be empty */
|
||
|
warning(WBADFLOAT);
|
||
|
frac = 1;
|
||
|
}
|
||
|
else {
|
||
|
goto BadFloat;
|
||
|
}
|
||
|
|
||
|
LOG((" q9 str2double : (before while) mantissa = %20.20g", mantissa));
|
||
|
|
||
|
while ((b = *str++) != 'e' && b != 'E' && b != '\0') {
|
||
|
if (b == '.') {
|
||
|
if (frac == 0) {
|
||
|
frac++;
|
||
|
}
|
||
|
else { /* there already was a '.' in input */
|
||
|
goto BadFloat;
|
||
|
}
|
||
|
}
|
||
|
else if ('0' <= b && b <= '9') {
|
||
|
double bval = b - '0';
|
||
|
|
||
|
if (frac) {
|
||
|
mantissa =
|
||
|
adf(mantissa, ttttp(bval, -frac));
|
||
|
frac++;
|
||
|
}
|
||
|
else {
|
||
|
mantissa =
|
||
|
adf(mlf(mantissa, 10.0), bval);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
goto BadFloat;
|
||
|
}
|
||
|
LOG((" q9 str2double : (inside while) mantissa = %20.20g",
|
||
|
mantissa));
|
||
|
}
|
||
|
LOG((" q9 str2double : mantissa = %10.10g", mantissa));
|
||
|
mantissa = sign * mantissa;
|
||
|
if (b == '\0')
|
||
|
return (mantissa);
|
||
|
/* else we have b == 'e' or b== 'E' */
|
||
|
|
||
|
/* Optional sign for exponent */
|
||
|
b = *str++;
|
||
|
if (b == '-') {
|
||
|
sign = -1;
|
||
|
b = *str++;
|
||
|
}
|
||
|
else if (b == '+') {
|
||
|
sign = 1;
|
||
|
b = *str++;
|
||
|
}
|
||
|
else {
|
||
|
sign = 1;
|
||
|
}
|
||
|
|
||
|
ex = 0;
|
||
|
do {
|
||
|
if ('0' <= b && b <= '9') {
|
||
|
ex = 10*ex + (b-'0');
|
||
|
}
|
||
|
else {
|
||
|
goto BadFloat;
|
||
|
}
|
||
|
} while ((b = *str++) != '\0');
|
||
|
LOG((" q9 str2double : exponent = %d", ex));
|
||
|
|
||
|
/* Construct total value of float */
|
||
|
ex = sign * ex;
|
||
|
d = ttttp(mantissa, ex);
|
||
|
return (d);
|
||
|
|
||
|
BadFloat:
|
||
|
fatal("Float garbled in loadfile");
|
||
|
return (0.0);
|
||
|
}
|
||
|
|
||
|
#else NOFLOAT
|
||
|
|
||
|
nofloat() {
|
||
|
fatal("attempt to execute a floating point instruction on an EM machine without FP");
|
||
|
}
|
||
|
|
||
|
#endif NOFLOAT
|
||
|
|