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