blob: d88728790d6fef40d283a010c9d5a5f996611e92 [file] [log] [blame]
#include "pdefs.h"
#include "precision.h"
#include <string.h>
#ifdef ASM_16BIT
#include "asm16bit.h"
#endif
/*
* Subtract u from v (assumes normalized)
*/
precision psub(u, v)
#ifndef ASM_16BIT
precision u, v;
{
register digitPtr HiDigit, wPtr, uPtr;
register digitPtr vPtr;
#else
register precision u, v;
{
register digitPtr wPtr, uPtr;
#endif
precision w;
register accumulator temp;
#ifndef ASM_16BIT
register digit noborrow;
#endif
register int i;
(void) pparm(u);
(void) pparm(v);
if (u->sign != v->sign) { /* Are we actually adding? */
w = pUndef;
v->sign = !v->sign; /* may generate -0 */
pset(&w, padd(u, v));
v->sign = !v->sign;
} else {
i = pcmp(u, v);
if (u->sign) i = -i; /* compare magnitudes only */
if (i < 0) {
w = u; u = v; v = w; /* make u the largest */
}
w = palloc(u->size); /* may produce much wasted storage */
if (w == pUndef) return w;
if (i < 0) w->sign = !u->sign; else w->sign = u->sign;
uPtr = u->value;
wPtr = w->value;
#ifndef ASM_16BIT
vPtr = v->value;
noborrow = 1;
HiDigit = v->value + v->size; /* digits in both args */
do {
temp = (BASE-1) - *vPtr++; /* 0 <= temp < base */
temp += *uPtr++; /* 0 <= temp < 2*base-1 */
temp += noborrow; /* 0 <= temp < 2*base */
noborrow = divBase(temp); /* 0 <= noborrow <= 1 */
*wPtr++ = modBase(temp);
} while (vPtr < HiDigit);
HiDigit = u->value + u->size; /* propagate borrow */
while (uPtr < HiDigit) {
temp = (BASE-1) + *uPtr++;
temp += noborrow; /* 0 <= temp < 2 * base */
noborrow = divBase(temp); /* 0 <= noborrow <= 1 */
*wPtr++ = modBase(temp);
} /* noborrow = 1 */
#else
i = v->size;
temp = u->size - i;
if (temp > 0) {
memcpy(wPtr + i, uPtr + i, temp * sizeof(digit));
}
if (memsubw(wPtr, uPtr, v->value, i)) { /* trashes uPtr */
memdecw(wPtr + i, temp);
}
wPtr += w->size;
#endif
do { /* normalize */
if (*--wPtr != 0) break;
} while (wPtr > w->value);
w->size = (wPtr - w->value) + 1;
}
pdestroy(u);
pdestroy(v);
return presult(w);
}