Blame lib/number.c

Packit 70b277
/* number.c: Implements arbitrary precision numbers. */
Packit 70b277
/*
Packit 70b277
    Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000, 2012-2017 Free Software Foundation, Inc.
Packit 70b277
Packit 70b277
    This program is free software; you can redistribute it and/or modify
Packit 70b277
    it under the terms of the GNU General Public License as published by
Packit 70b277
    the Free Software Foundation; either version 3 of the License , or
Packit 70b277
    (at your option) any later version.
Packit 70b277
Packit 70b277
    This program is distributed in the hope that it will be useful,
Packit 70b277
    but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 70b277
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 70b277
    GNU General Public License for more details.
Packit 70b277
Packit 70b277
    You should have received a copy of the GNU General Public License
Packit 70b277
    along with this program; see the file COPYING.  If not, write to:
Packit 70b277
Packit 70b277
      The Free Software Foundation, Inc.
Packit 70b277
      51 Franklin Street, Fifth Floor
Packit 70b277
      Boston, MA 02110-1301  USA
Packit 70b277
Packit 70b277
Packit 70b277
    You may contact the author by:
Packit 70b277
       e-mail:  philnelson@acm.org
Packit 70b277
      us-mail:  Philip A. Nelson
Packit 70b277
                Computer Science Department, 9062
Packit 70b277
                Western Washington University
Packit 70b277
                Bellingham, WA 98226-9062
Packit 70b277
       
Packit 70b277
*************************************************************************/
Packit 70b277
Packit 70b277
#include <stdio.h>
Packit 70b277
#include <config.h>
Packit 70b277
#include <number.h>
Packit 70b277
#include <assert.h>
Packit 70b277
#ifdef HAVE_STDLIB_H
Packit 70b277
#include <stdlib.h>
Packit 70b277
#endif
Packit 70b277
#ifdef HAVE_STRING_H
Packit 70b277
#include <string.h>
Packit 70b277
#endif
Packit 70b277
#include <ctype.h>
Packit 70b277
Packit 70b277
/* Prototypes needed for external utility routines. */
Packit 70b277
Packit 70b277
#define bc_rt_warn rt_warn
Packit 70b277
#define bc_rt_error rt_error
Packit 70b277
#define bc_out_of_memory out_of_memory
Packit 70b277
Packit 70b277
void rt_warn (const char *mesg ,...);
Packit 70b277
void rt_error (const char *mesg ,...);
Packit 70b277
void out_of_memory (void);
Packit 70b277
Packit 70b277
/* Storage used for special numbers. */
Packit 70b277
bc_num _zero_;
Packit 70b277
bc_num _one_;
Packit 70b277
bc_num _two_;
Packit 70b277
Packit 70b277
static bc_num _bc_Free_list = NULL;
Packit 70b277
Packit 70b277
/* new_num allocates a number and sets fields to known values. */
Packit 70b277
Packit 70b277
bc_num
Packit 70b277
bc_new_num (int length, int scale)
Packit 70b277
{
Packit 70b277
  bc_num temp;
Packit 70b277
Packit 70b277
  if (_bc_Free_list != NULL) {
Packit 70b277
    temp = _bc_Free_list;
Packit 70b277
    _bc_Free_list = temp->n_next;
Packit 70b277
  } else {
Packit 70b277
    temp = (bc_num) malloc (sizeof(bc_struct));
Packit 70b277
    if (temp == NULL) bc_out_of_memory ();
Packit 70b277
  }
Packit 70b277
  temp->n_sign = PLUS;
Packit 70b277
  temp->n_len = length;
Packit 70b277
  temp->n_scale = scale;
Packit 70b277
  temp->n_refs = 1;
Packit 70b277
  temp->n_ptr = (char *) malloc (length+scale);
Packit 70b277
  if (temp->n_ptr == NULL) bc_out_of_memory();
Packit 70b277
  temp->n_value = temp->n_ptr;
Packit 70b277
  memset (temp->n_ptr, 0, length+scale);
Packit 70b277
  return temp;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* "Frees" a bc_num NUM.  Actually decreases reference count and only
Packit 70b277
   frees the storage if reference count is zero. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_free_num (bc_num *num)
Packit 70b277
{
Packit 70b277
  if (*num == NULL) return;
Packit 70b277
  (*num)->n_refs--;
Packit 70b277
  if ((*num)->n_refs == 0) {
Packit 70b277
    if ((*num)->n_ptr)
Packit 70b277
      free ((*num)->n_ptr);
Packit 70b277
    (*num)->n_next = _bc_Free_list;
Packit 70b277
    _bc_Free_list = *num;
Packit 70b277
  }
Packit 70b277
  *num = NULL;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Intitialize the number package! */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_init_numbers (void)
Packit 70b277
{
Packit 70b277
  _zero_ = bc_new_num (1,0);
Packit 70b277
  _one_  = bc_new_num (1,0);
Packit 70b277
  _one_->n_value[0] = 1;
Packit 70b277
  _two_  = bc_new_num (1,0);
Packit 70b277
  _two_->n_value[0] = 2;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Make a copy of a number!  Just increments the reference count! */
Packit 70b277
Packit 70b277
bc_num
Packit 70b277
bc_copy_num (bc_num num)
Packit 70b277
{
Packit 70b277
  num->n_refs++;
Packit 70b277
  return num;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Initialize a number NUM by making it a copy of zero. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_init_num (bc_num *num)
Packit 70b277
{
Packit 70b277
  *num = bc_copy_num (_zero_);
Packit 70b277
}
Packit 70b277
/* For many things, we may have leading zeros in a number NUM.
Packit 70b277
   _bc_rm_leading_zeros just moves the data "value" pointer to the
Packit 70b277
   correct place and adjusts the length. */
Packit 70b277
Packit 70b277
static void
Packit 70b277
_bc_rm_leading_zeros (bc_num num)
Packit 70b277
{
Packit 70b277
  /* We can move n_value to point to the first non zero digit! */
Packit 70b277
  while (*num->n_value == 0 && num->n_len > 1) {
Packit 70b277
    num->n_value++;
Packit 70b277
    num->n_len--;
Packit 70b277
  }
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Compare two bc numbers.  Return value is 0 if equal, -1 if N1 is less
Packit 70b277
   than N2 and +1 if N1 is greater than N2.  If USE_SIGN is false, just
Packit 70b277
   compare the magnitudes. */
Packit 70b277
Packit 70b277
static int
Packit 70b277
_bc_do_compare ( bc_num n1, bc_num n2, int use_sign, int ignore_last )
Packit 70b277
{
Packit 70b277
  char *n1ptr, *n2ptr;
Packit 70b277
  int  count;
Packit 70b277
Packit 70b277
  /* First, compare signs. */
Packit 70b277
  if (use_sign && n1->n_sign != n2->n_sign)
Packit 70b277
    {
Packit 70b277
      if (n1->n_sign == PLUS)
Packit 70b277
	return (1);	/* Positive N1 > Negative N2 */
Packit 70b277
      else
Packit 70b277
	return (-1);	/* Negative N1 < Positive N1 */
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Now compare the magnitude. */
Packit 70b277
  if (n1->n_len != n2->n_len)
Packit 70b277
    {
Packit 70b277
      if (n1->n_len > n2->n_len)
Packit 70b277
	{
Packit 70b277
	  /* Magnitude of n1 > n2. */
Packit 70b277
	  if (!use_sign || n1->n_sign == PLUS)
Packit 70b277
	    return (1);
Packit 70b277
	  else
Packit 70b277
	    return (-1);
Packit 70b277
	}
Packit 70b277
      else
Packit 70b277
	{
Packit 70b277
	  /* Magnitude of n1 < n2. */
Packit 70b277
	  if (!use_sign || n1->n_sign == PLUS)
Packit 70b277
	    return (-1);
Packit 70b277
	  else
Packit 70b277
	    return (1);
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* If we get here, they have the same number of integer digits.
Packit 70b277
     check the integer part and the equal length part of the fraction. */
Packit 70b277
  count = n1->n_len + MIN (n1->n_scale, n2->n_scale);
Packit 70b277
  n1ptr = n1->n_value;
Packit 70b277
  n2ptr = n2->n_value;
Packit 70b277
Packit 70b277
  while ((count > 0) && (*n1ptr == *n2ptr))
Packit 70b277
    {
Packit 70b277
      n1ptr++;
Packit 70b277
      n2ptr++;
Packit 70b277
      count--;
Packit 70b277
    }
Packit 70b277
  if (ignore_last && count == 1 && n1->n_scale == n2->n_scale)
Packit 70b277
    return (0);
Packit 70b277
  if (count != 0)
Packit 70b277
    {
Packit 70b277
      if (*n1ptr > *n2ptr)
Packit 70b277
	{
Packit 70b277
	  /* Magnitude of n1 > n2. */
Packit 70b277
	  if (!use_sign || n1->n_sign == PLUS)
Packit 70b277
	    return (1);
Packit 70b277
	  else
Packit 70b277
	    return (-1);
Packit 70b277
	}
Packit 70b277
      else
Packit 70b277
	{
Packit 70b277
	  /* Magnitude of n1 < n2. */
Packit 70b277
	  if (!use_sign || n1->n_sign == PLUS)
Packit 70b277
	    return (-1);
Packit 70b277
	  else
Packit 70b277
	    return (1);
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* They are equal up to the last part of the equal part of the fraction. */
Packit 70b277
  if (n1->n_scale != n2->n_scale)
Packit 70b277
    {
Packit 70b277
      if (n1->n_scale > n2->n_scale)
Packit 70b277
	{
Packit 70b277
	  for (count = n1->n_scale-n2->n_scale; count>0; count--)
Packit 70b277
	    if (*n1ptr++ != 0)
Packit 70b277
	      {
Packit 70b277
		/* Magnitude of n1 > n2. */
Packit 70b277
		if (!use_sign || n1->n_sign == PLUS)
Packit 70b277
		  return (1);
Packit 70b277
		else
Packit 70b277
		  return (-1);
Packit 70b277
	      }
Packit 70b277
	}
Packit 70b277
      else
Packit 70b277
	{
Packit 70b277
	  for (count = n2->n_scale-n1->n_scale; count>0; count--)
Packit 70b277
	    if (*n2ptr++ != 0)
Packit 70b277
	      {
Packit 70b277
		/* Magnitude of n1 < n2. */
Packit 70b277
		if (!use_sign || n1->n_sign == PLUS)
Packit 70b277
		  return (-1);
Packit 70b277
		else
Packit 70b277
		  return (1);
Packit 70b277
	      }
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* They must be equal! */
Packit 70b277
  return (0);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* This is the "user callable" routine to compare numbers N1 and N2. */
Packit 70b277
Packit 70b277
int
Packit 70b277
bc_compare ( bc_num n1, bc_num n2 )
Packit 70b277
{
Packit 70b277
  return _bc_do_compare (n1, n2, TRUE, FALSE);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* In some places we need to check if the number is negative. */
Packit 70b277
Packit 70b277
char
Packit 70b277
bc_is_neg (bc_num num)
Packit 70b277
{
Packit 70b277
  return num->n_sign == MINUS;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* In some places we need to check if the number NUM is zero. */
Packit 70b277
Packit 70b277
char
Packit 70b277
bc_is_zero (bc_num num)
Packit 70b277
{
Packit 70b277
  int  count;
Packit 70b277
  char *nptr;
Packit 70b277
Packit 70b277
  /* Quick check. */
Packit 70b277
  if (num == _zero_) return TRUE;
Packit 70b277
Packit 70b277
  /* Initialize */
Packit 70b277
  count = num->n_len + num->n_scale;
Packit 70b277
  nptr = num->n_value;
Packit 70b277
Packit 70b277
  /* The check */
Packit 70b277
  while ((count > 0) && (*nptr++ == 0)) count--;
Packit 70b277
Packit 70b277
  if (count != 0)
Packit 70b277
    return FALSE;
Packit 70b277
  else
Packit 70b277
    return TRUE;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* In some places we need to check if the number NUM is almost zero.
Packit 70b277
   Specifically, all but the last digit is 0 and the last digit is 1.
Packit 70b277
   Last digit is defined by scale. */
Packit 70b277
Packit 70b277
char
Packit 70b277
bc_is_near_zero (bc_num num, int scale)
Packit 70b277
{
Packit 70b277
  int  count;
Packit 70b277
  char *nptr;
Packit 70b277
Packit 70b277
  /* Error checking */
Packit 70b277
  if (scale > num->n_scale)
Packit 70b277
    scale = num->n_scale;
Packit 70b277
Packit 70b277
  /* Initialize */
Packit 70b277
  count = num->n_len + scale;
Packit 70b277
  nptr = num->n_value;
Packit 70b277
Packit 70b277
  /* The check */
Packit 70b277
  while ((count > 0) && (*nptr++ == 0)) count--;
Packit 70b277
Packit 70b277
  if (count != 0 && (count != 1 || *--nptr != 1))
Packit 70b277
    return FALSE;
Packit 70b277
  else
Packit 70b277
    return TRUE;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Perform addition: N1 is added to N2 and the value is
Packit 70b277
   returned.  The signs of N1 and N2 are ignored.
Packit 70b277
   SCALE_MIN is to set the minimum scale of the result. */
Packit 70b277
Packit 70b277
static bc_num
Packit 70b277
_bc_do_add (bc_num n1, bc_num n2, int scale_min)
Packit 70b277
{
Packit 70b277
  bc_num sum;
Packit 70b277
  int sum_scale, sum_digits;
Packit 70b277
  char *n1ptr, *n2ptr, *sumptr;
Packit 70b277
  int carry, n1bytes, n2bytes;
Packit 70b277
  int count;
Packit 70b277
Packit 70b277
  /* Prepare sum. */
Packit 70b277
  sum_scale = MAX (n1->n_scale, n2->n_scale);
Packit 70b277
  sum_digits = MAX (n1->n_len, n2->n_len) + 1;
Packit 70b277
  sum = bc_new_num (sum_digits, MAX(sum_scale, scale_min));
Packit 70b277
Packit 70b277
  /* Zero extra digits made by scale_min. */
Packit 70b277
  if (scale_min > sum_scale)
Packit 70b277
    {
Packit 70b277
      sumptr = (char *) (sum->n_value + sum_scale + sum_digits);
Packit 70b277
      for (count = scale_min - sum_scale; count > 0; count--)
Packit 70b277
	*sumptr++ = 0;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Start with the fraction part.  Initialize the pointers. */
Packit 70b277
  n1bytes = n1->n_scale;
Packit 70b277
  n2bytes = n2->n_scale;
Packit 70b277
  n1ptr = (char *) (n1->n_value + n1->n_len + n1bytes - 1);
Packit 70b277
  n2ptr = (char *) (n2->n_value + n2->n_len + n2bytes - 1);
Packit 70b277
  sumptr = (char *) (sum->n_value + sum_scale + sum_digits - 1);
Packit 70b277
Packit 70b277
  /* Add the fraction part.  First copy the longer fraction.*/
Packit 70b277
  if (n1bytes != n2bytes)
Packit 70b277
    {
Packit 70b277
      if (n1bytes > n2bytes)
Packit 70b277
	while (n1bytes>n2bytes)
Packit 70b277
	  { *sumptr-- = *n1ptr--; n1bytes--;}
Packit 70b277
      else
Packit 70b277
	while (n2bytes>n1bytes)
Packit 70b277
	  { *sumptr-- = *n2ptr--; n2bytes--;}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Now add the remaining fraction part and equal size integer parts. */
Packit 70b277
  n1bytes += n1->n_len;
Packit 70b277
  n2bytes += n2->n_len;
Packit 70b277
  carry = 0;
Packit 70b277
  while ((n1bytes > 0) && (n2bytes > 0))
Packit 70b277
    {
Packit 70b277
      *sumptr = *n1ptr-- + *n2ptr-- + carry;
Packit 70b277
      if (*sumptr > (BASE-1))
Packit 70b277
	{
Packit 70b277
	   carry = 1;
Packit 70b277
	   *sumptr -= BASE;
Packit 70b277
	}
Packit 70b277
      else
Packit 70b277
	carry = 0;
Packit 70b277
      sumptr--;
Packit 70b277
      n1bytes--;
Packit 70b277
      n2bytes--;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Now add carry the longer integer part. */
Packit 70b277
  if (n1bytes == 0)
Packit 70b277
    { n1bytes = n2bytes; n1ptr = n2ptr; }
Packit 70b277
  while (n1bytes-- > 0)
Packit 70b277
    {
Packit 70b277
      *sumptr = *n1ptr-- + carry;
Packit 70b277
      if (*sumptr > (BASE-1))
Packit 70b277
	{
Packit 70b277
	   carry = 1;
Packit 70b277
	   *sumptr -= BASE;
Packit 70b277
	 }
Packit 70b277
      else
Packit 70b277
	carry = 0;
Packit 70b277
      sumptr--;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Set final carry. */
Packit 70b277
  if (carry == 1)
Packit 70b277
    *sumptr += 1;
Packit 70b277
Packit 70b277
  /* Adjust sum and return. */
Packit 70b277
  _bc_rm_leading_zeros (sum);
Packit 70b277
  return sum;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Perform subtraction: N2 is subtracted from N1 and the value is
Packit 70b277
   returned.  The signs of N1 and N2 are ignored.  Also, N1 is
Packit 70b277
   assumed to be larger than N2.  SCALE_MIN is the minimum scale
Packit 70b277
   of the result. */
Packit 70b277
Packit 70b277
static bc_num
Packit 70b277
_bc_do_sub (bc_num n1, bc_num n2, int scale_min)
Packit 70b277
{
Packit 70b277
  bc_num diff;
Packit 70b277
  int diff_scale, diff_len;
Packit 70b277
  int min_scale, min_len;
Packit 70b277
  char *n1ptr, *n2ptr, *diffptr;
Packit 70b277
  int borrow, count, val;
Packit 70b277
Packit 70b277
  /* Allocate temporary storage. */
Packit 70b277
  diff_len = MAX (n1->n_len, n2->n_len);
Packit 70b277
  diff_scale = MAX (n1->n_scale, n2->n_scale);
Packit 70b277
  min_len = MIN  (n1->n_len, n2->n_len);
Packit 70b277
  min_scale = MIN (n1->n_scale, n2->n_scale);
Packit 70b277
  diff = bc_new_num (diff_len, MAX(diff_scale, scale_min));
Packit 70b277
Packit 70b277
  /* Zero extra digits made by scale_min. */
Packit 70b277
  if (scale_min > diff_scale)
Packit 70b277
    {
Packit 70b277
      diffptr = (char *) (diff->n_value + diff_len + diff_scale);
Packit 70b277
      for (count = scale_min - diff_scale; count > 0; count--)
Packit 70b277
	*diffptr++ = 0;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Initialize the subtract. */
Packit 70b277
  n1ptr = (char *) (n1->n_value + n1->n_len + n1->n_scale -1);
Packit 70b277
  n2ptr = (char *) (n2->n_value + n2->n_len + n2->n_scale -1);
Packit 70b277
  diffptr = (char *) (diff->n_value + diff_len + diff_scale -1);
Packit 70b277
Packit 70b277
  /* Subtract the numbers. */
Packit 70b277
  borrow = 0;
Packit 70b277
Packit 70b277
  /* Take care of the longer scaled number. */
Packit 70b277
  if (n1->n_scale != min_scale)
Packit 70b277
    {
Packit 70b277
      /* n1 has the longer scale */
Packit 70b277
      for (count = n1->n_scale - min_scale; count > 0; count--)
Packit 70b277
	*diffptr-- = *n1ptr--;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      /* n2 has the longer scale */
Packit 70b277
      for (count = n2->n_scale - min_scale; count > 0; count--)
Packit 70b277
	{
Packit 70b277
	  val = - *n2ptr-- - borrow;
Packit 70b277
	  if (val < 0)
Packit 70b277
	    {
Packit 70b277
	      val += BASE;
Packit 70b277
	      borrow = 1;
Packit 70b277
	    }
Packit 70b277
	  else
Packit 70b277
	    borrow = 0;
Packit 70b277
	  *diffptr-- = val;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Now do the equal length scale and integer parts. */
Packit 70b277
Packit 70b277
  for (count = 0; count < min_len + min_scale; count++)
Packit 70b277
    {
Packit 70b277
      val = *n1ptr-- - *n2ptr-- - borrow;
Packit 70b277
      if (val < 0)
Packit 70b277
	{
Packit 70b277
	  val += BASE;
Packit 70b277
	  borrow = 1;
Packit 70b277
	}
Packit 70b277
      else
Packit 70b277
	borrow = 0;
Packit 70b277
      *diffptr-- = val;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* If n1 has more digits then n2, we now do that subtract. */
Packit 70b277
  if (diff_len != min_len)
Packit 70b277
    {
Packit 70b277
      for (count = diff_len - min_len; count > 0; count--)
Packit 70b277
	{
Packit 70b277
	  val = *n1ptr-- - borrow;
Packit 70b277
	  if (val < 0)
Packit 70b277
	    {
Packit 70b277
	      val += BASE;
Packit 70b277
	      borrow = 1;
Packit 70b277
	    }
Packit 70b277
	  else
Packit 70b277
	    borrow = 0;
Packit 70b277
	  *diffptr-- = val;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Clean up and return. */
Packit 70b277
  _bc_rm_leading_zeros (diff);
Packit 70b277
  return diff;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Here is the full subtract routine that takes care of negative numbers.
Packit 70b277
   N2 is subtracted from N1 and the result placed in RESULT.  SCALE_MIN
Packit 70b277
   is the minimum scale for the result. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_sub (bc_num n1, bc_num n2, bc_num *result, int scale_min)
Packit 70b277
{
Packit 70b277
  bc_num diff = NULL;
Packit 70b277
  int cmp_res;
Packit 70b277
  int res_scale;
Packit 70b277
Packit 70b277
  if (n1->n_sign != n2->n_sign)
Packit 70b277
    {
Packit 70b277
      diff = _bc_do_add (n1, n2, scale_min);
Packit 70b277
      diff->n_sign = n1->n_sign;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      /* subtraction must be done. */
Packit 70b277
      /* Compare magnitudes. */
Packit 70b277
      cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE);
Packit 70b277
      switch (cmp_res)
Packit 70b277
	{
Packit 70b277
	case -1:
Packit 70b277
	  /* n1 is less than n2, subtract n1 from n2. */
Packit 70b277
	  diff = _bc_do_sub (n2, n1, scale_min);
Packit 70b277
	  diff->n_sign = (n2->n_sign == PLUS ? MINUS : PLUS);
Packit 70b277
	  break;
Packit 70b277
	case  0:
Packit 70b277
	  /* They are equal! return zero! */
Packit 70b277
	  res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
Packit 70b277
	  diff = bc_new_num (1, res_scale);
Packit 70b277
	  memset (diff->n_value, 0, res_scale+1);
Packit 70b277
	  break;
Packit 70b277
	case  1:
Packit 70b277
	  /* n2 is less than n1, subtract n2 from n1. */
Packit 70b277
	  diff = _bc_do_sub (n1, n2, scale_min);
Packit 70b277
	  diff->n_sign = n1->n_sign;
Packit 70b277
	  break;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Clean up and return. */
Packit 70b277
  bc_free_num (result);
Packit 70b277
  *result = diff;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Here is the full add routine that takes care of negative numbers.
Packit 70b277
   N1 is added to N2 and the result placed into RESULT.  SCALE_MIN
Packit 70b277
   is the minimum scale for the result. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_add (bc_num n1, bc_num n2, bc_num *result, int scale_min)
Packit 70b277
{
Packit 70b277
  bc_num sum = NULL;
Packit 70b277
  int cmp_res;
Packit 70b277
  int res_scale;
Packit 70b277
Packit 70b277
  if (n1->n_sign == n2->n_sign)
Packit 70b277
    {
Packit 70b277
      sum = _bc_do_add (n1, n2, scale_min);
Packit 70b277
      sum->n_sign = n1->n_sign;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      /* subtraction must be done. */
Packit 70b277
      cmp_res = _bc_do_compare (n1, n2, FALSE, FALSE);  /* Compare magnitudes. */
Packit 70b277
      switch (cmp_res)
Packit 70b277
	{
Packit 70b277
	case -1:
Packit 70b277
	  /* n1 is less than n2, subtract n1 from n2. */
Packit 70b277
	  sum = _bc_do_sub (n2, n1, scale_min);
Packit 70b277
	  sum->n_sign = n2->n_sign;
Packit 70b277
	  break;
Packit 70b277
	case  0:
Packit 70b277
	  /* They are equal! return zero with the correct scale! */
Packit 70b277
	  res_scale = MAX (scale_min, MAX(n1->n_scale, n2->n_scale));
Packit 70b277
	  sum = bc_new_num (1, res_scale);
Packit 70b277
	  memset (sum->n_value, 0, res_scale+1);
Packit 70b277
	  break;
Packit 70b277
	case  1:
Packit 70b277
	  /* n2 is less than n1, subtract n2 from n1. */
Packit 70b277
	  sum = _bc_do_sub (n1, n2, scale_min);
Packit 70b277
	  sum->n_sign = n1->n_sign;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Clean up and return. */
Packit 70b277
  bc_free_num (result);
Packit 70b277
  *result = sum;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Recursive vs non-recursive multiply crossover ranges. */
Packit 70b277
#if defined(MULDIGITS)
Packit 70b277
#include "muldigits.h"
Packit 70b277
#else
Packit 70b277
#define MUL_BASE_DIGITS 80
Packit 70b277
#endif
Packit 70b277
Packit 70b277
int mul_base_digits = MUL_BASE_DIGITS;
Packit 70b277
#define MUL_SMALL_DIGITS mul_base_digits/4
Packit 70b277
Packit 70b277
/* Multiply utility routines */
Packit 70b277
Packit 70b277
static bc_num
Packit 70b277
new_sub_num (int length, int scale, char *value)
Packit 70b277
{
Packit 70b277
  bc_num temp;
Packit 70b277
Packit 70b277
  if (_bc_Free_list != NULL) {
Packit 70b277
    temp = _bc_Free_list;
Packit 70b277
    _bc_Free_list = temp->n_next;
Packit 70b277
  } else {
Packit 70b277
    temp = (bc_num) malloc (sizeof(bc_struct));
Packit 70b277
    if (temp == NULL) bc_out_of_memory ();
Packit 70b277
  }
Packit 70b277
  temp->n_sign = PLUS;
Packit 70b277
  temp->n_len = length;
Packit 70b277
  temp->n_scale = scale;
Packit 70b277
  temp->n_refs = 1;
Packit 70b277
  temp->n_ptr = NULL;
Packit 70b277
  temp->n_value = value;
Packit 70b277
  return temp;
Packit 70b277
}
Packit 70b277
Packit 70b277
static void
Packit 70b277
_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod)
Packit 70b277
{
Packit 70b277
  char *n1ptr, *n2ptr, *pvptr;
Packit 70b277
  char *n1end, *n2end;		/* To the end of n1 and n2. */
Packit 70b277
  int indx, sum, prodlen;
Packit 70b277
Packit 70b277
  prodlen = n1len+n2len+1;
Packit 70b277
Packit 70b277
  *prod = bc_new_num (prodlen, 0);
Packit 70b277
Packit 70b277
  n1end = (char *) (n1->n_value + n1len - 1);
Packit 70b277
  n2end = (char *) (n2->n_value + n2len - 1);
Packit 70b277
  pvptr = (char *) ((*prod)->n_value + prodlen - 1);
Packit 70b277
  sum = 0;
Packit 70b277
Packit 70b277
  /* Here is the loop... */
Packit 70b277
  for (indx = 0; indx < prodlen-1; indx++)
Packit 70b277
    {
Packit 70b277
      n1ptr = (char *) (n1end - MAX(0, indx-n2len+1));
Packit 70b277
      n2ptr = (char *) (n2end - MIN(indx, n2len-1));
Packit 70b277
      while ((n1ptr >= n1->n_value) && (n2ptr <= n2end))
Packit 70b277
	sum += *n1ptr-- * *n2ptr++;
Packit 70b277
      *pvptr-- = sum % BASE;
Packit 70b277
      sum = sum / BASE;
Packit 70b277
    }
Packit 70b277
  *pvptr = sum;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* A special adder/subtractor for the recursive divide and conquer
Packit 70b277
   multiply algorithm.  Note: if sub is called, accum must
Packit 70b277
   be larger that what is being subtracted.  Also, accum and val
Packit 70b277
   must have n_scale = 0.  (e.g. they must look like integers. *) */
Packit 70b277
static void
Packit 70b277
_bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
Packit 70b277
{
Packit 70b277
  signed char *accp, *valp;
Packit 70b277
  int  count, carry;
Packit 70b277
Packit 70b277
  count = val->n_len;
Packit 70b277
  if (val->n_value[0] == 0)
Packit 70b277
    count--;
Packit 70b277
  assert (accum->n_len+accum->n_scale >= shift+count);
Packit 70b277
  
Packit 70b277
  /* Set up pointers and others */
Packit 70b277
  accp = (signed char *)(accum->n_value +
Packit 70b277
			 accum->n_len + accum->n_scale - shift - 1);
Packit 70b277
  valp = (signed char *)(val->n_value + val->n_len - 1);
Packit 70b277
  carry = 0;
Packit 70b277
Packit 70b277
  if (sub) {
Packit 70b277
    /* Subtraction, carry is really borrow. */
Packit 70b277
    while (count--) {
Packit 70b277
      *accp -= *valp-- + carry;
Packit 70b277
      if (*accp < 0) {
Packit 70b277
	carry = 1;
Packit 70b277
        *accp-- += BASE;
Packit 70b277
      } else {
Packit 70b277
	carry = 0;
Packit 70b277
	accp--;
Packit 70b277
      }
Packit 70b277
    }
Packit 70b277
    while (carry) {
Packit 70b277
      *accp -= carry;
Packit 70b277
      if (*accp < 0)
Packit 70b277
	*accp-- += BASE;
Packit 70b277
      else
Packit 70b277
	carry = 0;
Packit 70b277
    }
Packit 70b277
  } else {
Packit 70b277
    /* Addition */
Packit 70b277
    while (count--) {
Packit 70b277
      *accp += *valp-- + carry;
Packit 70b277
      if (*accp > (BASE-1)) {
Packit 70b277
	carry = 1;
Packit 70b277
        *accp-- -= BASE;
Packit 70b277
      } else {
Packit 70b277
	carry = 0;
Packit 70b277
	accp--;
Packit 70b277
      }
Packit 70b277
    }
Packit 70b277
    while (carry) {
Packit 70b277
      *accp += carry;
Packit 70b277
      if (*accp > (BASE-1))
Packit 70b277
	*accp-- -= BASE;
Packit 70b277
      else
Packit 70b277
	carry = 0;
Packit 70b277
    }
Packit 70b277
  }
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Recursive divide and conquer multiply algorithm.  
Packit 70b277
   Based on 
Packit 70b277
   Let u = u0 + u1*(b^n)
Packit 70b277
   Let v = v0 + v1*(b^n)
Packit 70b277
   Then uv = (B^2n+B^n)*u1*v1 + B^n*(u1-u0)*(v0-v1) + (B^n+1)*u0*v0
Packit 70b277
Packit 70b277
   B is the base of storage, number of digits in u1,u0 close to equal.
Packit 70b277
*/
Packit 70b277
static void
Packit 70b277
_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod)
Packit 70b277
{ 
Packit 70b277
  bc_num u0, u1, v0, v1;
Packit 70b277
  bc_num m1, m2, m3, d1, d2;
Packit 70b277
  int n, prodlen, m1zero;
Packit 70b277
  int d1len, d2len;
Packit 70b277
Packit 70b277
  /* Base case? */
Packit 70b277
  if ((ulen+vlen) < mul_base_digits
Packit 70b277
      || ulen < MUL_SMALL_DIGITS
Packit 70b277
      || vlen < MUL_SMALL_DIGITS ) {
Packit 70b277
    _bc_simp_mul (u, ulen, v, vlen, prod);
Packit 70b277
    return;
Packit 70b277
  }
Packit 70b277
Packit 70b277
  /* Calculate n -- the u and v split point in digits. */
Packit 70b277
  n = (MAX(ulen, vlen)+1) / 2;
Packit 70b277
Packit 70b277
  /* Split u and v. */
Packit 70b277
  if (ulen < n) {
Packit 70b277
    u1 = bc_copy_num (_zero_);
Packit 70b277
    u0 = new_sub_num (ulen,0, u->n_value);
Packit 70b277
  } else {
Packit 70b277
    u1 = new_sub_num (ulen-n, 0, u->n_value);
Packit 70b277
    u0 = new_sub_num (n, 0, u->n_value+ulen-n);
Packit 70b277
  }
Packit 70b277
  if (vlen < n) {
Packit 70b277
    v1 = bc_copy_num (_zero_);
Packit 70b277
    v0 = new_sub_num (vlen,0, v->n_value);
Packit 70b277
  } else {
Packit 70b277
    v1 = new_sub_num (vlen-n, 0, v->n_value);
Packit 70b277
    v0 = new_sub_num (n, 0, v->n_value+vlen-n);
Packit 70b277
    }
Packit 70b277
  _bc_rm_leading_zeros (u1);
Packit 70b277
  _bc_rm_leading_zeros (u0);
Packit 70b277
  _bc_rm_leading_zeros (v1);
Packit 70b277
  _bc_rm_leading_zeros (v0);
Packit 70b277
Packit 70b277
  m1zero = bc_is_zero(u1) || bc_is_zero(v1);
Packit 70b277
Packit 70b277
  /* Calculate sub results ... */
Packit 70b277
Packit 70b277
  bc_init_num(&d1;;
Packit 70b277
  bc_init_num(&d2;;
Packit 70b277
  bc_sub (u1, u0, &d1, 0);
Packit 70b277
  d1len = d1->n_len;
Packit 70b277
  bc_sub (v0, v1, &d2, 0);
Packit 70b277
  d2len = d2->n_len;
Packit 70b277
Packit 70b277
Packit 70b277
  /* Do recursive multiplies and shifted adds. */
Packit 70b277
  if (m1zero)
Packit 70b277
    m1 = bc_copy_num (_zero_);
Packit 70b277
  else
Packit 70b277
    _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1;;
Packit 70b277
Packit 70b277
  if (bc_is_zero(d1) || bc_is_zero(d2))
Packit 70b277
    m2 = bc_copy_num (_zero_);
Packit 70b277
  else
Packit 70b277
    _bc_rec_mul (d1, d1len, d2, d2len, &m2;;
Packit 70b277
Packit 70b277
  if (bc_is_zero(u0) || bc_is_zero(v0))
Packit 70b277
    m3 = bc_copy_num (_zero_);
Packit 70b277
  else
Packit 70b277
    _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3;;
Packit 70b277
Packit 70b277
  /* Initialize product */
Packit 70b277
  prodlen = ulen+vlen+1;
Packit 70b277
  *prod = bc_new_num(prodlen, 0);
Packit 70b277
Packit 70b277
  if (!m1zero) {
Packit 70b277
    _bc_shift_addsub (*prod, m1, 2*n, 0);
Packit 70b277
    _bc_shift_addsub (*prod, m1, n, 0);
Packit 70b277
  }
Packit 70b277
  _bc_shift_addsub (*prod, m3, n, 0);
Packit 70b277
  _bc_shift_addsub (*prod, m3, 0, 0);
Packit 70b277
  _bc_shift_addsub (*prod, m2, n, d1->n_sign != d2->n_sign);
Packit 70b277
Packit 70b277
  /* Now clean up! */
Packit 70b277
  bc_free_num (&u1;;
Packit 70b277
  bc_free_num (&u0;;
Packit 70b277
  bc_free_num (&v1;;
Packit 70b277
  bc_free_num (&m1;;
Packit 70b277
  bc_free_num (&v0;;
Packit 70b277
  bc_free_num (&m2;;
Packit 70b277
  bc_free_num (&m3;;
Packit 70b277
  bc_free_num (&d1;;
Packit 70b277
  bc_free_num (&d2;;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* The multiply routine.  N2 times N1 is put int PROD with the scale of
Packit 70b277
   the result being MIN(N2 scale+N1 scale, MAX (SCALE, N2 scale, N1 scale)).
Packit 70b277
   */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_multiply (bc_num n1, bc_num n2, bc_num *prod, int scale)
Packit 70b277
{
Packit 70b277
  bc_num pval; 
Packit 70b277
  int len1, len2;
Packit 70b277
  int full_scale, prod_scale;
Packit 70b277
Packit 70b277
  /* Initialize things. */
Packit 70b277
  len1 = n1->n_len + n1->n_scale;
Packit 70b277
  len2 = n2->n_len + n2->n_scale;
Packit 70b277
  full_scale = n1->n_scale + n2->n_scale;
Packit 70b277
  prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
Packit 70b277
Packit 70b277
  /* Do the multiply */
Packit 70b277
  _bc_rec_mul (n1, len1, n2, len2, &pval);
Packit 70b277
Packit 70b277
  /* Assign to prod and clean up the number. */
Packit 70b277
  pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
Packit 70b277
  pval->n_value = pval->n_ptr;
Packit 70b277
  pval->n_len = len2 + len1 + 1 - full_scale;
Packit 70b277
  pval->n_scale = prod_scale;
Packit 70b277
  _bc_rm_leading_zeros (pval);
Packit 70b277
  if (bc_is_zero (pval))
Packit 70b277
    pval->n_sign = PLUS;
Packit 70b277
  bc_free_num (prod);
Packit 70b277
  *prod = pval;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Some utility routines for the divide:  First a one digit multiply.
Packit 70b277
   NUM (with SIZE digits) is multiplied by DIGIT and the result is
Packit 70b277
   placed into RESULT.  It is written so that NUM and RESULT can be
Packit 70b277
   the same pointers.  */
Packit 70b277
Packit 70b277
static void
Packit 70b277
_one_mult (unsigned char *num, int size, int digit, unsigned char *result)
Packit 70b277
{
Packit 70b277
  int carry, value;
Packit 70b277
  unsigned char *nptr, *rptr;
Packit 70b277
Packit 70b277
  if (digit == 0)
Packit 70b277
    memset (result, 0, size);
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      if (digit == 1)
Packit 70b277
	memcpy (result, num, size);
Packit 70b277
      else
Packit 70b277
	{
Packit 70b277
	  /* Initialize */
Packit 70b277
	  nptr = (unsigned char *) (num+size-1);
Packit 70b277
	  rptr = (unsigned char *) (result+size-1);
Packit 70b277
	  carry = 0;
Packit 70b277
Packit 70b277
	  while (size-- > 0)
Packit 70b277
	    {
Packit 70b277
	      value = *nptr-- * digit + carry;
Packit 70b277
	      *rptr-- = value % BASE;
Packit 70b277
	      carry = value / BASE;
Packit 70b277
	    }
Packit 70b277
Packit 70b277
	  if (carry != 0) *rptr = carry;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* The full division routine. This computes N1 / N2.  It returns
Packit 70b277
   0 if the division is ok and the result is in QUOT.  The number of
Packit 70b277
   digits after the decimal point is SCALE. It returns -1 if division
Packit 70b277
   by zero is tried.  The algorithm is found in Knuth Vol 2. p237. */
Packit 70b277
Packit 70b277
int
Packit 70b277
bc_divide (bc_num n1, bc_num n2, bc_num *quot,  int scale)
Packit 70b277
{
Packit 70b277
  bc_num qval;
Packit 70b277
  unsigned char *num1, *num2;
Packit 70b277
  unsigned char *ptr1, *ptr2, *n2ptr, *qptr;
Packit 70b277
  int  scale1, val;
Packit 70b277
  unsigned int  len1, len2, scale2, qdigits, extra, count;
Packit 70b277
  unsigned int  qdig, qguess, borrow, carry;
Packit 70b277
  unsigned char *mval;
Packit 70b277
  char zero;
Packit 70b277
  unsigned int  norm;
Packit 70b277
Packit 70b277
  /* Test for divide by zero. */
Packit 70b277
  if (bc_is_zero (n2)) return -1;
Packit 70b277
Packit 70b277
  /* Test for divide by 1.  If it is we must truncate. */
Packit 70b277
  if (n2->n_scale == 0)
Packit 70b277
    {
Packit 70b277
      if (n2->n_len == 1 && *n2->n_value == 1)
Packit 70b277
	{
Packit 70b277
	  qval = bc_new_num (n1->n_len, scale);
Packit 70b277
	  qval->n_sign = (n1->n_sign == n2->n_sign ? PLUS : MINUS);
Packit 70b277
	  memset (&qval->n_value[n1->n_len],0,scale);
Packit 70b277
	  memcpy (qval->n_value, n1->n_value,
Packit 70b277
		  n1->n_len + MIN(n1->n_scale,scale));
Packit 70b277
	  bc_free_num (quot);
Packit 70b277
	  *quot = qval;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Set up the divide.  Move the decimal point on n1 by n2's scale.
Packit 70b277
     Remember, zeros on the end of num2 are wasted effort for dividing. */
Packit 70b277
  scale2 = n2->n_scale;
Packit 70b277
  n2ptr = (unsigned char *) n2->n_value+n2->n_len+scale2-1;
Packit 70b277
  while ((scale2 > 0) && (*n2ptr-- == 0)) scale2--;
Packit 70b277
Packit 70b277
  len1 = n1->n_len + scale2;
Packit 70b277
  scale1 = n1->n_scale - scale2;
Packit 70b277
  if (scale1 < scale)
Packit 70b277
    extra = scale - scale1;
Packit 70b277
  else
Packit 70b277
    extra = 0;
Packit 70b277
  num1 = (unsigned char *) malloc (n1->n_len+n1->n_scale+extra+2);
Packit 70b277
  if (num1 == NULL) bc_out_of_memory();
Packit 70b277
  memset (num1, 0, n1->n_len+n1->n_scale+extra+2);
Packit 70b277
  memcpy (num1+1, n1->n_value, n1->n_len+n1->n_scale);
Packit 70b277
Packit 70b277
  len2 = n2->n_len + scale2;
Packit 70b277
  num2 = (unsigned char *) malloc (len2+1);
Packit 70b277
  if (num2 == NULL) bc_out_of_memory();
Packit 70b277
  memcpy (num2, n2->n_value, len2);
Packit 70b277
  *(num2+len2) = 0;
Packit 70b277
  n2ptr = num2;
Packit 70b277
  while (*n2ptr == 0)
Packit 70b277
    {
Packit 70b277
      n2ptr++;
Packit 70b277
      len2--;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Calculate the number of quotient digits. */
Packit 70b277
  if (len2 > len1+scale)
Packit 70b277
    {
Packit 70b277
      qdigits = scale+1;
Packit 70b277
      zero = TRUE;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      zero = FALSE;
Packit 70b277
      if (len2>len1)
Packit 70b277
	qdigits = scale+1;  	/* One for the zero integer part. */
Packit 70b277
      else
Packit 70b277
	qdigits = len1-len2+scale+1;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Allocate and zero the storage for the quotient. */
Packit 70b277
  qval = bc_new_num (qdigits-scale,scale);
Packit 70b277
  memset (qval->n_value, 0, qdigits);
Packit 70b277
Packit 70b277
  /* Allocate storage for the temporary storage mval. */
Packit 70b277
  mval = (unsigned char *) malloc (len2+1);
Packit 70b277
  if (mval == NULL) bc_out_of_memory ();
Packit 70b277
Packit 70b277
  /* Now for the full divide algorithm. */
Packit 70b277
  if (!zero)
Packit 70b277
    {
Packit 70b277
      /* Normalize */
Packit 70b277
      norm =  10 / ((int)*n2ptr + 1);
Packit 70b277
      if (norm != 1)
Packit 70b277
	{
Packit 70b277
	  _one_mult (num1, len1+scale1+extra+1, norm, num1);
Packit 70b277
	  _one_mult (n2ptr, len2, norm, n2ptr);
Packit 70b277
	}
Packit 70b277
Packit 70b277
      /* Initialize divide loop. */
Packit 70b277
      qdig = 0;
Packit 70b277
      if (len2 > len1)
Packit 70b277
	qptr = (unsigned char *) qval->n_value+len2-len1;
Packit 70b277
      else
Packit 70b277
	qptr = (unsigned char *) qval->n_value;
Packit 70b277
Packit 70b277
      /* Loop */
Packit 70b277
      while (qdig <= len1+scale-len2)
Packit 70b277
	{
Packit 70b277
	  /* Calculate the quotient digit guess. */
Packit 70b277
	  if (*n2ptr == num1[qdig])
Packit 70b277
	    qguess = 9;
Packit 70b277
	  else
Packit 70b277
	    qguess = (num1[qdig]*10 + num1[qdig+1]) / *n2ptr;
Packit 70b277
Packit 70b277
	  /* Test qguess. */
Packit 70b277
	  if (n2ptr[1]*qguess >
Packit 70b277
	      (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
Packit 70b277
	       + num1[qdig+2])
Packit 70b277
	    {
Packit 70b277
	      qguess--;
Packit 70b277
	      /* And again. */
Packit 70b277
	      if (n2ptr[1]*qguess >
Packit 70b277
		  (num1[qdig]*10 + num1[qdig+1] - *n2ptr*qguess)*10
Packit 70b277
		  + num1[qdig+2])
Packit 70b277
		qguess--;
Packit 70b277
	    }
Packit 70b277
Packit 70b277
	  /* Multiply and subtract. */
Packit 70b277
	  borrow = 0;
Packit 70b277
	  if (qguess != 0)
Packit 70b277
	    {
Packit 70b277
	      *mval = 0;
Packit 70b277
	      _one_mult (n2ptr, len2, qguess, mval+1);
Packit 70b277
	      ptr1 = (unsigned char *) num1+qdig+len2;
Packit 70b277
	      ptr2 = (unsigned char *) mval+len2;
Packit 70b277
	      for (count = 0; count < len2+1; count++)
Packit 70b277
		{
Packit 70b277
		  val = (int) *ptr1 - (int) *ptr2-- - borrow;
Packit 70b277
		  if (val < 0)
Packit 70b277
		    {
Packit 70b277
		      val += 10;
Packit 70b277
		      borrow = 1;
Packit 70b277
		    }
Packit 70b277
		  else
Packit 70b277
		    borrow = 0;
Packit 70b277
		  *ptr1-- = val;
Packit 70b277
		}
Packit 70b277
	    }
Packit 70b277
Packit 70b277
	  /* Test for negative result. */
Packit 70b277
	  if (borrow == 1)
Packit 70b277
	    {
Packit 70b277
	      qguess--;
Packit 70b277
	      ptr1 = (unsigned char *) num1+qdig+len2;
Packit 70b277
	      ptr2 = (unsigned char *) n2ptr+len2-1;
Packit 70b277
	      carry = 0;
Packit 70b277
	      for (count = 0; count < len2; count++)
Packit 70b277
		{
Packit 70b277
		  val = (int) *ptr1 + (int) *ptr2-- + carry;
Packit 70b277
		  if (val > 9)
Packit 70b277
		    {
Packit 70b277
		      val -= 10;
Packit 70b277
		      carry = 1;
Packit 70b277
		    }
Packit 70b277
		  else
Packit 70b277
		    carry = 0;
Packit 70b277
		  *ptr1-- = val;
Packit 70b277
		}
Packit 70b277
	      if (carry == 1) *ptr1 = (*ptr1 + 1) % 10;
Packit 70b277
	    }
Packit 70b277
Packit 70b277
	  /* We now know the quotient digit. */
Packit 70b277
	  *qptr++ =  qguess;
Packit 70b277
	  qdig++;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Clean up and return the number. */
Packit 70b277
  qval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
Packit 70b277
  if (bc_is_zero (qval)) qval->n_sign = PLUS;
Packit 70b277
  _bc_rm_leading_zeros (qval);
Packit 70b277
  bc_free_num (quot);
Packit 70b277
  *quot = qval;
Packit 70b277
Packit 70b277
  /* Clean up temporary storage. */
Packit 70b277
  free (mval);
Packit 70b277
  free (num1);
Packit 70b277
  free (num2);
Packit 70b277
Packit 70b277
  return 0;	/* Everything is OK. */
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Division *and* modulo for numbers.  This computes both NUM1 / NUM2 and
Packit 70b277
   NUM1 % NUM2  and puts the results in QUOT and REM, except that if QUOT
Packit 70b277
   is NULL then that store will be omitted.
Packit 70b277
 */
Packit 70b277
Packit 70b277
int
Packit 70b277
bc_divmod (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale)
Packit 70b277
{
Packit 70b277
  bc_num quotient = NULL;
Packit 70b277
  bc_num temp;
Packit 70b277
  int rscale;
Packit 70b277
Packit 70b277
  /* Check for correct numbers. */
Packit 70b277
  if (bc_is_zero (num2)) return -1;
Packit 70b277
Packit 70b277
  /* Calculate final scale. */
Packit 70b277
  rscale = MAX (num1->n_scale, num2->n_scale+scale);
Packit 70b277
  bc_init_num(&temp);
Packit 70b277
Packit 70b277
  /* Calculate it. */
Packit 70b277
  bc_divide (num1, num2, &temp, scale);
Packit 70b277
  if (quot)
Packit 70b277
    quotient = bc_copy_num (temp);
Packit 70b277
  bc_multiply (temp, num2, &temp, rscale);
Packit 70b277
  bc_sub (num1, temp, rem, rscale);
Packit 70b277
  bc_free_num (&temp);
Packit 70b277
Packit 70b277
  if (quot)
Packit 70b277
    {
Packit 70b277
      bc_free_num (quot);
Packit 70b277
      *quot = quotient;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  return 0;	/* Everything is OK. */
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Modulo for numbers.  This computes NUM1 % NUM2  and puts the
Packit 70b277
   result in RESULT.   */
Packit 70b277
Packit 70b277
int
Packit 70b277
bc_modulo ( bc_num num1, bc_num num2, bc_num *result, int scale)
Packit 70b277
{
Packit 70b277
  return bc_divmod (num1, num2, NULL, result, scale);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Raise BASE to the EXPO power, reduced modulo MOD.  The result is
Packit 70b277
   placed in RESULT.  If a EXPO is not an integer,
Packit 70b277
   only the integer part is used.  */
Packit 70b277
Packit 70b277
int
Packit 70b277
bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
Packit 70b277
{
Packit 70b277
  bc_num power, exponent, parity, temp;
Packit 70b277
  int rscale;
Packit 70b277
Packit 70b277
  /* Check for correct numbers. */
Packit 70b277
  if (bc_is_zero(mod)) return -1;
Packit 70b277
  if (bc_is_neg(expo)) return -1;
Packit 70b277
Packit 70b277
  /* Set initial values.  */
Packit 70b277
  power = bc_copy_num (base);
Packit 70b277
  exponent = bc_copy_num (expo);
Packit 70b277
  temp = bc_copy_num (_one_);
Packit 70b277
  bc_init_num(&parity);
Packit 70b277
Packit 70b277
  /* Check the base for scale digits. */
Packit 70b277
  if (base->n_scale != 0)
Packit 70b277
      bc_rt_warn ("non-zero scale in base");
Packit 70b277
Packit 70b277
  /* Check the exponent for scale digits. */
Packit 70b277
  if (exponent->n_scale != 0)
Packit 70b277
    {
Packit 70b277
      bc_rt_warn ("non-zero scale in exponent");
Packit 70b277
      bc_divide (exponent, _one_, &exponent, 0); /*truncate */
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Check the modulus for scale digits. */
Packit 70b277
  if (mod->n_scale != 0)
Packit 70b277
      bc_rt_warn ("non-zero scale in modulus");
Packit 70b277
Packit 70b277
  /* Do the calculation. */
Packit 70b277
  rscale = MAX(scale, base->n_scale);
Packit 70b277
  while ( !bc_is_zero(exponent) )
Packit 70b277
    {
Packit 70b277
      (void) bc_divmod (exponent, _two_, &exponent, &parity, 0);
Packit 70b277
      if ( !bc_is_zero(parity) )
Packit 70b277
	{
Packit 70b277
	  bc_multiply (temp, power, &temp, rscale);
Packit 70b277
	  (void) bc_modulo (temp, mod, &temp, scale);
Packit 70b277
	}
Packit 70b277
Packit 70b277
      bc_multiply (power, power, &power, rscale);
Packit 70b277
      (void) bc_modulo (power, mod, &power, scale);
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Assign the value. */
Packit 70b277
  bc_free_num (&power);
Packit 70b277
  bc_free_num (&exponent);
Packit 70b277
  bc_free_num (result);
Packit 70b277
  *result = temp;
Packit 70b277
  return 0;	/* Everything is OK. */
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Raise NUM1 to the NUM2 power.  The result is placed in RESULT.
Packit 70b277
   Maximum exponent is LONG_MAX.  If a NUM2 is not an integer,
Packit 70b277
   only the integer part is used.  */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_raise (bc_num num1, bc_num num2, bc_num *result, int scale)
Packit 70b277
{
Packit 70b277
   bc_num temp, power;
Packit 70b277
   long exponent;
Packit 70b277
   unsigned long uexponent;
Packit 70b277
   int rscale;
Packit 70b277
   int pwrscale;
Packit 70b277
   int calcscale;
Packit 70b277
   char neg;
Packit 70b277
Packit 70b277
   /* Check the exponent for scale digits and convert to a long. */
Packit 70b277
   if (num2->n_scale != 0)
Packit 70b277
     bc_rt_warn ("non-zero scale in exponent");
Packit 70b277
   exponent = bc_num2long (num2);
Packit 70b277
   if (exponent == 0 && (num2->n_len > 1 || num2->n_value[0] != 0))
Packit 70b277
       bc_rt_error ("exponent too large in raise");
Packit 70b277
Packit 70b277
   /* Special case if exponent is a zero. */
Packit 70b277
   if (exponent == 0)
Packit 70b277
     {
Packit 70b277
       bc_free_num (result);
Packit 70b277
       *result = bc_copy_num (_one_);
Packit 70b277
       return;
Packit 70b277
     }
Packit 70b277
Packit 70b277
   /* Other initializations. */
Packit 70b277
   if (exponent < 0)
Packit 70b277
     {
Packit 70b277
       neg = TRUE;
Packit 70b277
       uexponent = -exponent;
Packit 70b277
       rscale = scale;
Packit 70b277
     }
Packit 70b277
   else
Packit 70b277
     {
Packit 70b277
       neg = FALSE;
Packit 70b277
       uexponent = exponent;
Packit 70b277
       rscale = MIN (num1->n_scale*uexponent, 
Packit 70b277
                       (unsigned long) MAX(scale, num1->n_scale));
Packit 70b277
     }
Packit 70b277
Packit 70b277
   /* Set initial value of temp.  */
Packit 70b277
   power = bc_copy_num (num1);
Packit 70b277
   pwrscale = num1->n_scale;
Packit 70b277
   while ((uexponent & 1) == 0)
Packit 70b277
     {
Packit 70b277
       pwrscale <<= 1;
Packit 70b277
       bc_multiply (power, power, &power, pwrscale);
Packit 70b277
       uexponent = uexponent >> 1;
Packit 70b277
     }
Packit 70b277
   temp = bc_copy_num (power);
Packit 70b277
   calcscale = pwrscale;
Packit 70b277
   uexponent >>= 1;
Packit 70b277
Packit 70b277
   /* Do the calculation. */
Packit 70b277
   while (uexponent > 0)
Packit 70b277
     {
Packit 70b277
       pwrscale <<= 1;
Packit 70b277
       bc_multiply (power, power, &power, pwrscale);
Packit 70b277
       if ((uexponent & 1) == 1) {
Packit 70b277
	 calcscale = pwrscale + calcscale;
Packit 70b277
	 bc_multiply (temp, power, &temp, calcscale);
Packit 70b277
       }
Packit 70b277
       uexponent >>= 1;
Packit 70b277
     }
Packit 70b277
Packit 70b277
   /* Assign the value. */
Packit 70b277
   if (neg)
Packit 70b277
     {
Packit 70b277
       bc_divide (_one_, temp, result, rscale);
Packit 70b277
       bc_free_num (&temp);
Packit 70b277
     }
Packit 70b277
   else
Packit 70b277
     {
Packit 70b277
       bc_free_num (result);
Packit 70b277
       *result = temp;
Packit 70b277
       if ((*result)->n_scale > rscale)
Packit 70b277
	 (*result)->n_scale = rscale;
Packit 70b277
     }
Packit 70b277
   bc_free_num (&power);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Take the square root NUM and return it in NUM with SCALE digits
Packit 70b277
   after the decimal place. */
Packit 70b277
Packit 70b277
int
Packit 70b277
bc_sqrt (bc_num *num, int scale)
Packit 70b277
{
Packit 70b277
  int rscale, cmp_res, done;
Packit 70b277
  int cscale;
Packit 70b277
  bc_num guess, guess1, point5, diff;
Packit 70b277
Packit 70b277
  /* Initial checks. */
Packit 70b277
  cmp_res = bc_compare (*num, _zero_);
Packit 70b277
  if (cmp_res < 0)
Packit 70b277
    return 0;		/* error */
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      if (cmp_res == 0)
Packit 70b277
	{
Packit 70b277
	  bc_free_num (num);
Packit 70b277
	  *num = bc_copy_num (_zero_);
Packit 70b277
	  return 1;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
  cmp_res = bc_compare (*num, _one_);
Packit 70b277
  if (cmp_res == 0)
Packit 70b277
    {
Packit 70b277
      bc_free_num (num);
Packit 70b277
      *num = bc_copy_num (_one_);
Packit 70b277
      return 1;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Initialize the variables. */
Packit 70b277
  rscale = MAX (scale, (*num)->n_scale);
Packit 70b277
  bc_init_num(&guess);
Packit 70b277
  bc_init_num(&guess1);
Packit 70b277
  bc_init_num(&diff);
Packit 70b277
  point5 = bc_new_num (1,1);
Packit 70b277
  point5->n_value[1] = 5;
Packit 70b277
Packit 70b277
Packit 70b277
  /* Calculate the initial guess. */
Packit 70b277
  if (cmp_res < 0)
Packit 70b277
    {
Packit 70b277
      /* The number is between 0 and 1.  Guess should start at 1. */
Packit 70b277
      guess = bc_copy_num (_one_);
Packit 70b277
      cscale = (*num)->n_scale;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      /* The number is greater than 1.  Guess should start at 10^(exp/2). */
Packit 70b277
      bc_int2num (&guess,10);
Packit 70b277
Packit 70b277
      bc_int2num (&guess1,(*num)->n_len);
Packit 70b277
      bc_multiply (guess1, point5, &guess1, 0);
Packit 70b277
      guess1->n_scale = 0;
Packit 70b277
      bc_raise (guess, guess1, &guess, 0);
Packit 70b277
      bc_free_num (&guess1);
Packit 70b277
      cscale = 3;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Find the square root using Newton's algorithm. */
Packit 70b277
  done = FALSE;
Packit 70b277
  while (!done)
Packit 70b277
    {
Packit 70b277
      bc_free_num (&guess1);
Packit 70b277
      guess1 = bc_copy_num (guess);
Packit 70b277
      bc_divide (*num, guess, &guess, cscale);
Packit 70b277
      bc_add (guess, guess1, &guess, 0);
Packit 70b277
      bc_multiply (guess, point5, &guess, cscale);
Packit 70b277
      bc_sub (guess, guess1, &diff, cscale+1);
Packit 70b277
      if (bc_is_near_zero (diff, cscale))
Packit 70b277
	{
Packit 70b277
	  if (cscale < rscale+1)
Packit 70b277
	    cscale = MIN (cscale*3, rscale+1);
Packit 70b277
	  else
Packit 70b277
	    done = TRUE;
Packit 70b277
	}
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Assign the number and clean up. */
Packit 70b277
  bc_free_num (num);
Packit 70b277
  bc_divide (guess,_one_,num,rscale);
Packit 70b277
  bc_free_num (&guess);
Packit 70b277
  bc_free_num (&guess1);
Packit 70b277
  bc_free_num (&point5;;
Packit 70b277
  bc_free_num (&diff);
Packit 70b277
  return 1;
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* The following routines provide output for bcd numbers package
Packit 70b277
   using the rules of POSIX bc for output. */
Packit 70b277
Packit 70b277
/* This structure is used for saving digits in the conversion process. */
Packit 70b277
typedef struct stk_rec {
Packit 70b277
	long  digit;
Packit 70b277
	struct stk_rec *next;
Packit 70b277
} stk_rec;
Packit 70b277
Packit 70b277
/* The reference string for digits. */
Packit 70b277
static char ref_str[] = "0123456789ABCDEF";
Packit 70b277
Packit 70b277
Packit 70b277
/* A special output routine for "multi-character digits."  Exactly
Packit 70b277
   SIZE characters must be output for the value VAL.  If SPACE is
Packit 70b277
   non-zero, we must output one space before the number.  OUT_CHAR
Packit 70b277
   is the actual routine for writing the characters. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_out_long (long val, int size, int space, void (*out_char)(int))
Packit 70b277
{
Packit 70b277
  char digits[40];
Packit 70b277
  int len, ix;
Packit 70b277
Packit 70b277
  if (space) (*out_char) (' ');
Packit 70b277
  snprintf (digits, sizeof(digits), "%ld", val);
Packit 70b277
  len = strlen (digits);
Packit 70b277
  while (size > len)
Packit 70b277
    {
Packit 70b277
      (*out_char) ('0');
Packit 70b277
      size--;
Packit 70b277
    }
Packit 70b277
  for (ix=0; ix < len; ix++)
Packit 70b277
    (*out_char) (digits[ix]);
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Output of a bcd number.  NUM is written in base O_BASE using OUT_CHAR
Packit 70b277
   as the routine to do the actual output of the characters. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_out_num (bc_num num, int o_base, void (*out_char)(int), int leading_zero)
Packit 70b277
{
Packit 70b277
  char *nptr;
Packit 70b277
  int  ix, fdigit, pre_space;
Packit 70b277
  stk_rec *digits, *temp;
Packit 70b277
  bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
Packit 70b277
Packit 70b277
  /* The negative sign if needed. */
Packit 70b277
  if (num->n_sign == MINUS) (*out_char) ('-');
Packit 70b277
Packit 70b277
  /* Output the number. */
Packit 70b277
  if (bc_is_zero (num))
Packit 70b277
    (*out_char) ('0');
Packit 70b277
  else
Packit 70b277
    if (o_base == 10)
Packit 70b277
      {
Packit 70b277
	/* The number is in base 10, do it the fast way. */
Packit 70b277
	nptr = num->n_value;
Packit 70b277
	if (num->n_len > 1 || *nptr != 0)
Packit 70b277
	  for (ix=num->n_len; ix>0; ix--)
Packit 70b277
	    (*out_char) (BCD_CHAR(*nptr++));
Packit 70b277
	else
Packit 70b277
	  nptr++;
Packit 70b277
Packit 70b277
	if (leading_zero && bc_is_zero (num))
Packit 70b277
	  (*out_char) ('0');
Packit 70b277
Packit 70b277
	/* Now the fraction. */
Packit 70b277
	if (num->n_scale > 0)
Packit 70b277
	  {
Packit 70b277
	    (*out_char) ('.');
Packit 70b277
	    for (ix=0; ix<num->n_scale; ix++)
Packit 70b277
	      (*out_char) (BCD_CHAR(*nptr++));
Packit 70b277
	  }
Packit 70b277
      }
Packit 70b277
    else
Packit 70b277
      {
Packit 70b277
	/* special case ... */
Packit 70b277
	if (leading_zero && bc_is_zero (num))
Packit 70b277
	  (*out_char) ('0');
Packit 70b277
Packit 70b277
	/* The number is some other base. */
Packit 70b277
	digits = NULL;
Packit 70b277
	bc_init_num (&int_part);
Packit 70b277
	bc_divide (num, _one_, &int_part, 0);
Packit 70b277
	bc_init_num (&frac_part);
Packit 70b277
	bc_init_num (&cur_dig);
Packit 70b277
	bc_init_num (&base);
Packit 70b277
	bc_sub (num, int_part, &frac_part, 0);
Packit 70b277
	/* Make the INT_PART and FRAC_PART positive. */
Packit 70b277
	int_part->n_sign = PLUS;
Packit 70b277
	frac_part->n_sign = PLUS;
Packit 70b277
	bc_int2num (&base, o_base);
Packit 70b277
	bc_init_num (&max_o_digit);
Packit 70b277
	bc_int2num (&max_o_digit, o_base-1);
Packit 70b277
Packit 70b277
Packit 70b277
	/* Get the digits of the integer part and push them on a stack. */
Packit 70b277
	while (!bc_is_zero (int_part))
Packit 70b277
	  {
Packit 70b277
	    bc_modulo (int_part, base, &cur_dig, 0);
Packit 70b277
	    temp = (stk_rec *) malloc (sizeof(stk_rec));
Packit 70b277
	    if (temp == NULL) bc_out_of_memory();
Packit 70b277
	    temp->digit = bc_num2long (cur_dig);
Packit 70b277
	    temp->next = digits;
Packit 70b277
	    digits = temp;
Packit 70b277
	    bc_divide (int_part, base, &int_part, 0);
Packit 70b277
	  }
Packit 70b277
Packit 70b277
	/* Print the digits on the stack. */
Packit 70b277
	if (digits != NULL)
Packit 70b277
	  {
Packit 70b277
	    /* Output the digits. */
Packit 70b277
	    while (digits != NULL)
Packit 70b277
	      {
Packit 70b277
		temp = digits;
Packit 70b277
		digits = digits->next;
Packit 70b277
		if (o_base <= 16)
Packit 70b277
		  (*out_char) (ref_str[ (int) temp->digit]);
Packit 70b277
		else
Packit 70b277
		  bc_out_long (temp->digit, max_o_digit->n_len, 1, out_char);
Packit 70b277
		free (temp);
Packit 70b277
	      }
Packit 70b277
	  }
Packit 70b277
Packit 70b277
	/* Get and print the digits of the fraction part. */
Packit 70b277
	if (num->n_scale > 0)
Packit 70b277
	  {
Packit 70b277
	    (*out_char) ('.');
Packit 70b277
	    pre_space = 0;
Packit 70b277
	    t_num = bc_copy_num (_one_);
Packit 70b277
	    while (t_num->n_len <= num->n_scale) {
Packit 70b277
	      bc_multiply (frac_part, base, &frac_part, num->n_scale);
Packit 70b277
	      fdigit = bc_num2long (frac_part);
Packit 70b277
	      bc_int2num (&int_part, fdigit);
Packit 70b277
	      bc_sub (frac_part, int_part, &frac_part, 0);
Packit 70b277
	      if (o_base <= 16)
Packit 70b277
		(*out_char) (ref_str[fdigit]);
Packit 70b277
	      else {
Packit 70b277
		bc_out_long (fdigit, max_o_digit->n_len, pre_space, out_char);
Packit 70b277
		pre_space = 1;
Packit 70b277
	      }
Packit 70b277
	      bc_multiply (t_num, base, &t_num, 0);
Packit 70b277
	    }
Packit 70b277
	    bc_free_num (&t_num);
Packit 70b277
	  }
Packit 70b277
Packit 70b277
	/* Clean up. */
Packit 70b277
	bc_free_num (&int_part);
Packit 70b277
	bc_free_num (&frac_part);
Packit 70b277
	bc_free_num (&base);
Packit 70b277
	bc_free_num (&cur_dig);
Packit 70b277
	bc_free_num (&max_o_digit);
Packit 70b277
      }
Packit 70b277
}
Packit 70b277
/* Convert a number NUM to a long.  The function returns only the integer
Packit 70b277
   part of the number.  For numbers that are too large to represent as
Packit 70b277
   a long, this function returns a zero.  This can be detected by checking
Packit 70b277
   the NUM for zero after having a zero returned. */
Packit 70b277
Packit 70b277
long
Packit 70b277
bc_num2long (bc_num num)
Packit 70b277
{
Packit 70b277
  long val;
Packit 70b277
  char *nptr;
Packit 70b277
  int  i;
Packit 70b277
Packit 70b277
  /* Extract the int value, ignore the fraction. */
Packit 70b277
  val = 0;
Packit 70b277
  nptr = num->n_value;
Packit 70b277
  for (i=num->n_len; (i>0) && (val<=(LONG_MAX/BASE)); i--)
Packit 70b277
    val = val*BASE + *nptr++;
Packit 70b277
Packit 70b277
  /* Check for overflow.  If overflow, return zero. */
Packit 70b277
  if (i>0) val = 0;
Packit 70b277
  if (val < 0) val = 0;
Packit 70b277
Packit 70b277
  /* Return the value. */
Packit 70b277
  if (num->n_sign == PLUS)
Packit 70b277
    return (val);
Packit 70b277
  else
Packit 70b277
    return (-val);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* Convert an integer VAL to a bc number NUM. */
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_int2num (bc_num *num, int val)
Packit 70b277
{
Packit 70b277
  char buffer[30];
Packit 70b277
  char *bptr, *vptr;
Packit 70b277
  int  ix = 1;
Packit 70b277
  char neg = 0;
Packit 70b277
Packit 70b277
  /* Sign. */
Packit 70b277
  if (val < 0)
Packit 70b277
    {
Packit 70b277
      neg = 1;
Packit 70b277
      val = -val;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Get things going. */
Packit 70b277
  bptr = buffer;
Packit 70b277
  *bptr++ = val % BASE;
Packit 70b277
  val = val / BASE;
Packit 70b277
Packit 70b277
  /* Extract remaining digits. */
Packit 70b277
  while (val != 0)
Packit 70b277
    {
Packit 70b277
      *bptr++ = val % BASE;
Packit 70b277
      val = val / BASE;
Packit 70b277
      ix++; 		/* Count the digits. */
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Make the number. */
Packit 70b277
  bc_free_num (num);
Packit 70b277
  *num = bc_new_num (ix, 0);
Packit 70b277
  if (neg) (*num)->n_sign = MINUS;
Packit 70b277
Packit 70b277
  /* Assign the digits. */
Packit 70b277
  vptr = (*num)->n_value;
Packit 70b277
  while (ix-- > 0)
Packit 70b277
    *vptr++ = *--bptr;
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Convert a numbers to a string.  Base 10 only.*/
Packit 70b277
Packit 70b277
char
Packit 70b277
*bc_num2str (bc_num num)
Packit 70b277
{
Packit 70b277
  char *str, *sptr;
Packit 70b277
  char *nptr;
Packit 70b277
  int  i, signch;
Packit 70b277
Packit 70b277
  /* Allocate the string memory. */
Packit 70b277
  signch = ( num->n_sign == PLUS ? 0 : 1 );  /* Number of sign chars. */
Packit 70b277
  if (num->n_scale > 0)
Packit 70b277
    str = (char *) malloc (num->n_len + num->n_scale + 2 + signch);
Packit 70b277
  else
Packit 70b277
    str = (char *) malloc (num->n_len + 1 + signch);
Packit 70b277
  if (str == NULL) bc_out_of_memory();
Packit 70b277
Packit 70b277
  /* The negative sign if needed. */
Packit 70b277
  sptr = str;
Packit 70b277
  if (signch) *sptr++ = '-';
Packit 70b277
Packit 70b277
  /* Load the whole number. */
Packit 70b277
  nptr = num->n_value;
Packit 70b277
  for (i=num->n_len; i>0; i--)
Packit 70b277
    *sptr++ = BCD_CHAR(*nptr++);
Packit 70b277
Packit 70b277
  /* Now the fraction. */
Packit 70b277
  if (num->n_scale > 0)
Packit 70b277
    {
Packit 70b277
      *sptr++ = '.';
Packit 70b277
      for (i=0; i<num->n_scale; i++)
Packit 70b277
	*sptr++ = BCD_CHAR(*nptr++);
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Terminate the string and return it! */
Packit 70b277
  *sptr = '\0';
Packit 70b277
  return (str);
Packit 70b277
}
Packit 70b277
/* Convert strings to bc numbers.  Base 10 only.*/
Packit 70b277
Packit 70b277
void
Packit 70b277
bc_str2num (bc_num *num, char *str, int scale)
Packit 70b277
{
Packit 70b277
  int digits, strscale;
Packit 70b277
  char *ptr, *nptr;
Packit 70b277
  char zero_int;
Packit 70b277
Packit 70b277
  /* Prepare num. */
Packit 70b277
  bc_free_num (num);
Packit 70b277
Packit 70b277
  /* Check for valid number and count digits. */
Packit 70b277
  ptr = str;
Packit 70b277
  digits = 0;
Packit 70b277
  strscale = 0;
Packit 70b277
  zero_int = FALSE;
Packit 70b277
  if ( (*ptr == '+') || (*ptr == '-'))  ptr++;  /* Sign */
Packit 70b277
  while (*ptr == '0') ptr++;			/* Skip leading zeros. */
Packit 70b277
  while (isdigit((int)*ptr)) ptr++, digits++;	/* digits */
Packit 70b277
  if (*ptr == '.') ptr++;			/* decimal point */
Packit 70b277
  while (isdigit((int)*ptr)) ptr++, strscale++;	/* digits */
Packit 70b277
  if ((*ptr != '\0') || (digits+strscale == 0))
Packit 70b277
    {
Packit 70b277
      *num = bc_copy_num (_zero_);
Packit 70b277
      return;
Packit 70b277
    }
Packit 70b277
Packit 70b277
  /* Adjust numbers and allocate storage and initialize fields. */
Packit 70b277
  strscale = MIN(strscale, scale);
Packit 70b277
  if (digits == 0)
Packit 70b277
    {
Packit 70b277
      zero_int = TRUE;
Packit 70b277
      digits = 1;
Packit 70b277
    }
Packit 70b277
  *num = bc_new_num (digits, strscale);
Packit 70b277
Packit 70b277
  /* Build the whole number. */
Packit 70b277
  ptr = str;
Packit 70b277
  if (*ptr == '-')
Packit 70b277
    {
Packit 70b277
      (*num)->n_sign = MINUS;
Packit 70b277
      ptr++;
Packit 70b277
    }
Packit 70b277
  else
Packit 70b277
    {
Packit 70b277
      (*num)->n_sign = PLUS;
Packit 70b277
      if (*ptr == '+') ptr++;
Packit 70b277
    }
Packit 70b277
  while (*ptr == '0') ptr++;			/* Skip leading zeros. */
Packit 70b277
  nptr = (*num)->n_value;
Packit 70b277
  if (zero_int)
Packit 70b277
    {
Packit 70b277
      *nptr++ = 0;
Packit 70b277
      digits = 0;
Packit 70b277
    }
Packit 70b277
  for (;digits > 0; digits--)
Packit 70b277
    *nptr++ = CH_VAL(*ptr++);
Packit 70b277
Packit 70b277
Packit 70b277
  /* Build the fractional part. */
Packit 70b277
  if (strscale > 0)
Packit 70b277
    {
Packit 70b277
      ptr++;  /* skip the decimal point! */
Packit 70b277
      for (;strscale > 0; strscale--)
Packit 70b277
	*nptr++ = CH_VAL(*ptr++);
Packit 70b277
    }
Packit 70b277
}
Packit 70b277
Packit 70b277
/* Debugging routines */
Packit 70b277
Packit 70b277
#ifdef DEBUG
Packit 70b277
Packit 70b277
/* pn prints the number NUM in base 10. */
Packit 70b277
Packit 70b277
static void
Packit 70b277
out_char (int c)
Packit 70b277
{
Packit 70b277
  putchar(c);
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
void
Packit 70b277
pn (bc_num num)
Packit 70b277
{
Packit 70b277
  bc_out_num (num, 10, out_char, 0);
Packit 70b277
  out_char ('\n');
Packit 70b277
}
Packit 70b277
Packit 70b277
Packit 70b277
/* pv prints a character array as if it was a string of bcd digits. */
Packit 70b277
void
Packit 70b277
pv (char *name, unsigned char *num, int len)
Packit 70b277
{
Packit 70b277
  int i;
Packit 70b277
  printf ("%s=", name);
Packit 70b277
  for (i=0; i
Packit 70b277
  printf ("\n");
Packit 70b277
}
Packit 70b277
Packit 70b277
#endif