summaryrefslogtreecommitdiff
path: root/libc/sysdeps/ieee754/dbl-64/mpa.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/sysdeps/ieee754/dbl-64/mpa.c')
-rw-r--r--libc/sysdeps/ieee754/dbl-64/mpa.c245
1 files changed, 100 insertions, 145 deletions
diff --git a/libc/sysdeps/ieee754/dbl-64/mpa.c b/libc/sysdeps/ieee754/dbl-64/mpa.c
index 7e0ee445c..7abad6782 100644
--- a/libc/sysdeps/ieee754/dbl-64/mpa.c
+++ b/libc/sysdeps/ieee754/dbl-64/mpa.c
@@ -1,7 +1,7 @@
/*
* IBM Accurate Mathematical Library
* written by International Business Machines Corp.
- * Copyright (C) 2001, 2011 Free Software Foundation
+ * Copyright (C) 2001-2013 Free Software Foundation, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
@@ -45,17 +45,20 @@
#include "endian.h"
#include "mpa.h"
#include "mpa2.h"
-#include <sys/param.h> /* For MIN() */
+#include <sys/param.h>
#ifndef SECTION
# define SECTION
#endif
+#ifndef NO__CONST
+const mp_no mpone = {1, {1.0, 1.0}};
+const mp_no mptwo = {1, {1.0, 2.0}};
+#endif
+
#ifndef NO___ACR
-/* mcr() compares the sizes of the mantissas of two multiple precision */
-/* numbers. Mantissas are compared regardless of the signs of the */
-/* numbers, even if x->d[0] or y->d[0] are zero. Exponents are also */
-/* disregarded. */
+/* Compare mantissa of two multiple precision numbers regardless of the sign
+ and exponent of the numbers. */
static int
mcr(const mp_no *x, const mp_no *y, int p) {
int i;
@@ -66,8 +69,7 @@ mcr(const mp_no *x, const mp_no *y, int p) {
return 0;
}
-
-/* acr() compares the absolute values of two multiple precision numbers */
+/* Compare the absolute values of two multiple precision numbers. */
int
__acr(const mp_no *x, const mp_no *y, int p) {
int i;
@@ -87,59 +89,22 @@ __acr(const mp_no *x, const mp_no *y, int p) {
}
#endif
-
-#if 0
-/* cr() compares the values of two multiple precision numbers */
-static int __cr(const mp_no *x, const mp_no *y, int p) {
- int i;
-
- if (X[0] > Y[0]) i= 1;
- else if (X[0] < Y[0]) i=-1;
- else if (X[0] < ZERO ) i= __acr(y,x,p);
- else i= __acr(x,y,p);
-
- return i;
-}
-#endif
-
-
#ifndef NO___CPY
-/* Copy a multiple precision number. Set *y=*x. x=y is permissible. */
+/* Copy multiple precision number X into Y. They could be the same
+ number. */
void __cpy(const mp_no *x, mp_no *y, int p) {
EY = EX;
for (int i=0; i <= p; i++) Y[i] = X[i];
}
#endif
-
-#if 0
-/* Copy a multiple precision number x of precision m into a */
-/* multiple precision number y of precision n. In case n>m, */
-/* the digits of y beyond the m'th are set to zero. In case */
-/* n<m, the digits of x beyond the n'th are ignored. */
-/* x=y is permissible. */
-
-static void __cpymn(const mp_no *x, int m, mp_no *y, int n) {
-
- int i,k;
-
- EY = EX; k=MIN(m,n);
- for (i=0; i <= k; i++) Y[i] = X[i];
- for ( ; i <= n; i++) Y[i] = ZERO;
-}
-#endif
-
-
#ifndef NO___MP_DBL
-/* Convert a multiple precision number *x into a double precision */
-/* number *y, normalized case (|x| >= 2**(-1022))) */
+/* Convert a multiple precision number *X into a double precision
+ number *Y, normalized case (|x| >= 2**(-1022))). */
static void norm(const mp_no *x, double *y, int p)
{
- #define R radixi.d
+ #define R RADIXI
int i;
-#if 0
- int k;
-#endif
double a,c,u,v,z[5];
if (p<5) {
if (p==1) c = X[1];
@@ -185,17 +150,14 @@ static void norm(const mp_no *x, double *y, int p)
#undef R
}
-/* Convert a multiple precision number *x into a double precision */
-/* number *y, denormalized case (|x| < 2**(-1022))) */
+/* Convert a multiple precision number *X into a double precision
+ number *Y, Denormal case (|x| < 2**(-1022))). */
static void denorm(const mp_no *x, double *y, int p)
{
int i,k;
double c,u,z[5];
-#if 0
- double a,v;
-#endif
-#define R radixi.d
+#define R RADIXI
if (EX<-44 || (EX==-44 && X[1]<TWO5))
{ *y=ZERO; return; }
@@ -232,28 +194,21 @@ static void denorm(const mp_no *x, double *y, int p)
#undef R
}
-/* Convert a multiple precision number *x into a double precision number *y. */
-/* The result is correctly rounded to the nearest/even. *x is left unchanged */
-
+/* Convert multiple precision number *X into double precision number *Y. The
+ result is correctly rounded to the nearest/even. */
void __mp_dbl(const mp_no *x, double *y, int p) {
-#if 0
- int i,k;
- double a,c,u,v,z[5];
-#endif
if (X[0] == ZERO) {*y = ZERO; return; }
- if (EX> -42) norm(x,y,p);
- else if (EX==-42 && X[1]>=TWO10) norm(x,y,p);
- else denorm(x,y,p);
+ if (__glibc_likely (EX > -42 || (EX == -42 && X[1] >= TWO10)))
+ norm(x,y,p);
+ else
+ denorm(x,y,p);
}
#endif
-
-/* dbl_mp() converts a double precision number x into a multiple precision */
-/* number *y. If the precision p is too small the result is truncated. x is */
-/* left unchanged. */
-
+/* Get the multiple precision equivalent of X into *Y. If the precision is too
+ small, the result is truncated. */
void
SECTION
__dbl_mp(double x, mp_no *y, int p) {
@@ -261,16 +216,16 @@ __dbl_mp(double x, mp_no *y, int p) {
int i,n;
double u;
- /* Sign */
+ /* Sign. */
if (x == ZERO) {Y[0] = ZERO; return; }
else if (x > ZERO) Y[0] = ONE;
else {Y[0] = MONE; x=-x; }
- /* Exponent */
+ /* Exponent. */
for (EY=ONE; x >= RADIX; EY += ONE) x *= RADIXI;
for ( ; x < ONE; EY -= ONE) x *= RADIX;
- /* Digits */
+ /* Digits. */
n=MIN(p,4);
for (i=1; i<=n; i++) {
u = (x + TWO52) - TWO52;
@@ -279,13 +234,10 @@ __dbl_mp(double x, mp_no *y, int p) {
for ( ; i<=p; i++) Y[i] = ZERO;
}
-
-/* add_magnitudes() adds the magnitudes of *x & *y assuming that */
-/* abs(*x) >= abs(*y) > 0. */
-/* The sign of the sum *z is undefined. x&y may overlap but not x&z or y&z. */
-/* No guard digit is used. The result equals the exact sum, truncated. */
-/* *x & *y are left unchanged. */
-
+/* Add magnitudes of *X and *Y assuming that abs (*X) >= abs (*Y) > 0. The
+ sign of the sum *Z is not changed. X and Y may overlap but not X and Z or
+ Y and Z. No guard digit is used. The result equals the exact sum,
+ truncated. */
static void
SECTION
add_magnitudes(const mp_no *x, const mp_no *y, mp_no *z, int p) {
@@ -323,13 +275,10 @@ add_magnitudes(const mp_no *x, const mp_no *y, mp_no *z, int p) {
else EZ += ONE;
}
-
-/* sub_magnitudes() subtracts the magnitudes of *x & *y assuming that */
-/* abs(*x) > abs(*y) > 0. */
-/* The sign of the difference *z is undefined. x&y may overlap but not x&z */
-/* or y&z. One guard digit is used. The error is less than one ulp. */
-/* *x & *y are left unchanged. */
-
+/* Subtract the magnitudes of *X and *Y assuming that abs (*x) > abs (*y) > 0.
+ The sign of the difference *Z is not changed. X and Y may overlap but not X
+ and Z or Y and Z. One guard digit is used. The error is less than one
+ ULP. */
static void
SECTION
sub_magnitudes(const mp_no *x, const mp_no *y, mp_no *z, int p) {
@@ -381,11 +330,9 @@ sub_magnitudes(const mp_no *x, const mp_no *y, mp_no *z, int p) {
Z[k++] = ZERO;
}
-
-/* Add two multiple precision numbers. Set *z = *x + *y. x&y may overlap */
-/* but not x&z or y&z. One guard digit is used. The error is less than */
-/* one ulp. *x & *y are left unchanged. */
-
+/* Add *X and *Y and store the result in *Z. X and Y may overlap, but not X
+ and Z or Y and Z. One guard digit is used. The error is less than one
+ ULP. */
void
SECTION
__add(const mp_no *x, const mp_no *y, mp_no *z, int p) {
@@ -406,11 +353,9 @@ __add(const mp_no *x, const mp_no *y, mp_no *z, int p) {
}
}
-
-/* Subtract two multiple precision numbers. *z is set to *x - *y. x&y may */
-/* overlap but not x&z or y&z. One guard digit is used. The error is */
-/* less than one ulp. *x & *y are left unchanged. */
-
+/* Subtract *Y from *X and return the result in *Z. X and Y may overlap but
+ not X and Z or Y and Z. One guard digit is used. The error is less than
+ one ULP. */
void
SECTION
__sub(const mp_no *x, const mp_no *y, mp_no *z, int p) {
@@ -431,68 +376,77 @@ __sub(const mp_no *x, const mp_no *y, mp_no *z, int p) {
}
}
-
-/* Multiply two multiple precision numbers. *z is set to *x * *y. x&y */
-/* may overlap but not x&z or y&z. In case p=1,2,3 the exact result is */
-/* truncated to p digits. In case p>3 the error is bounded by 1.001 ulp. */
-/* *x & *y are left unchanged. */
-
+/* Multiply *X and *Y and store result in *Z. X and Y may overlap but not X
+ and Z or Y and Z. For P in [1, 2, 3], the exact result is truncated to P
+ digits. In case P > 3 the error is bounded by 1.001 ULP. */
void
SECTION
__mul(const mp_no *x, const mp_no *y, mp_no *z, int p) {
- int i, i1, i2, j, k, k2;
+ int i, j, k, k2;
double u;
- /* Is z=0? */
- if (X[0]*Y[0]==ZERO)
- { Z[0]=ZERO; return; }
-
- /* Multiply, add and carry */
- k2 = (p<3) ? p+p : p+3;
- Z[k2]=ZERO;
- for (k=k2; k>1; ) {
- if (k > p) {i1=k-p; i2=p+1; }
- else {i1=1; i2=k; }
- for (i=i1,j=i2-1; i<i2; i++,j--) Z[k] += X[i]*Y[j];
-
- u = (Z[k] + CUTTER)-CUTTER;
- if (u > Z[k]) u -= RADIX;
- Z[k] -= u;
- Z[--k] = u*RADIXI;
- }
+ /* Is z=0? */
+ if (__glibc_unlikely (X[0] * Y[0] == ZERO))
+ {
+ Z[0]=ZERO;
+ return;
+ }
- /* Is there a carry beyond the most significant digit? */
- if (Z[1] == ZERO) {
- for (i=1; i<=p; i++) Z[i]=Z[i+1];
- EZ = EX + EY - 1; }
- else
- EZ = EX + EY;
+ /* Multiply, add and carry. */
+ k2 = (__glibc_unlikely (p < 3)) ? p + p : p + 3;
+ Z[k2] = ZERO;
+
+ for (k = k2; k > p; )
+ {
+ for (i = k - p, j = p; i < p + 1; i++, j--)
+ Z[k] += X[i] * Y[j];
+
+ u = (Z[k] + CUTTER) - CUTTER;
+ if (u > Z[k])
+ u -= RADIX;
+ Z[k] -= u;
+ Z[--k] = u * RADIXI;
+ }
+
+ while (k > 1)
+ {
+ for (i = 1,j = k - 1; i < k; i++, j--)
+ Z[k] += X[i] * Y[j];
+
+ u = (Z[k] + CUTTER) - CUTTER;
+ if (u > Z[k])
+ u -= RADIX;
+ Z[k] -= u;
+ Z[--k] = u * RADIXI;
+ }
+
+ EZ = EX + EY;
+ /* Is there a carry beyond the most significant digit? */
+ if (__glibc_unlikely (Z[1] == ZERO))
+ {
+ for (i = 1; i <= p; i++)
+ Z[i] = Z[i+1];
+ EZ--;
+ }
Z[0] = X[0] * Y[0];
}
+/* Invert *X and store in *Y. Relative error bound:
+ - For P = 2: 1.001 * R ^ (1 - P)
+ - For P = 3: 1.063 * R ^ (1 - P)
+ - For P > 3: 2.001 * R ^ (1 - P)
-/* Invert a multiple precision number. Set *y = 1 / *x. */
-/* Relative error bound = 1.001*r**(1-p) for p=2, 1.063*r**(1-p) for p=3, */
-/* 2.001*r**(1-p) for p>3. */
-/* *x=0 is not permissible. *x is left unchanged. */
-
+ *X = 0 is not permissible. */
static
SECTION
void __inv(const mp_no *x, mp_no *y, int p) {
int i;
-#if 0
- int l;
-#endif
double t;
mp_no z,w;
static const int np1[] = {0,0,0,0,1,2,2,2,2,3,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4};
- const mp_no mptwo = {1,{1.0,2.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,
- 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,
- 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,
- 0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}};
__cpy(x,&z,p); z.e=0; __mp_dbl(&z,&t,p);
t=ONE/t; __dbl_mp(t,y,p); EY -= EX;
@@ -505,12 +459,13 @@ void __inv(const mp_no *x, mp_no *y, int p) {
}
}
+/* Divide *X by *Y and store result in *Z. X and Y may overlap but not X and Z
+ or Y and Z. Relative error bound:
+ - For P = 2: 2.001 * R ^ (1 - P)
+ - For P = 3: 2.063 * R ^ (1 - P)
+ - For P > 3: 3.001 * R ^ (1 - P)
-/* Divide one multiple precision number by another.Set *z = *x / *y. *x & *y */
-/* are left unchanged. x&y may overlap but not x&z or y&z. */
-/* Relative error bound = 2.001*r**(1-p) for p=2, 2.063*r**(1-p) for p=3 */
-/* and 3.001*r**(1-p) for p>3. *y=0 is not permissible. */
-
+ *X = 0 is not permissible. */
void
SECTION
__dvd(const mp_no *x, const mp_no *y, mp_no *z, int p) {