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