summaryrefslogtreecommitdiff
path: root/lib/number.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/number.c')
-rw-r--r--lib/number.c222
1 files changed, 83 insertions, 139 deletions
diff --git a/lib/number.c b/lib/number.c
index 1f913d5..f394e92 100644
--- a/lib/number.c
+++ b/lib/number.c
@@ -1,10 +1,10 @@
/* number.c: Implements arbitrary precision numbers. */
/*
- Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1991, 1992, 1993, 1994, 1997, 2000, 2012-2017 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License , or
+ the Free Software Foundation; either version 3 of the License , or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -16,8 +16,8 @@
along with this program; see the file COPYING. If not, write to:
The Free Software Foundation, Inc.
- 59 Temple Place, Suite 330
- Boston, MA 02111-1307 USA.
+ 51 Franklin Street, Fifth Floor
+ Boston, MA 02110-1301 USA
You may contact the author by:
@@ -33,16 +33,23 @@
#include <config.h>
#include <number.h>
#include <assert.h>
+#ifdef HAVE_STDLIB_H
#include <stdlib.h>
-#include <ctype.h>/* Prototypes needed for external utility routines. */
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <ctype.h>
+
+/* Prototypes needed for external utility routines. */
#define bc_rt_warn rt_warn
#define bc_rt_error rt_error
#define bc_out_of_memory out_of_memory
-_PROTOTYPE(void rt_warn, (char *mesg ,...));
-_PROTOTYPE(void rt_error, (char *mesg ,...));
-_PROTOTYPE(void out_of_memory, (void));
+void rt_warn (const char *mesg ,...);
+void rt_error (const char *mesg ,...);
+void out_of_memory (void);
/* Storage used for special numbers. */
bc_num _zero_;
@@ -54,8 +61,7 @@ static bc_num _bc_Free_list = NULL;
/* new_num allocates a number and sets fields to known values. */
bc_num
-bc_new_num (length, scale)
- int length, scale;
+bc_new_num (int length, int scale)
{
bc_num temp;
@@ -81,8 +87,7 @@ bc_new_num (length, scale)
frees the storage if reference count is zero. */
void
-bc_free_num (num)
- bc_num *num;
+bc_free_num (bc_num *num)
{
if (*num == NULL) return;
(*num)->n_refs--;
@@ -99,7 +104,7 @@ bc_free_num (num)
/* Intitialize the number package! */
void
-bc_init_numbers ()
+bc_init_numbers (void)
{
_zero_ = bc_new_num (1,0);
_one_ = bc_new_num (1,0);
@@ -112,8 +117,7 @@ bc_init_numbers ()
/* Make a copy of a number! Just increments the reference count! */
bc_num
-bc_copy_num (num)
- bc_num num;
+bc_copy_num (bc_num num)
{
num->n_refs++;
return num;
@@ -123,19 +127,16 @@ bc_copy_num (num)
/* Initialize a number NUM by making it a copy of zero. */
void
-bc_init_num (num)
- bc_num *num;
+bc_init_num (bc_num *num)
{
*num = bc_copy_num (_zero_);
}
-
/* For many things, we may have leading zeros in a number NUM.
_bc_rm_leading_zeros just moves the data "value" pointer to the
correct place and adjusts the length. */
static void
-_bc_rm_leading_zeros (num)
- bc_num num;
+_bc_rm_leading_zeros (bc_num num)
{
/* We can move n_value to point to the first non zero digit! */
while (*num->n_value == 0 && num->n_len > 1) {
@@ -150,10 +151,7 @@ _bc_rm_leading_zeros (num)
compare the magnitudes. */
static int
-_bc_do_compare (n1, n2, use_sign, ignore_last)
- bc_num n1, n2;
- int use_sign;
- int ignore_last;
+_bc_do_compare ( bc_num n1, bc_num n2, int use_sign, int ignore_last )
{
char *n1ptr, *n2ptr;
int count;
@@ -259,8 +257,7 @@ _bc_do_compare (n1, n2, use_sign, ignore_last)
/* This is the "user callable" routine to compare numbers N1 and N2. */
int
-bc_compare (n1, n2)
- bc_num n1, n2;
+bc_compare ( bc_num n1, bc_num n2 )
{
return _bc_do_compare (n1, n2, TRUE, FALSE);
}
@@ -268,8 +265,7 @@ bc_compare (n1, n2)
/* In some places we need to check if the number is negative. */
char
-bc_is_neg (num)
- bc_num num;
+bc_is_neg (bc_num num)
{
return num->n_sign == MINUS;
}
@@ -277,8 +273,7 @@ bc_is_neg (num)
/* In some places we need to check if the number NUM is zero. */
char
-bc_is_zero (num)
- bc_num num;
+bc_is_zero (bc_num num)
{
int count;
char *nptr;
@@ -304,9 +299,7 @@ bc_is_zero (num)
Last digit is defined by scale. */
char
-bc_is_near_zero (num, scale)
- bc_num num;
- int scale;
+bc_is_near_zero (bc_num num, int scale)
{
int count;
char *nptr;
@@ -334,9 +327,7 @@ bc_is_near_zero (num, scale)
SCALE_MIN is to set the minimum scale of the result. */
static bc_num
-_bc_do_add (n1, n2, scale_min)
- bc_num n1, n2;
- int scale_min;
+_bc_do_add (bc_num n1, bc_num n2, int scale_min)
{
bc_num sum;
int sum_scale, sum_digits;
@@ -426,9 +417,7 @@ _bc_do_add (n1, n2, scale_min)
of the result. */
static bc_num
-_bc_do_sub (n1, n2, scale_min)
- bc_num n1, n2;
- int scale_min;
+_bc_do_sub (bc_num n1, bc_num n2, int scale_min)
{
bc_num diff;
int diff_scale, diff_len;
@@ -526,9 +515,7 @@ _bc_do_sub (n1, n2, scale_min)
is the minimum scale for the result. */
void
-bc_sub (n1, n2, result, scale_min)
- bc_num n1, n2, *result;
- int scale_min;
+bc_sub (bc_num n1, bc_num n2, bc_num *result, int scale_min)
{
bc_num diff = NULL;
int cmp_res;
@@ -576,9 +563,7 @@ bc_sub (n1, n2, result, scale_min)
is the minimum scale for the result. */
void
-bc_add (n1, n2, result, scale_min)
- bc_num n1, n2, *result;
- int scale_min;
+bc_add (bc_num n1, bc_num n2, bc_num *result, int scale_min)
{
bc_num sum = NULL;
int cmp_res;
@@ -631,9 +616,7 @@ int mul_base_digits = MUL_BASE_DIGITS;
/* Multiply utility routines */
static bc_num
-new_sub_num (length, scale, value)
- int length, scale;
- char *value;
+new_sub_num (int length, int scale, char *value)
{
bc_num temp;
@@ -654,8 +637,7 @@ new_sub_num (length, scale, value)
}
static void
-_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod,
- int full_scale)
+_bc_simp_mul (bc_num n1, int n1len, bc_num n2, int n2len, bc_num *prod)
{
char *n1ptr, *n2ptr, *pvptr;
char *n1end, *n2end; /* To the end of n1 and n2. */
@@ -755,11 +737,9 @@ _bc_shift_addsub (bc_num accum, bc_num val, int shift, int sub)
B is the base of storage, number of digits in u1,u0 close to equal.
*/
static void
-_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
- int full_scale)
+_bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod)
{
bc_num u0, u1, v0, v1;
- int u0len, v0len;
bc_num m1, m2, m3, d1, d2;
int n, prodlen, m1zero;
int d1len, d2len;
@@ -768,7 +748,7 @@ _bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
if ((ulen+vlen) < mul_base_digits
|| ulen < MUL_SMALL_DIGITS
|| vlen < MUL_SMALL_DIGITS ) {
- _bc_simp_mul (u, ulen, v, vlen, prod, full_scale);
+ _bc_simp_mul (u, ulen, v, vlen, prod);
return;
}
@@ -792,10 +772,8 @@ _bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
}
_bc_rm_leading_zeros (u1);
_bc_rm_leading_zeros (u0);
- u0len = u0->n_len;
_bc_rm_leading_zeros (v1);
_bc_rm_leading_zeros (v0);
- v0len = v0->n_len;
m1zero = bc_is_zero(u1) || bc_is_zero(v1);
@@ -813,17 +791,17 @@ _bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
if (m1zero)
m1 = bc_copy_num (_zero_);
else
- _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1, 0);
+ _bc_rec_mul (u1, u1->n_len, v1, v1->n_len, &m1);
if (bc_is_zero(d1) || bc_is_zero(d2))
m2 = bc_copy_num (_zero_);
else
- _bc_rec_mul (d1, d1len, d2, d2len, &m2, 0);
+ _bc_rec_mul (d1, d1len, d2, d2len, &m2);
if (bc_is_zero(u0) || bc_is_zero(v0))
m3 = bc_copy_num (_zero_);
else
- _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3, 0);
+ _bc_rec_mul (u0, u0->n_len, v0, v0->n_len, &m3);
/* Initialize product */
prodlen = ulen+vlen+1;
@@ -854,9 +832,7 @@ _bc_rec_mul (bc_num u, int ulen, bc_num v, int vlen, bc_num *prod,
*/
void
-bc_multiply (n1, n2, prod, scale)
- bc_num n1, n2, *prod;
- int scale;
+bc_multiply (bc_num n1, bc_num n2, bc_num *prod, int scale)
{
bc_num pval;
int len1, len2;
@@ -869,7 +845,7 @@ bc_multiply (n1, n2, prod, scale)
prod_scale = MIN(full_scale,MAX(scale,MAX(n1->n_scale,n2->n_scale)));
/* Do the multiply */
- _bc_rec_mul (n1, len1, n2, len2, &pval, full_scale);
+ _bc_rec_mul (n1, len1, n2, len2, &pval);
/* Assign to prod and clean up the number. */
pval->n_sign = ( n1->n_sign == n2->n_sign ? PLUS : MINUS );
@@ -889,10 +865,7 @@ bc_multiply (n1, n2, prod, scale)
the same pointers. */
static void
-_one_mult (num, size, digit, result)
- unsigned char *num;
- int size, digit;
- unsigned char *result;
+_one_mult (unsigned char *num, int size, int digit, unsigned char *result)
{
int carry, value;
unsigned char *nptr, *rptr;
@@ -929,9 +902,7 @@ _one_mult (num, size, digit, result)
by zero is tried. The algorithm is found in Knuth Vol 2. p237. */
int
-bc_divide (n1, n2, quot, scale)
- bc_num n1, n2, *quot;
- int scale;
+bc_divide (bc_num n1, bc_num n2, bc_num *quot, int scale)
{
bc_num qval;
unsigned char *num1, *num2;
@@ -1125,9 +1096,7 @@ bc_divide (n1, n2, quot, scale)
*/
int
-bc_divmod (num1, num2, quot, rem, scale)
- bc_num num1, num2, *quot, *rem;
- int scale;
+bc_divmod (bc_num num1, bc_num num2, bc_num *quot, bc_num *rem, int scale)
{
bc_num quotient = NULL;
bc_num temp;
@@ -1162,9 +1131,7 @@ bc_divmod (num1, num2, quot, rem, scale)
result in RESULT. */
int
-bc_modulo (num1, num2, result, scale)
- bc_num num1, num2, *result;
- int scale;
+bc_modulo ( bc_num num1, bc_num num2, bc_num *result, int scale)
{
return bc_divmod (num1, num2, NULL, result, scale);
}
@@ -1174,9 +1141,7 @@ bc_modulo (num1, num2, result, scale)
only the integer part is used. */
int
-bc_raisemod (base, expo, mod, result, scale)
- bc_num base, expo, mod, *result;
- int scale;
+bc_raisemod (bc_num base, bc_num expo, bc_num mod, bc_num *result, int scale)
{
bc_num power, exponent, parity, temp;
int rscale;
@@ -1234,12 +1199,11 @@ bc_raisemod (base, expo, mod, result, scale)
only the integer part is used. */
void
-bc_raise (num1, num2, result, scale)
- bc_num num1, num2, *result;
- int scale;
+bc_raise (bc_num num1, bc_num num2, bc_num *result, int scale)
{
bc_num temp, power;
long exponent;
+ unsigned long uexponent;
int rscale;
int pwrscale;
int calcscale;
@@ -1264,38 +1228,40 @@ bc_raise (num1, num2, result, scale)
if (exponent < 0)
{
neg = TRUE;
- exponent = -exponent;
+ uexponent = -exponent;
rscale = scale;
}
else
{
neg = FALSE;
- rscale = MIN (num1->n_scale*exponent, MAX(scale, num1->n_scale));
+ uexponent = exponent;
+ rscale = MIN (num1->n_scale*uexponent,
+ (unsigned long) MAX(scale, num1->n_scale));
}
/* Set initial value of temp. */
power = bc_copy_num (num1);
pwrscale = num1->n_scale;
- while ((exponent & 1) == 0)
+ while ((uexponent & 1) == 0)
{
- pwrscale = 2*pwrscale;
+ pwrscale <<= 1;
bc_multiply (power, power, &power, pwrscale);
- exponent = exponent >> 1;
+ uexponent = uexponent >> 1;
}
temp = bc_copy_num (power);
calcscale = pwrscale;
- exponent = exponent >> 1;
+ uexponent >>= 1;
/* Do the calculation. */
- while (exponent > 0)
+ while (uexponent > 0)
{
- pwrscale = 2*pwrscale;
+ pwrscale <<= 1;
bc_multiply (power, power, &power, pwrscale);
- if ((exponent & 1) == 1) {
+ if ((uexponent & 1) == 1) {
calcscale = pwrscale + calcscale;
bc_multiply (temp, power, &temp, calcscale);
}
- exponent = exponent >> 1;
+ uexponent >>= 1;
}
/* Assign the value. */
@@ -1318,9 +1284,7 @@ bc_raise (num1, num2, result, scale)
after the decimal place. */
int
-bc_sqrt (num, scale)
- bc_num *num;
- int scale;
+bc_sqrt (bc_num *num, int scale)
{
int rscale, cmp_res, done;
int cscale;
@@ -1425,20 +1389,13 @@ static char ref_str[] = "0123456789ABCDEF";
is the actual routine for writing the characters. */
void
-bc_out_long (val, size, space, out_char)
- long val;
- int size, space;
-#ifdef __STDC__
- void (*out_char)(int);
-#else
- void (*out_char)();
-#endif
+bc_out_long (long val, int size, int space, void (*out_char)(int))
{
char digits[40];
int len, ix;
if (space) (*out_char) (' ');
- sprintf (digits, "%ld", val);
+ snprintf (digits, sizeof(digits), "%ld", val);
len = strlen (digits);
while (size > len)
{
@@ -1453,18 +1410,10 @@ bc_out_long (val, size, space, out_char)
as the routine to do the actual output of the characters. */
void
-bc_out_num (num, o_base, out_char, leading_zero)
- bc_num num;
- int o_base;
-#ifdef __STDC__
- void (*out_char)(int);
-#else
- void (*out_char)();
-#endif
- int leading_zero;
+bc_out_num (bc_num num, int o_base, void (*out_char)(int), int leading_zero)
{
char *nptr;
- int index, fdigit, pre_space;
+ int ix, fdigit, pre_space;
stk_rec *digits, *temp;
bc_num int_part, frac_part, base, cur_dig, t_num, max_o_digit;
@@ -1480,7 +1429,7 @@ bc_out_num (num, o_base, out_char, leading_zero)
/* The number is in base 10, do it the fast way. */
nptr = num->n_value;
if (num->n_len > 1 || *nptr != 0)
- for (index=num->n_len; index>0; index--)
+ for (ix=num->n_len; ix>0; ix--)
(*out_char) (BCD_CHAR(*nptr++));
else
nptr++;
@@ -1492,7 +1441,7 @@ bc_out_num (num, o_base, out_char, leading_zero)
if (num->n_scale > 0)
{
(*out_char) ('.');
- for (index=0; index<num->n_scale; index++)
+ for (ix=0; ix<num->n_scale; ix++)
(*out_char) (BCD_CHAR(*nptr++));
}
}
@@ -1582,21 +1531,20 @@ bc_out_num (num, o_base, out_char, leading_zero)
the NUM for zero after having a zero returned. */
long
-bc_num2long (num)
- bc_num num;
+bc_num2long (bc_num num)
{
long val;
char *nptr;
- int index;
+ int i;
/* Extract the int value, ignore the fraction. */
val = 0;
nptr = num->n_value;
- for (index=num->n_len; (index>0) && (val<=(LONG_MAX/BASE)); index--)
+ for (i=num->n_len; (i>0) && (val<=(LONG_MAX/BASE)); i--)
val = val*BASE + *nptr++;
/* Check for overflow. If overflow, return zero. */
- if (index>0) val = 0;
+ if (i>0) val = 0;
if (val < 0) val = 0;
/* Return the value. */
@@ -1610,9 +1558,7 @@ bc_num2long (num)
/* Convert an integer VAL to a bc number NUM. */
void
-bc_int2num (num, val)
- bc_num *num;
- int val;
+bc_int2num (bc_num *num, int val)
{
char buffer[30];
char *bptr, *vptr;
@@ -1653,12 +1599,11 @@ bc_int2num (num, val)
/* Convert a numbers to a string. Base 10 only.*/
char
-*num2str (num)
- bc_num num;
+*bc_num2str (bc_num num)
{
char *str, *sptr;
char *nptr;
- int index, signch;
+ int i, signch;
/* Allocate the string memory. */
signch = ( num->n_sign == PLUS ? 0 : 1 ); /* Number of sign chars. */
@@ -1674,14 +1619,14 @@ char
/* Load the whole number. */
nptr = num->n_value;
- for (index=num->n_len; index>0; index--)
+ for (i=num->n_len; i>0; i--)
*sptr++ = BCD_CHAR(*nptr++);
/* Now the fraction. */
if (num->n_scale > 0)
{
*sptr++ = '.';
- for (index=0; index<num->n_scale; index++)
+ for (i=0; i<num->n_scale; i++)
*sptr++ = BCD_CHAR(*nptr++);
}
@@ -1692,10 +1637,7 @@ char
/* Convert strings to bc numbers. Base 10 only.*/
void
-bc_str2num (num, str, scale)
- bc_num *num;
- char *str;
- int scale;
+bc_str2num (bc_num *num, char *str, int scale)
{
int digits, strscale;
char *ptr, *nptr;
@@ -1761,6 +1703,10 @@ bc_str2num (num, str, scale)
}
}
+/* Debugging routines */
+
+#ifdef DEBUG
+
/* pn prints the number NUM in base 10. */
static void
@@ -1771,8 +1717,7 @@ out_char (int c)
void
-pn (num)
- bc_num num;
+pn (bc_num num)
{
bc_out_num (num, 10, out_char, 0);
out_char ('\n');
@@ -1781,13 +1726,12 @@ pn (num)
/* pv prints a character array as if it was a string of bcd digits. */
void
-pv (name, num, len)
- char *name;
- unsigned char *num;
- int len;
+pv (char *name, unsigned char *num, int len)
{
int i;
printf ("%s=", name);
for (i=0; i<len; i++) printf ("%c",BCD_CHAR(num[i]));
printf ("\n");
}
+
+#endif