1 : /* doaddsub.c: bcmath library file. */
2 : /*
3 : Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
4 : Copyright (C) 2000 Philip A. Nelson
5 :
6 : This library is free software; you can redistribute it and/or
7 : modify it under the terms of the GNU Lesser General Public
8 : License as published by the Free Software Foundation; either
9 : version 2 of the License, or (at your option) any later version.
10 :
11 : This library is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details. (COPYING.LIB)
15 :
16 : You should have received a copy of the GNU Lesser General Public
17 : License along with this library; if not, write to:
18 :
19 : The Free Software Foundation, Inc.
20 : 59 Temple Place, Suite 330
21 : Boston, MA 02111-1307 USA.
22 :
23 : You may contact the author by:
24 : e-mail: philnelson@acm.org
25 : us-mail: Philip A. Nelson
26 : Computer Science Department, 9062
27 : Western Washington University
28 : Bellingham, WA 98226-9062
29 :
30 : *************************************************************************/
31 :
32 : #include <config.h>
33 : #include <stdio.h>
34 : #include <assert.h>
35 : #include <stdlib.h>
36 : #include <ctype.h>
37 : #include <stdarg.h>
38 : #include "bcmath.h"
39 : #include "private.h"
40 :
41 :
42 : /* Perform addition: N1 is added to N2 and the value is
43 : returned. The signs of N1 and N2 are ignored.
44 : SCALE_MIN is to set the minimum scale of the result. */
45 :
46 : bc_num
47 : _bc_do_add (n1, n2, scale_min)
48 : bc_num n1, n2;
49 : int scale_min;
50 22 : {
51 : bc_num sum;
52 : int sum_scale, sum_digits;
53 : char *n1ptr, *n2ptr, *sumptr;
54 : int carry, n1bytes, n2bytes;
55 : int count;
56 :
57 : /* Prepare sum. */
58 22 : sum_scale = MAX (n1->n_scale, n2->n_scale);
59 22 : sum_digits = MAX (n1->n_len, n2->n_len) + 1;
60 22 : sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
61 :
62 : /* Zero extra digits made by scale_min. */
63 22 : if (scale_min > sum_scale)
64 : {
65 4 : sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
66 22 : for (count = scale_min - sum_scale; count > 0; count--)
67 18 : *sumptr++ = 0;
68 : }
69 :
70 : /* Start with the fraction part. Initialize the pointers. */
71 22 : n1bytes = n1->n_scale;
72 22 : n2bytes = n2->n_scale;
73 22 : n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
74 22 : n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
75 22 : sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
76 :
77 : /* Add the fraction part. First copy the longer fraction.*/
78 22 : if (n1bytes != n2bytes)
79 : {
80 3 : if (n1bytes > n2bytes)
81 15 : while (n1bytes>n2bytes)
82 9 : { *sumptr-- = *n1ptr--; n1bytes--;}
83 : else
84 0 : while (n2bytes>n1bytes)
85 0 : { *sumptr-- = *n2ptr--; n2bytes--;}
86 : }
87 :
88 : /* Now add the remaining fraction part and equal size integer parts. */
89 22 : n1bytes += n1->n_len;
90 22 : n2bytes += n2->n_len;
91 22 : carry = 0;
92 216 : while ((n1bytes > 0) && (n2bytes > 0))
93 : {
94 172 : *sumptr = *n1ptr-- + *n2ptr-- + carry;
95 172 : if (*sumptr > (BASE-1))
96 : {
97 50 : carry = 1;
98 50 : *sumptr -= BASE;
99 : }
100 : else
101 122 : carry = 0;
102 172 : sumptr--;
103 172 : n1bytes--;
104 172 : n2bytes--;
105 : }
106 :
107 : /* Now add carry the longer integer part. */
108 22 : if (n1bytes == 0)
109 22 : { n1bytes = n2bytes; n1ptr = n2ptr; }
110 54 : while (n1bytes-- > 0)
111 : {
112 10 : *sumptr = *n1ptr-- + carry;
113 10 : if (*sumptr > (BASE-1))
114 : {
115 0 : carry = 1;
116 0 : *sumptr -= BASE;
117 : }
118 : else
119 10 : carry = 0;
120 10 : sumptr--;
121 : }
122 :
123 : /* Set final carry. */
124 22 : if (carry == 1)
125 1 : *sumptr += 1;
126 :
127 : /* Adjust sum and return. */
128 22 : _bc_rm_leading_zeros (sum);
129 22 : return sum;
130 : }
131 :
132 :
133 : /* Perform subtraction: N2 is subtracted from N1 and the value is
134 : returned. The signs of N1 and N2 are ignored. Also, N1 is
135 : assumed to be larger than N2. SCALE_MIN is the minimum scale
136 : of the result. */
137 :
138 : bc_num
139 : _bc_do_sub (n1, n2, scale_min)
140 : bc_num n1, n2;
141 : int scale_min;
142 16 : {
143 : bc_num diff;
144 : int diff_scale, diff_len;
145 : int min_scale, min_len;
146 : char *n1ptr, *n2ptr, *diffptr;
147 : int borrow, count, val;
148 :
149 : /* Allocate temporary storage. */
150 16 : diff_len = MAX (n1->n_len, n2->n_len);
151 16 : diff_scale = MAX (n1->n_scale, n2->n_scale);
152 16 : min_len = MIN (n1->n_len, n2->n_len);
153 16 : min_scale = MIN (n1->n_scale, n2->n_scale);
154 16 : diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
155 :
156 : /* Zero extra digits made by scale_min. */
157 16 : if (scale_min > diff_scale)
158 : {
159 13 : diffptr = (char *) (diff->n_value + diff_len + diff_scale);
160 30 : for (count = scale_min - diff_scale; count > 0; count--)
161 17 : *diffptr++ = 0;
162 : }
163 :
164 : /* Initialize the subtract. */
165 16 : n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
166 16 : n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
167 16 : diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
168 :
169 : /* Subtract the numbers. */
170 16 : borrow = 0;
171 :
172 : /* Take care of the longer scaled number. */
173 16 : if (n1->n_scale != min_scale)
174 : {
175 : /* n1 has the longer scale */
176 8 : for (count = n1->n_scale - min_scale; count > 0; count--)
177 6 : *diffptr-- = *n1ptr--;
178 : }
179 : else
180 : {
181 : /* n2 has the longer scale */
182 17 : for (count = n2->n_scale - min_scale; count > 0; count--)
183 : {
184 3 : val = - *n2ptr-- - borrow;
185 3 : if (val < 0)
186 : {
187 3 : val += BASE;
188 3 : borrow = 1;
189 : }
190 : else
191 0 : borrow = 0;
192 3 : *diffptr-- = val;
193 : }
194 : }
195 :
196 : /* Now do the equal length scale and integer parts. */
197 :
198 181 : for (count = 0; count < min_len + min_scale; count++)
199 : {
200 165 : val = *n1ptr-- - *n2ptr-- - borrow;
201 165 : if (val < 0)
202 : {
203 54 : val += BASE;
204 54 : borrow = 1;
205 : }
206 : else
207 111 : borrow = 0;
208 165 : *diffptr-- = val;
209 : }
210 :
211 : /* If n1 has more digits then n2, we now do that subtract. */
212 16 : if (diff_len != min_len)
213 : {
214 12 : for (count = diff_len - min_len; count > 0; count--)
215 : {
216 10 : val = *n1ptr-- - borrow;
217 10 : if (val < 0)
218 : {
219 0 : val += BASE;
220 0 : borrow = 1;
221 : }
222 : else
223 10 : borrow = 0;
224 10 : *diffptr-- = val;
225 : }
226 : }
227 :
228 : /* Clean up and return. */
229 16 : _bc_rm_leading_zeros (diff);
230 16 : return diff;
231 : }
232 :
|