doaddsub.c 5.8 KB

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