root/ext/bcmath/libbcmath/src/doaddsub.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _bc_do_add
  2. _bc_do_sub

   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 {
  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   sum_scale = MAX (n1->n_scale, n2->n_scale);
  59   sum_digits = MAX (n1->n_len, n2->n_len) + 1;
  60   sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
  61 
  62   /* Zero extra digits made by scale_min. */
  63   if (scale_min > sum_scale)
  64     {
  65       sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
  66       for (count = scale_min - sum_scale; count > 0; count--)
  67         *sumptr++ = 0;
  68     }
  69 
  70   /* Start with the fraction part.  Initialize the pointers. */
  71   n1bytes = n1->n_scale;
  72   n2bytes = n2->n_scale;
  73   n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
  74   n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
  75   sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
  76 
  77   /* Add the fraction part.  First copy the longer fraction.*/
  78   if (n1bytes != n2bytes)
  79     {
  80       if (n1bytes > n2bytes)
  81         while (n1bytes>n2bytes)
  82           { *sumptr-- = *n1ptr--; n1bytes--;}
  83       else
  84         while (n2bytes>n1bytes)
  85           { *sumptr-- = *n2ptr--; n2bytes--;}
  86     }
  87 
  88   /* Now add the remaining fraction part and equal size integer parts. */
  89   n1bytes += n1->n_len;
  90   n2bytes += n2->n_len;
  91   carry = 0;
  92   while ((n1bytes > 0) && (n2bytes > 0))
  93     {
  94       *sumptr = *n1ptr-- + *n2ptr-- + carry;
  95       if (*sumptr > (BASE-1))
  96         {
  97            carry = 1;
  98            *sumptr -= BASE;
  99         }
 100       else
 101         carry = 0;
 102       sumptr--;
 103       n1bytes--;
 104       n2bytes--;
 105     }
 106 
 107   /* Now add carry the longer integer part. */
 108   if (n1bytes == 0)
 109     { n1bytes = n2bytes; n1ptr = n2ptr; }
 110   while (n1bytes-- > 0)
 111     {
 112       *sumptr = *n1ptr-- + carry;
 113       if (*sumptr > (BASE-1))
 114         {
 115            carry = 1;
 116            *sumptr -= BASE;
 117          }
 118       else
 119         carry = 0;
 120       sumptr--;
 121     }
 122 
 123   /* Set final carry. */
 124   if (carry == 1)
 125     *sumptr += 1;
 126 
 127   /* Adjust sum and return. */
 128   _bc_rm_leading_zeros (sum);
 129   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 {
 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   diff_len = MAX (n1->n_len, n2->n_len);
 151   diff_scale = MAX (n1->n_scale, n2->n_scale);
 152   min_len = MIN  (n1->n_len, n2->n_len);
 153   min_scale = MIN (n1->n_scale, n2->n_scale);
 154   diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
 155 
 156   /* Zero extra digits made by scale_min. */
 157   if (scale_min > diff_scale)
 158     {
 159       diffptr = (char *) (diff->n_value + diff_len + diff_scale);
 160       for (count = scale_min - diff_scale; count > 0; count--)
 161         *diffptr++ = 0;
 162     }
 163 
 164   /* Initialize the subtract. */
 165   n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
 166   n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
 167   diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
 168 
 169   /* Subtract the numbers. */
 170   borrow = 0;
 171 
 172   /* Take care of the longer scaled number. */
 173   if (n1->n_scale != min_scale)
 174     {
 175       /* n1 has the longer scale */
 176       for (count = n1->n_scale - min_scale; count > 0; count--)
 177         *diffptr-- = *n1ptr--;
 178     }
 179   else
 180     {
 181       /* n2 has the longer scale */
 182       for (count = n2->n_scale - min_scale; count > 0; count--)
 183         {
 184           val = - *n2ptr-- - borrow;
 185           if (val < 0)
 186             {
 187               val += BASE;
 188               borrow = 1;
 189             }
 190           else
 191             borrow = 0;
 192           *diffptr-- = val;
 193         }
 194     }
 195 
 196   /* Now do the equal length scale and integer parts. */
 197 
 198   for (count = 0; count < min_len + min_scale; count++)
 199     {
 200       val = *n1ptr-- - *n2ptr-- - borrow;
 201       if (val < 0)
 202         {
 203           val += BASE;
 204           borrow = 1;
 205         }
 206       else
 207         borrow = 0;
 208       *diffptr-- = val;
 209     }
 210 
 211   /* If n1 has more digits then n2, we now do that subtract. */
 212   if (diff_len != min_len)
 213     {
 214       for (count = diff_len - min_len; count > 0; count--)
 215         {
 216           val = *n1ptr-- - borrow;
 217           if (val < 0)
 218             {
 219               val += BASE;
 220               borrow = 1;
 221             }
 222           else
 223             borrow = 0;
 224           *diffptr-- = val;
 225         }
 226     }
 227 
 228   /* Clean up and return. */
 229   _bc_rm_leading_zeros (diff);
 230   return diff;
 231 }
 232 

/* [<][>][^][v][top][bottom][index][help] */