Back to index

php5  5.3.10
doaddsub.c
Go to the documentation of this file.
00001 /* doaddsub.c: bcmath library file. */
00002 /*
00003     Copyright (C) 1991, 1992, 1993, 1994, 1997 Free Software Foundation, Inc.
00004     Copyright (C) 2000 Philip A. Nelson
00005 
00006     This library is free software; you can redistribute it and/or
00007     modify it under the terms of the GNU Lesser General Public
00008     License as published by the Free Software Foundation; either
00009     version 2 of the License, or (at your option) any later version.
00010 
00011     This library is distributed in the hope that it will be useful,
00012     but WITHOUT ANY WARRANTY; without even the implied warranty of
00013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014     Lesser General Public License for more details.  (COPYING.LIB)
00015 
00016     You should have received a copy of the GNU Lesser General Public
00017     License along with this library; if not, write to:
00018 
00019       The Free Software Foundation, Inc.
00020       59 Temple Place, Suite 330
00021       Boston, MA 02111-1307 USA.
00022 
00023     You may contact the author by:
00024        e-mail:  philnelson@acm.org
00025       us-mail:  Philip A. Nelson
00026                 Computer Science Department, 9062
00027                 Western Washington University
00028                 Bellingham, WA 98226-9062
00029        
00030 *************************************************************************/
00031 
00032 #include <config.h>
00033 #include <stdio.h>
00034 #include <assert.h>
00035 #include <stdlib.h>
00036 #include <ctype.h>
00037 #include <stdarg.h>
00038 #include "bcmath.h"
00039 #include "private.h"
00040 
00041 
00042 /* Perform addition: N1 is added to N2 and the value is
00043    returned.  The signs of N1 and N2 are ignored.
00044    SCALE_MIN is to set the minimum scale of the result. */
00045 
00046  bc_num
00047 _bc_do_add (n1, n2, scale_min)
00048      bc_num n1, n2;
00049      int scale_min;
00050 {
00051   bc_num sum;
00052   int sum_scale, sum_digits;
00053   char *n1ptr, *n2ptr, *sumptr;
00054   int carry, n1bytes, n2bytes;
00055   int count;
00056 
00057   /* Prepare sum. */
00058   sum_scale = MAX (n1->n_scale, n2->n_scale);
00059   sum_digits = MAX (n1->n_len, n2->n_len) + 1;
00060   sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
00061 
00062   /* Zero extra digits made by scale_min. */
00063   if (scale_min > sum_scale)
00064     {
00065       sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
00066       for (count = scale_min - sum_scale; count > 0; count--)
00067        *sumptr++ = 0;
00068     }
00069 
00070   /* Start with the fraction part.  Initialize the pointers. */
00071   n1bytes = n1->n_scale;
00072   n2bytes = n2->n_scale;
00073   n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
00074   n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
00075   sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
00076 
00077   /* Add the fraction part.  First copy the longer fraction.*/
00078   if (n1bytes != n2bytes)
00079     {
00080       if (n1bytes > n2bytes)
00081        while (n1bytes>n2bytes)
00082          { *sumptr-- = *n1ptr--; n1bytes--;}
00083       else
00084        while (n2bytes>n1bytes)
00085          { *sumptr-- = *n2ptr--; n2bytes--;}
00086     }
00087 
00088   /* Now add the remaining fraction part and equal size integer parts. */
00089   n1bytes += n1->n_len;
00090   n2bytes += n2->n_len;
00091   carry = 0;
00092   while ((n1bytes > 0) && (n2bytes > 0))
00093     {
00094       *sumptr = *n1ptr-- + *n2ptr-- + carry;
00095       if (*sumptr > (BASE-1))
00096        {
00097           carry = 1;
00098           *sumptr -= BASE;
00099        }
00100       else
00101        carry = 0;
00102       sumptr--;
00103       n1bytes--;
00104       n2bytes--;
00105     }
00106 
00107   /* Now add carry the longer integer part. */
00108   if (n1bytes == 0)
00109     { n1bytes = n2bytes; n1ptr = n2ptr; }
00110   while (n1bytes-- > 0)
00111     {
00112       *sumptr = *n1ptr-- + carry;
00113       if (*sumptr > (BASE-1))
00114        {
00115           carry = 1;
00116           *sumptr -= BASE;
00117         }
00118       else
00119        carry = 0;
00120       sumptr--;
00121     }
00122 
00123   /* Set final carry. */
00124   if (carry == 1)
00125     *sumptr += 1;
00126 
00127   /* Adjust sum and return. */
00128   _bc_rm_leading_zeros (sum);
00129   return sum;
00130 }
00131 
00132 
00133 /* Perform subtraction: N2 is subtracted from N1 and the value is
00134    returned.  The signs of N1 and N2 are ignored.  Also, N1 is
00135    assumed to be larger than N2.  SCALE_MIN is the minimum scale
00136    of the result. */
00137 
00138  bc_num
00139 _bc_do_sub (n1, n2, scale_min)
00140      bc_num n1, n2;
00141      int scale_min;
00142 {
00143   bc_num diff;
00144   int diff_scale, diff_len;
00145   int min_scale, min_len;
00146   char *n1ptr, *n2ptr, *diffptr;
00147   int borrow, count, val;
00148 
00149   /* Allocate temporary storage. */
00150   diff_len = MAX (n1->n_len, n2->n_len);
00151   diff_scale = MAX (n1->n_scale, n2->n_scale);
00152   min_len = MIN  (n1->n_len, n2->n_len);
00153   min_scale = MIN (n1->n_scale, n2->n_scale);
00154   diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
00155 
00156   /* Zero extra digits made by scale_min. */
00157   if (scale_min > diff_scale)
00158     {
00159       diffptr = (char *) (diff->n_value + diff_len + diff_scale);
00160       for (count = scale_min - diff_scale; count > 0; count--)
00161        *diffptr++ = 0;
00162     }
00163 
00164   /* Initialize the subtract. */
00165   n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
00166   n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
00167   diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
00168 
00169   /* Subtract the numbers. */
00170   borrow = 0;
00171 
00172   /* Take care of the longer scaled number. */
00173   if (n1->n_scale != min_scale)
00174     {
00175       /* n1 has the longer scale */
00176       for (count = n1->n_scale - min_scale; count > 0; count--)
00177        *diffptr-- = *n1ptr--;
00178     }
00179   else
00180     {
00181       /* n2 has the longer scale */
00182       for (count = n2->n_scale - min_scale; count > 0; count--)
00183        {
00184          val = - *n2ptr-- - borrow;
00185          if (val < 0)
00186            {
00187              val += BASE;
00188              borrow = 1;
00189            }
00190          else
00191            borrow = 0;
00192          *diffptr-- = val;
00193        }
00194     }
00195 
00196   /* Now do the equal length scale and integer parts. */
00197 
00198   for (count = 0; count < min_len + min_scale; count++)
00199     {
00200       val = *n1ptr-- - *n2ptr-- - borrow;
00201       if (val < 0)
00202        {
00203          val += BASE;
00204          borrow = 1;
00205        }
00206       else
00207        borrow = 0;
00208       *diffptr-- = val;
00209     }
00210 
00211   /* If n1 has more digits then n2, we now do that subtract. */
00212   if (diff_len != min_len)
00213     {
00214       for (count = diff_len - min_len; count > 0; count--)
00215        {
00216          val = *n1ptr-- - borrow;
00217          if (val < 0)
00218            {
00219              val += BASE;
00220              borrow = 1;
00221            }
00222          else
00223            borrow = 0;
00224          *diffptr-- = val;
00225        }
00226     }
00227 
00228   /* Clean up and return. */
00229   _bc_rm_leading_zeros (diff);
00230   return diff;
00231 }
00232