fis-gtm/sr_port/op_add.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;
}