xref: /haiku/src/libs/mapm/mapm_add.c (revision 59d799dabcba86f92658ddb402f634e262d9aae7)
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