1*59d799daSIngo Weinhold
2*59d799daSIngo Weinhold /*
3*59d799daSIngo Weinhold * M_APM - mapm_add.c
4*59d799daSIngo Weinhold *
5*59d799daSIngo Weinhold * Copyright (C) 1999 - 2007 Michael C. Ring
6*59d799daSIngo Weinhold *
7*59d799daSIngo Weinhold * Permission to use, copy, and distribute this software and its
8*59d799daSIngo Weinhold * documentation for any purpose with or without fee is hereby granted,
9*59d799daSIngo Weinhold * provided that the above copyright notice appear in all copies and
10*59d799daSIngo Weinhold * that both that copyright notice and this permission notice appear
11*59d799daSIngo Weinhold * in supporting documentation.
12*59d799daSIngo Weinhold *
13*59d799daSIngo Weinhold * Permission to modify the software is granted. Permission to distribute
14*59d799daSIngo Weinhold * the modified code is granted. Modifications are to be distributed by
15*59d799daSIngo Weinhold * using the file 'license.txt' as a template to modify the file header.
16*59d799daSIngo Weinhold * 'license.txt' is available in the official MAPM distribution.
17*59d799daSIngo Weinhold *
18*59d799daSIngo Weinhold * This software is provided "as is" without express or implied warranty.
19*59d799daSIngo Weinhold */
20*59d799daSIngo Weinhold
21*59d799daSIngo Weinhold /*
22*59d799daSIngo Weinhold * $Id: mapm_add.c,v 1.5 2007/12/03 01:33:39 mike Exp $
23*59d799daSIngo Weinhold *
24*59d799daSIngo Weinhold * This file contains basic addition/subtraction functions
25*59d799daSIngo Weinhold *
26*59d799daSIngo Weinhold * $Log: mapm_add.c,v $
27*59d799daSIngo Weinhold * Revision 1.5 2007/12/03 01:33:39 mike
28*59d799daSIngo Weinhold * Update license
29*59d799daSIngo Weinhold *
30*59d799daSIngo Weinhold * Revision 1.4 2003/12/04 01:15:42 mike
31*59d799daSIngo Weinhold * redo math with 'borrow'
32*59d799daSIngo Weinhold *
33*59d799daSIngo Weinhold * Revision 1.3 2002/11/03 22:03:31 mike
34*59d799daSIngo Weinhold * Updated function parameters to use the modern style
35*59d799daSIngo Weinhold *
36*59d799daSIngo Weinhold * Revision 1.2 2001/07/16 18:59:25 mike
37*59d799daSIngo Weinhold * add function M_free_all_add
38*59d799daSIngo Weinhold *
39*59d799daSIngo Weinhold * Revision 1.1 1999/05/10 20:56:31 mike
40*59d799daSIngo Weinhold * Initial revision
41*59d799daSIngo Weinhold */
42*59d799daSIngo Weinhold
43*59d799daSIngo Weinhold #include "m_apm_lc.h"
44*59d799daSIngo Weinhold
45*59d799daSIngo Weinhold static M_APM M_work1 = NULL;
46*59d799daSIngo Weinhold static M_APM M_work2 = NULL;
47*59d799daSIngo Weinhold static int M_add_firsttime = TRUE;
48*59d799daSIngo Weinhold
49*59d799daSIngo Weinhold /****************************************************************************/
M_free_all_add()50*59d799daSIngo Weinhold void M_free_all_add()
51*59d799daSIngo Weinhold {
52*59d799daSIngo Weinhold if (M_add_firsttime == FALSE)
53*59d799daSIngo Weinhold {
54*59d799daSIngo Weinhold m_apm_free(M_work1);
55*59d799daSIngo Weinhold m_apm_free(M_work2);
56*59d799daSIngo Weinhold M_add_firsttime = TRUE;
57*59d799daSIngo Weinhold }
58*59d799daSIngo Weinhold }
59*59d799daSIngo Weinhold /****************************************************************************/
m_apm_add(M_APM r,M_APM a,M_APM b)60*59d799daSIngo Weinhold void m_apm_add(M_APM r, M_APM a, M_APM b)
61*59d799daSIngo Weinhold {
62*59d799daSIngo Weinhold int j, carry, sign, aexp, bexp, adigits, bdigits;
63*59d799daSIngo Weinhold
64*59d799daSIngo Weinhold if (M_add_firsttime)
65*59d799daSIngo Weinhold {
66*59d799daSIngo Weinhold M_add_firsttime = FALSE;
67*59d799daSIngo Weinhold M_work1 = m_apm_init();
68*59d799daSIngo Weinhold M_work2 = m_apm_init();
69*59d799daSIngo Weinhold }
70*59d799daSIngo Weinhold
71*59d799daSIngo Weinhold if (a->m_apm_sign == 0)
72*59d799daSIngo Weinhold {
73*59d799daSIngo Weinhold m_apm_copy(r,b);
74*59d799daSIngo Weinhold return;
75*59d799daSIngo Weinhold }
76*59d799daSIngo Weinhold
77*59d799daSIngo Weinhold if (b->m_apm_sign == 0)
78*59d799daSIngo Weinhold {
79*59d799daSIngo Weinhold m_apm_copy(r,a);
80*59d799daSIngo Weinhold return;
81*59d799daSIngo Weinhold }
82*59d799daSIngo Weinhold
83*59d799daSIngo Weinhold if (a->m_apm_sign == 1 && b->m_apm_sign == -1)
84*59d799daSIngo Weinhold {
85*59d799daSIngo Weinhold b->m_apm_sign = 1;
86*59d799daSIngo Weinhold m_apm_subtract(r,a,b);
87*59d799daSIngo Weinhold b->m_apm_sign = -1;
88*59d799daSIngo Weinhold return;
89*59d799daSIngo Weinhold }
90*59d799daSIngo Weinhold
91*59d799daSIngo Weinhold if (a->m_apm_sign == -1 && b->m_apm_sign == 1)
92*59d799daSIngo Weinhold {
93*59d799daSIngo Weinhold a->m_apm_sign = 1;
94*59d799daSIngo Weinhold m_apm_subtract(r,b,a);
95*59d799daSIngo Weinhold a->m_apm_sign = -1;
96*59d799daSIngo Weinhold return;
97*59d799daSIngo Weinhold }
98*59d799daSIngo Weinhold
99*59d799daSIngo Weinhold sign = a->m_apm_sign; /* signs are the same, result will be same */
100*59d799daSIngo Weinhold
101*59d799daSIngo Weinhold aexp = a->m_apm_exponent;
102*59d799daSIngo Weinhold bexp = b->m_apm_exponent;
103*59d799daSIngo Weinhold
104*59d799daSIngo Weinhold m_apm_copy(M_work1, a);
105*59d799daSIngo Weinhold m_apm_copy(M_work2, b);
106*59d799daSIngo Weinhold
107*59d799daSIngo Weinhold /*
108*59d799daSIngo Weinhold * scale by at least 1 factor of 10 in case the MSB carrys
109*59d799daSIngo Weinhold */
110*59d799daSIngo Weinhold
111*59d799daSIngo Weinhold if (aexp == bexp)
112*59d799daSIngo Weinhold {
113*59d799daSIngo Weinhold M_apm_scale(M_work1, 2); /* shift 2 digits == 1 byte for efficiency */
114*59d799daSIngo Weinhold M_apm_scale(M_work2, 2);
115*59d799daSIngo Weinhold }
116*59d799daSIngo Weinhold else
117*59d799daSIngo Weinhold {
118*59d799daSIngo Weinhold if (aexp > bexp)
119*59d799daSIngo Weinhold {
120*59d799daSIngo Weinhold M_apm_scale(M_work1, 2);
121*59d799daSIngo Weinhold M_apm_scale(M_work2, (aexp + 2 - bexp));
122*59d799daSIngo Weinhold }
123*59d799daSIngo Weinhold else /* aexp < bexp */
124*59d799daSIngo Weinhold {
125*59d799daSIngo Weinhold M_apm_scale(M_work2, 2);
126*59d799daSIngo Weinhold M_apm_scale(M_work1, (bexp + 2 - aexp));
127*59d799daSIngo Weinhold }
128*59d799daSIngo Weinhold }
129*59d799daSIngo Weinhold
130*59d799daSIngo Weinhold adigits = M_work1->m_apm_datalength;
131*59d799daSIngo Weinhold bdigits = M_work2->m_apm_datalength;
132*59d799daSIngo Weinhold
133*59d799daSIngo Weinhold if (adigits >= bdigits)
134*59d799daSIngo Weinhold {
135*59d799daSIngo Weinhold m_apm_copy(r, M_work1);
136*59d799daSIngo Weinhold j = (bdigits + 1) >> 1;
137*59d799daSIngo Weinhold carry = 0;
138*59d799daSIngo Weinhold
139*59d799daSIngo Weinhold while (TRUE)
140*59d799daSIngo Weinhold {
141*59d799daSIngo Weinhold j--;
142*59d799daSIngo Weinhold r->m_apm_data[j] += carry + M_work2->m_apm_data[j];
143*59d799daSIngo Weinhold
144*59d799daSIngo Weinhold if (r->m_apm_data[j] >= 100)
145*59d799daSIngo Weinhold {
146*59d799daSIngo Weinhold r->m_apm_data[j] -= 100;
147*59d799daSIngo Weinhold carry = 1;
148*59d799daSIngo Weinhold }
149*59d799daSIngo Weinhold else
150*59d799daSIngo Weinhold carry = 0;
151*59d799daSIngo Weinhold
152*59d799daSIngo Weinhold if (j == 0)
153*59d799daSIngo Weinhold break;
154*59d799daSIngo Weinhold }
155*59d799daSIngo Weinhold }
156*59d799daSIngo Weinhold else
157*59d799daSIngo Weinhold {
158*59d799daSIngo Weinhold m_apm_copy(r, M_work2);
159*59d799daSIngo Weinhold j = (adigits + 1) >> 1;
160*59d799daSIngo Weinhold carry = 0;
161*59d799daSIngo Weinhold
162*59d799daSIngo Weinhold while (TRUE)
163*59d799daSIngo Weinhold {
164*59d799daSIngo Weinhold j--;
165*59d799daSIngo Weinhold r->m_apm_data[j] += carry + M_work1->m_apm_data[j];
166*59d799daSIngo Weinhold
167*59d799daSIngo Weinhold if (r->m_apm_data[j] >= 100)
168*59d799daSIngo Weinhold {
169*59d799daSIngo Weinhold r->m_apm_data[j] -= 100;
170*59d799daSIngo Weinhold carry = 1;
171*59d799daSIngo Weinhold }
172*59d799daSIngo Weinhold else
173*59d799daSIngo Weinhold carry = 0;
174*59d799daSIngo Weinhold
175*59d799daSIngo Weinhold if (j == 0)
176*59d799daSIngo Weinhold break;
177*59d799daSIngo Weinhold }
178*59d799daSIngo Weinhold }
179*59d799daSIngo Weinhold
180*59d799daSIngo Weinhold r->m_apm_sign = sign;
181*59d799daSIngo Weinhold
182*59d799daSIngo Weinhold M_apm_normalize(r);
183*59d799daSIngo Weinhold }
184*59d799daSIngo Weinhold /****************************************************************************/
m_apm_subtract(M_APM r,M_APM a,M_APM b)185*59d799daSIngo Weinhold void m_apm_subtract(M_APM r, M_APM a, M_APM b)
186*59d799daSIngo Weinhold {
187*59d799daSIngo Weinhold int itmp, j, flag, icompare, sign, aexp, bexp,
188*59d799daSIngo Weinhold borrow, adigits, bdigits;
189*59d799daSIngo Weinhold
190*59d799daSIngo Weinhold if (M_add_firsttime)
191*59d799daSIngo Weinhold {
192*59d799daSIngo Weinhold M_add_firsttime = FALSE;
193*59d799daSIngo Weinhold M_work1 = m_apm_init();
194*59d799daSIngo Weinhold M_work2 = m_apm_init();
195*59d799daSIngo Weinhold }
196*59d799daSIngo Weinhold
197*59d799daSIngo Weinhold if (b->m_apm_sign == 0)
198*59d799daSIngo Weinhold {
199*59d799daSIngo Weinhold m_apm_copy(r,a);
200*59d799daSIngo Weinhold return;
201*59d799daSIngo Weinhold }
202*59d799daSIngo Weinhold
203*59d799daSIngo Weinhold if (a->m_apm_sign == 0)
204*59d799daSIngo Weinhold {
205*59d799daSIngo Weinhold m_apm_copy(r,b);
206*59d799daSIngo Weinhold r->m_apm_sign = -(r->m_apm_sign);
207*59d799daSIngo Weinhold return;
208*59d799daSIngo Weinhold }
209*59d799daSIngo Weinhold
210*59d799daSIngo Weinhold if (a->m_apm_sign == 1 && b->m_apm_sign == -1)
211*59d799daSIngo Weinhold {
212*59d799daSIngo Weinhold b->m_apm_sign = 1;
213*59d799daSIngo Weinhold m_apm_add(r,a,b);
214*59d799daSIngo Weinhold b->m_apm_sign = -1;
215*59d799daSIngo Weinhold return;
216*59d799daSIngo Weinhold }
217*59d799daSIngo Weinhold
218*59d799daSIngo Weinhold if (a->m_apm_sign == -1 && b->m_apm_sign == 1)
219*59d799daSIngo Weinhold {
220*59d799daSIngo Weinhold b->m_apm_sign = -1;
221*59d799daSIngo Weinhold m_apm_add(r,a,b);
222*59d799daSIngo Weinhold b->m_apm_sign = 1;
223*59d799daSIngo Weinhold return;
224*59d799daSIngo Weinhold }
225*59d799daSIngo Weinhold
226*59d799daSIngo Weinhold /* now, the signs are the same */
227*59d799daSIngo Weinhold /* make a positive working copy */
228*59d799daSIngo Weinhold
229*59d799daSIngo Weinhold m_apm_absolute_value(M_work1, a);
230*59d799daSIngo Weinhold m_apm_absolute_value(M_work2, b);
231*59d799daSIngo Weinhold
232*59d799daSIngo Weinhold /* are they the same?? if so, the result is zero */
233*59d799daSIngo Weinhold
234*59d799daSIngo Weinhold if ((icompare = m_apm_compare(M_work1, M_work2)) == 0)
235*59d799daSIngo Weinhold {
236*59d799daSIngo Weinhold M_set_to_zero(r);
237*59d799daSIngo Weinhold return;
238*59d799daSIngo Weinhold }
239*59d799daSIngo Weinhold
240*59d799daSIngo Weinhold if (icompare == 1) /* |a| > |b| (do A-B) */
241*59d799daSIngo Weinhold {
242*59d799daSIngo Weinhold flag = TRUE;
243*59d799daSIngo Weinhold sign = a->m_apm_sign;
244*59d799daSIngo Weinhold }
245*59d799daSIngo Weinhold else /* |b| > |a| (do B-A) */
246*59d799daSIngo Weinhold {
247*59d799daSIngo Weinhold flag = FALSE;
248*59d799daSIngo Weinhold sign = -(a->m_apm_sign);
249*59d799daSIngo Weinhold }
250*59d799daSIngo Weinhold
251*59d799daSIngo Weinhold aexp = M_work1->m_apm_exponent;
252*59d799daSIngo Weinhold bexp = M_work2->m_apm_exponent;
253*59d799daSIngo Weinhold
254*59d799daSIngo Weinhold if (aexp > bexp)
255*59d799daSIngo Weinhold M_apm_scale(M_work2, (aexp - bexp));
256*59d799daSIngo Weinhold
257*59d799daSIngo Weinhold if (aexp < bexp)
258*59d799daSIngo Weinhold M_apm_scale(M_work1, (bexp - aexp));
259*59d799daSIngo Weinhold
260*59d799daSIngo Weinhold adigits = M_work1->m_apm_datalength;
261*59d799daSIngo Weinhold bdigits = M_work2->m_apm_datalength;
262*59d799daSIngo Weinhold
263*59d799daSIngo Weinhold if (adigits > bdigits)
264*59d799daSIngo Weinhold M_apm_pad(M_work2, adigits);
265*59d799daSIngo Weinhold
266*59d799daSIngo Weinhold if (adigits < bdigits)
267*59d799daSIngo Weinhold M_apm_pad(M_work1, bdigits);
268*59d799daSIngo Weinhold
269*59d799daSIngo Weinhold if (flag) /* perform A-B, M_work1 - M_work2 */
270*59d799daSIngo Weinhold {
271*59d799daSIngo Weinhold m_apm_copy(r, M_work1);
272*59d799daSIngo Weinhold j = (r->m_apm_datalength + 1) >> 1;
273*59d799daSIngo Weinhold borrow = 0;
274*59d799daSIngo Weinhold
275*59d799daSIngo Weinhold while (TRUE)
276*59d799daSIngo Weinhold {
277*59d799daSIngo Weinhold j--;
278*59d799daSIngo Weinhold itmp = (int)r->m_apm_data[j] - ((int)M_work2->m_apm_data[j] + borrow);
279*59d799daSIngo Weinhold
280*59d799daSIngo Weinhold if (itmp >= 0)
281*59d799daSIngo Weinhold {
282*59d799daSIngo Weinhold r->m_apm_data[j] = (UCHAR)itmp;
283*59d799daSIngo Weinhold borrow = 0;
284*59d799daSIngo Weinhold }
285*59d799daSIngo Weinhold else
286*59d799daSIngo Weinhold {
287*59d799daSIngo Weinhold r->m_apm_data[j] = (UCHAR)(100 + itmp);
288*59d799daSIngo Weinhold borrow = 1;
289*59d799daSIngo Weinhold }
290*59d799daSIngo Weinhold
291*59d799daSIngo Weinhold if (j == 0)
292*59d799daSIngo Weinhold break;
293*59d799daSIngo Weinhold }
294*59d799daSIngo Weinhold }
295*59d799daSIngo Weinhold else /* perform B-A, M_work2 - M_work1 */
296*59d799daSIngo Weinhold {
297*59d799daSIngo Weinhold m_apm_copy(r, M_work2);
298*59d799daSIngo Weinhold j = (r->m_apm_datalength + 1) >> 1;
299*59d799daSIngo Weinhold borrow = 0;
300*59d799daSIngo Weinhold
301*59d799daSIngo Weinhold while (TRUE)
302*59d799daSIngo Weinhold {
303*59d799daSIngo Weinhold j--;
304*59d799daSIngo Weinhold itmp = (int)r->m_apm_data[j] - ((int)M_work1->m_apm_data[j] + borrow);
305*59d799daSIngo Weinhold
306*59d799daSIngo Weinhold if (itmp >= 0)
307*59d799daSIngo Weinhold {
308*59d799daSIngo Weinhold r->m_apm_data[j] = (UCHAR)itmp;
309*59d799daSIngo Weinhold borrow = 0;
310*59d799daSIngo Weinhold }
311*59d799daSIngo Weinhold else
312*59d799daSIngo Weinhold {
313*59d799daSIngo Weinhold r->m_apm_data[j] = (UCHAR)(100 + itmp);
314*59d799daSIngo Weinhold borrow = 1;
315*59d799daSIngo Weinhold }
316*59d799daSIngo Weinhold
317*59d799daSIngo Weinhold if (j == 0)
318*59d799daSIngo Weinhold break;
319*59d799daSIngo Weinhold }
320*59d799daSIngo Weinhold }
321*59d799daSIngo Weinhold
322*59d799daSIngo Weinhold r->m_apm_sign = sign;
323*59d799daSIngo Weinhold
324*59d799daSIngo Weinhold M_apm_normalize(r);
325*59d799daSIngo Weinhold }
326*59d799daSIngo Weinhold /****************************************************************************/
327