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. (LICENSE)
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 <stdlib.h>
35 #include <ctype.h>
36 #include <stdarg.h>
37 #include "bcmath.h"
38 #include "private.h"
39
40
41 /* Perform addition: N1 is added to N2 and the value is
42 returned. The signs of N1 and N2 are ignored.
43 SCALE_MIN is to set the minimum scale of the result. */
44
45 bc_num
_bc_do_add(n1,n2,scale_min)46 _bc_do_add (n1, n2, scale_min)
47 bc_num n1, n2;
48 int scale_min;
49 {
50 bc_num sum;
51 int sum_scale, sum_digits;
52 char *n1ptr, *n2ptr, *sumptr;
53 int carry, n1bytes, n2bytes;
54 int count;
55
56 /* Prepare sum. */
57 sum_scale = MAX (n1->n_scale, n2->n_scale);
58 sum_digits = MAX (n1->n_len, n2->n_len) + 1;
59 sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
60
61 /* Zero extra digits made by scale_min. */
62 if (scale_min > sum_scale)
63 {
64 sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
65 for (count = scale_min - sum_scale; count > 0; count--)
66 *sumptr++ = 0;
67 }
68
69 /* Start with the fraction part. Initialize the pointers. */
70 n1bytes = n1->n_scale;
71 n2bytes = n2->n_scale;
72 n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
73 n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
74 sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
75
76 /* Add the fraction part. First copy the longer fraction.*/
77 if (n1bytes != n2bytes)
78 {
79 if (n1bytes > n2bytes)
80 while (n1bytes>n2bytes)
81 { *sumptr-- = *n1ptr--; n1bytes--;}
82 else
83 while (n2bytes>n1bytes)
84 { *sumptr-- = *n2ptr--; n2bytes--;}
85 }
86
87 /* Now add the remaining fraction part and equal size integer parts. */
88 n1bytes += n1->n_len;
89 n2bytes += n2->n_len;
90 carry = 0;
91 while ((n1bytes > 0) && (n2bytes > 0))
92 {
93 *sumptr = *n1ptr-- + *n2ptr-- + carry;
94 if (*sumptr > (BASE-1))
95 {
96 carry = 1;
97 *sumptr -= BASE;
98 }
99 else
100 carry = 0;
101 sumptr--;
102 n1bytes--;
103 n2bytes--;
104 }
105
106 /* Now add carry the longer integer part. */
107 if (n1bytes == 0)
108 { n1bytes = n2bytes; n1ptr = n2ptr; }
109 while (n1bytes-- > 0)
110 {
111 *sumptr = *n1ptr-- + carry;
112 if (*sumptr > (BASE-1))
113 {
114 carry = 1;
115 *sumptr -= BASE;
116 }
117 else
118 carry = 0;
119 sumptr--;
120 }
121
122 /* Set final carry. */
123 if (carry == 1)
124 *sumptr += 1;
125
126 /* Adjust sum and return. */
127 _bc_rm_leading_zeros (sum);
128 return sum;
129 }
130
131
132 /* Perform subtraction: N2 is subtracted from N1 and the value is
133 returned. The signs of N1 and N2 are ignored. Also, N1 is
134 assumed to be larger than N2. SCALE_MIN is the minimum scale
135 of the result. */
136
137 bc_num
_bc_do_sub(n1,n2,scale_min)138 _bc_do_sub (n1, n2, scale_min)
139 bc_num n1, n2;
140 int scale_min;
141 {
142 bc_num diff;
143 int diff_scale, diff_len;
144 int min_scale, min_len;
145 char *n1ptr, *n2ptr, *diffptr;
146 int borrow, count, val;
147
148 /* Allocate temporary storage. */
149 diff_len = MAX (n1->n_len, n2->n_len);
150 diff_scale = MAX (n1->n_scale, n2->n_scale);
151 min_len = MIN (n1->n_len, n2->n_len);
152 min_scale = MIN (n1->n_scale, n2->n_scale);
153 diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
154
155 /* Zero extra digits made by scale_min. */
156 if (scale_min > diff_scale)
157 {
158 diffptr = (char *) (diff->n_value + diff_len + diff_scale);
159 for (count = scale_min - diff_scale; count > 0; count--)
160 *diffptr++ = 0;
161 }
162
163 /* Initialize the subtract. */
164 n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
165 n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
166 diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
167
168 /* Subtract the numbers. */
169 borrow = 0;
170
171 /* Take care of the longer scaled number. */
172 if (n1->n_scale != min_scale)
173 {
174 /* n1 has the longer scale */
175 for (count = n1->n_scale - min_scale; count > 0; count--)
176 *diffptr-- = *n1ptr--;
177 }
178 else
179 {
180 /* n2 has the longer scale */
181 for (count = n2->n_scale - min_scale; count > 0; count--)
182 {
183 val = - *n2ptr-- - borrow;
184 if (val < 0)
185 {
186 val += BASE;
187 borrow = 1;
188 }
189 else
190 borrow = 0;
191 *diffptr-- = val;
192 }
193 }
194
195 /* Now do the equal length scale and integer parts. */
196
197 for (count = 0; count < min_len + min_scale; count++)
198 {
199 val = *n1ptr-- - *n2ptr-- - borrow;
200 if (val < 0)
201 {
202 val += BASE;
203 borrow = 1;
204 }
205 else
206 borrow = 0;
207 *diffptr-- = val;
208 }
209
210 /* If n1 has more digits then n2, we now do that subtract. */
211 if (diff_len != min_len)
212 {
213 for (count = diff_len - min_len; count > 0; count--)
214 {
215 val = *n1ptr-- - borrow;
216 if (val < 0)
217 {
218 val += BASE;
219 borrow = 1;
220 }
221 else
222 borrow = 0;
223 *diffptr-- = val;
224 }
225 }
226
227 /* Clean up and return. */
228 _bc_rm_leading_zeros (diff);
229 return diff;
230 }
231