299 lines
6.0 KiB
C
299 lines
6.0 KiB
C
/****************************************************************
|
|
* *
|
|
* Copyright 2001, 2011 Fidelity Information Services, Inc *
|
|
* *
|
|
* This source code contains the intellectual property *
|
|
* of its copyright holder(s), and is made available *
|
|
* under a license. If you do not know the terms of *
|
|
* the license, please stop and do not read further. *
|
|
* *
|
|
****************************************************************/
|
|
|
|
#include "mdef.h"
|
|
#include "arit.h"
|
|
#include "op.h"
|
|
|
|
LITREF int4 ten_pwr[] ;
|
|
LITREF mval literal_zero;
|
|
|
|
error_def(ERR_NUMOFLOW);
|
|
|
|
void add_mvals(mval *u, mval *v, int subtraction, mval *result)
|
|
{
|
|
int delta, uexp, vexp, exp;
|
|
int4 m0, m1, n0, n1, x, factor;
|
|
char usign, vsign, rsign;
|
|
|
|
m1 = u->m[1];
|
|
if ((u->mvtype & MV_INT) == 0)
|
|
{
|
|
usign = u->sgn;
|
|
m0 = u->m[0];
|
|
uexp = u->e;
|
|
} else
|
|
{
|
|
if (m1 == 0)
|
|
goto result_is_v;
|
|
m0 = 0;
|
|
if (m1 > 0)
|
|
usign = 0;
|
|
else
|
|
{
|
|
usign = 1;
|
|
m1 = -m1;
|
|
}
|
|
for (uexp = EXP_INT_OVERF - 1 ; m1 < MANT_LO ; m1 *= 10 , uexp--)
|
|
;
|
|
}
|
|
n1 = v->m[1];
|
|
if ((v->mvtype & MV_INT) == 0)
|
|
{
|
|
n0 = v->m[0];
|
|
vexp = v->e;
|
|
vsign = v->sgn ^ subtraction;
|
|
} else
|
|
{
|
|
if (n1 == 0)
|
|
goto result_is_u;
|
|
else if (n1 > 0)
|
|
vsign = subtraction;
|
|
else
|
|
{
|
|
vsign = !subtraction;
|
|
n1 = -n1;
|
|
}
|
|
n0 = 0;
|
|
for (vexp = EXP_INT_OVERF - 1 ; n1 < MANT_LO ; n1 *= 10 , vexp--)
|
|
;
|
|
}
|
|
delta = uexp - vexp;
|
|
if (delta >= 0)
|
|
{
|
|
exp = uexp;
|
|
if (delta >= NUM_DEC_DG_2L)
|
|
goto result_is_u;
|
|
else if (delta >= NUM_DEC_DG_1L)
|
|
{
|
|
n0 = n1 / ten_pwr[delta - NUM_DEC_DG_1L];
|
|
n1 = 0;
|
|
} else if (delta > 0)
|
|
{
|
|
factor = ten_pwr[delta];
|
|
x = n1;
|
|
n1 /= factor;
|
|
n0 = (x - (n1 * factor)) * ten_pwr[NUM_DEC_DG_1L - delta] + (n0 / factor);
|
|
}
|
|
} else
|
|
{
|
|
exp = vexp;
|
|
if (delta <= - NUM_DEC_DG_2L)
|
|
goto result_is_v;
|
|
else if (delta <= - NUM_DEC_DG_1L)
|
|
{
|
|
m0 = m1 / ten_pwr[-delta - NUM_DEC_DG_1L];
|
|
m1 = 0;
|
|
} else
|
|
{
|
|
factor = ten_pwr[-delta];
|
|
x = m1;
|
|
m1 /= factor;
|
|
m0 = (x - (m1 * factor)) * ten_pwr[NUM_DEC_DG_1L + delta] + (m0 / factor);
|
|
}
|
|
}
|
|
if (usign == vsign)
|
|
{
|
|
/* Perform addition */
|
|
m0 += n0;
|
|
if (m0 >= MANT_HI)
|
|
{
|
|
m1++;
|
|
m0 -= MANT_HI;
|
|
}
|
|
m1 += n1;
|
|
if (m1 >= MANT_HI)
|
|
{
|
|
x = m1 / 10;
|
|
m0 = (m0 / 10) + (m1 - x * 10) * MANT_LO;
|
|
m1 = x;
|
|
exp++;
|
|
}
|
|
rsign = usign;
|
|
} else
|
|
{
|
|
/* perform subtraction */
|
|
if (delta < 0 || (delta == 0 && (m1 < n1 || (m1 == n1 && m0 < n0))))
|
|
{
|
|
x = m1;
|
|
m1 = n1;
|
|
n1 = x;
|
|
x = m0;
|
|
m0 = n0;
|
|
n0 = x;
|
|
rsign = vsign;
|
|
} else
|
|
{
|
|
rsign = usign;
|
|
}
|
|
m0 -= n0;
|
|
if (m0 < 0)
|
|
{
|
|
m1--;
|
|
m0 += MANT_HI;
|
|
assert(m0 > 0 && m0 < MANT_HI);
|
|
}
|
|
m1 -= n1;
|
|
if (m1 == 0)
|
|
{
|
|
exp -= NUM_DEC_DG_1L;
|
|
m1 = m0;
|
|
if (m1 == 0)
|
|
{
|
|
result->mvtype = MV_NM | MV_INT;
|
|
result->m[1] = 0;
|
|
return;
|
|
}
|
|
m0 = 0;
|
|
}
|
|
if (m1 < 0)
|
|
{
|
|
m1 += MANT_HI;
|
|
exp--;
|
|
}
|
|
if (m1 < MANT_LO)
|
|
{
|
|
for (delta = 0 ; m1 < MANT_LO ; delta++)
|
|
m1 *= 10;
|
|
assert(delta > 0 && delta <= NUM_DEC_DG_1L);
|
|
factor = ten_pwr[NUM_DEC_DG_1L - delta];
|
|
x = m0 / factor;
|
|
m1 += x;
|
|
m0 = (m0 - x * factor) * ten_pwr[delta];
|
|
exp -= delta;
|
|
}
|
|
}
|
|
if ( exp < EXP_INT_OVERF && exp > EXP_INT_UNDERF && m0 == 0)
|
|
{
|
|
factor = ten_pwr[EXP_INT_OVERF - 1 - exp];
|
|
x = m1 / factor;
|
|
if (x * factor == m1)
|
|
{
|
|
result->mvtype = MV_NM | MV_INT;
|
|
result->m[1] = rsign ? - x : x;
|
|
return;
|
|
}
|
|
}
|
|
if (EXPHI <= exp)
|
|
rts_error(VARLSTCNT(1) ERR_NUMOFLOW);
|
|
else if (EXPLO > exp)
|
|
*result = literal_zero;
|
|
else
|
|
{
|
|
result->mvtype = MV_NM;
|
|
result->sgn = rsign;
|
|
result->e = exp;
|
|
result->m[0] = m0;
|
|
result->m[1] = m1;
|
|
}
|
|
return;
|
|
|
|
result_is_u:
|
|
*result = *u;
|
|
MV_FORCE_CANONICAL(result);
|
|
return;
|
|
|
|
result_is_v:
|
|
if (subtraction)
|
|
{
|
|
if (v->mvtype & MV_INT)
|
|
{
|
|
result->mvtype = (MV_NM | MV_INT);
|
|
result->m[1] = - v->m[1];
|
|
} else
|
|
{
|
|
result->mvtype = MV_NM;
|
|
result->sgn = !v->sgn;
|
|
result->e = v->e;
|
|
result->m[0] = v->m[0];
|
|
result->m[1] = v->m[1];
|
|
}
|
|
} else
|
|
{
|
|
*result = *v;
|
|
MV_FORCE_CANONICAL(result);
|
|
}
|
|
return;
|
|
}
|
|
|
|
void op_add (mval *u, mval *v, mval *s)
|
|
{
|
|
int4 m0, m1;
|
|
char utype, vtype;
|
|
|
|
MV_FORCE_NUM(u);
|
|
MV_FORCE_NUM(v);
|
|
utype = u->mvtype;
|
|
vtype = v->mvtype;
|
|
if ( utype & vtype & MV_INT )
|
|
{
|
|
m1 = u->m[1] + v->m[1] ;
|
|
if (m1 < MANT_HI && m1 > -MANT_HI)
|
|
{
|
|
s->mvtype = MV_INT | MV_NM ;
|
|
s->m[1] = m1;
|
|
return;
|
|
}
|
|
if ( m1 > 0)
|
|
{
|
|
s->sgn = 0;
|
|
} else
|
|
{
|
|
s->sgn = 1;
|
|
m1 = -m1;
|
|
}
|
|
s->mvtype = MV_NM;
|
|
s->e = EXP_INT_OVERF;
|
|
m0 = m1 / 10;
|
|
s->m[0] = (m1 - (m0 * 10)) * MANT_LO;
|
|
s->m[1] = m0;
|
|
return;
|
|
}
|
|
add_mvals(u, v, 0, s);
|
|
return;
|
|
}
|
|
|
|
void op_sub (mval *u, mval *v, mval *s)
|
|
{
|
|
int4 m0, m1;
|
|
char utype, vtype;
|
|
|
|
MV_FORCE_NUM(u);
|
|
MV_FORCE_NUM(v);
|
|
utype = u->mvtype;
|
|
vtype = v->mvtype;
|
|
if ( utype & vtype & MV_INT )
|
|
{
|
|
m1 = u->m[1] - v->m[1] ;
|
|
if (m1 < MANT_HI && m1 > -MANT_HI)
|
|
{
|
|
s->mvtype = MV_INT | MV_NM ;
|
|
s->m[1] = m1;
|
|
return;
|
|
}
|
|
if ( m1 > 0)
|
|
{
|
|
s->sgn = 0;
|
|
} else
|
|
{ s->sgn = 1;
|
|
m1 = -m1;
|
|
}
|
|
s->mvtype = MV_NM;
|
|
s->e = EXP_INT_OVERF;
|
|
m0 = m1 / 10;
|
|
s->m[0] = (m1 - (m0 * 10)) * MANT_LO;
|
|
s->m[1] = m0;
|
|
return;
|
|
}
|
|
add_mvals(u, v, 1, s);
|
|
return;
|
|
}
|