mirror of
https://sourceware.org/git/glibc.git
synced 2025-08-10 05:03:06 +03:00
New __sqr function as a faster special case of __mul
This commit is contained in:
13
ChangeLog
13
ChangeLog
@@ -1,3 +1,16 @@
|
|||||||
|
2013-02-14 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||||
|
|
||||||
|
* sysdeps/ieee754/dbl-64/mpa.c (__sqr): New function.
|
||||||
|
* sysdeps/ieee754/dbl-64/mpa.h (__sqr): Declare.
|
||||||
|
* sysdeps/ieee754/dbl-64/mpexp.c (__mpexp): use __sqr instead
|
||||||
|
of __mul for squares.
|
||||||
|
* sysdeps/powerpc/powerpc32/power4/fpu/mpa.c (__sqr): New
|
||||||
|
function
|
||||||
|
* sysdeps/powerpc/powerpc64/power4/fpu/mpa.c (__sqr):
|
||||||
|
Likewise.
|
||||||
|
* sysdeps/x86_64/fpu/multiarch/mpa-avx.c: Define __sqr.
|
||||||
|
* sysdeps/x86_64/fpu/multiarch/mpa-fma4.c: Likewise.
|
||||||
|
|
||||||
2013-02-13 Joseph Myers <joseph@codesourcery.com>
|
2013-02-13 Joseph Myers <joseph@codesourcery.com>
|
||||||
|
|
||||||
[BZ #13550]
|
[BZ #13550]
|
||||||
|
@@ -702,6 +702,97 @@ __mul (const mp_no *x, const mp_no *y, mp_no *z, int p)
|
|||||||
Z[0] = X[0] * Y[0];
|
Z[0] = X[0] * Y[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Square *X and store result in *Y. X and Y may not overlap. 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. This is a faster special case of
|
||||||
|
multiplication. */
|
||||||
|
void
|
||||||
|
SECTION
|
||||||
|
__sqr (const mp_no *x, mp_no *y, int p)
|
||||||
|
{
|
||||||
|
long i, j, k, ip;
|
||||||
|
double u, yk;
|
||||||
|
|
||||||
|
/* Is z=0? */
|
||||||
|
if (__glibc_unlikely (X[0] == ZERO))
|
||||||
|
{
|
||||||
|
Y[0] = ZERO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need not iterate through all X's since it's pointless to
|
||||||
|
multiply zeroes. */
|
||||||
|
for (ip = p; ip > 0; ip--)
|
||||||
|
if (X[ip] != ZERO)
|
||||||
|
break;
|
||||||
|
|
||||||
|
k = (__glibc_unlikely (p < 3)) ? p + p : p + 3;
|
||||||
|
|
||||||
|
while (k > 2 * ip + 1)
|
||||||
|
Y[k--] = ZERO;
|
||||||
|
|
||||||
|
yk = ZERO;
|
||||||
|
|
||||||
|
while (k > p)
|
||||||
|
{
|
||||||
|
double yk2 = 0.0;
|
||||||
|
long lim = k / 2;
|
||||||
|
|
||||||
|
if (k % 2 == 0)
|
||||||
|
{
|
||||||
|
yk += X[lim] * X[lim];
|
||||||
|
lim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = k - p, j = p; i <= lim; i++, j--)
|
||||||
|
yk2 += X[i] * X[j];
|
||||||
|
|
||||||
|
yk += 2.0 * yk2;
|
||||||
|
|
||||||
|
u = (yk + CUTTER) - CUTTER;
|
||||||
|
if (u > yk)
|
||||||
|
u -= RADIX;
|
||||||
|
Y[k--] = yk - u;
|
||||||
|
yk = u * RADIXI;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (k > 1)
|
||||||
|
{
|
||||||
|
double yk2 = 0.0;
|
||||||
|
long lim = k / 2;
|
||||||
|
|
||||||
|
if (k % 2 == 0)
|
||||||
|
{
|
||||||
|
yk += X[lim] * X[lim];
|
||||||
|
lim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 1, j = k - 1; i <= lim; i++, j--)
|
||||||
|
yk2 += X[i] * X[j];
|
||||||
|
|
||||||
|
yk += 2.0 * yk2;
|
||||||
|
|
||||||
|
u = (yk + CUTTER) - CUTTER;
|
||||||
|
if (u > yk)
|
||||||
|
u -= RADIX;
|
||||||
|
Y[k--] = yk - u;
|
||||||
|
yk = u * RADIXI;
|
||||||
|
}
|
||||||
|
Y[k] = yk;
|
||||||
|
|
||||||
|
/* Squares are always positive. */
|
||||||
|
Y[0] = 1.0;
|
||||||
|
|
||||||
|
EY = 2 * EX;
|
||||||
|
/* Is there a carry beyond the most significant digit? */
|
||||||
|
if (__glibc_unlikely (Y[1] == ZERO))
|
||||||
|
{
|
||||||
|
for (i = 1; i <= p; i++)
|
||||||
|
Y[i] = Y[i + 1];
|
||||||
|
EY--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Invert *X and store in *Y. Relative error bound:
|
/* Invert *X and store in *Y. Relative error bound:
|
||||||
- For P = 2: 1.001 * R ^ (1 - P)
|
- For P = 2: 1.001 * R ^ (1 - P)
|
||||||
- For P = 3: 1.063 * R ^ (1 - P)
|
- For P = 3: 1.063 * R ^ (1 - P)
|
||||||
|
@@ -115,6 +115,7 @@ void __dbl_mp (double, mp_no *, int);
|
|||||||
void __add (const mp_no *, const mp_no *, mp_no *, int);
|
void __add (const mp_no *, const mp_no *, mp_no *, int);
|
||||||
void __sub (const mp_no *, const mp_no *, mp_no *, int);
|
void __sub (const mp_no *, const mp_no *, mp_no *, int);
|
||||||
void __mul (const mp_no *, const mp_no *, mp_no *, int);
|
void __mul (const mp_no *, const mp_no *, mp_no *, int);
|
||||||
|
void __sqr (const mp_no *, mp_no *, int);
|
||||||
void __dvd (const mp_no *, const mp_no *, mp_no *, int);
|
void __dvd (const mp_no *, const mp_no *, mp_no *, int);
|
||||||
|
|
||||||
extern void __mpatan (mp_no *, mp_no *, int);
|
extern void __mpatan (mp_no *, mp_no *, int);
|
||||||
|
@@ -145,14 +145,14 @@ __mpexp (mp_no *x, mp_no *y, int p)
|
|||||||
/* Raise polynomial value to the power of 2**m. Put result in y. */
|
/* Raise polynomial value to the power of 2**m. Put result in y. */
|
||||||
for (k = 0, j = 0; k < m;)
|
for (k = 0, j = 0; k < m;)
|
||||||
{
|
{
|
||||||
__mul (&mpt2, &mpt2, &mpt1, p);
|
__sqr (&mpt2, &mpt1, p);
|
||||||
k++;
|
k++;
|
||||||
if (k == m)
|
if (k == m)
|
||||||
{
|
{
|
||||||
j = 1;
|
j = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
__mul (&mpt1, &mpt1, &mpt2, p);
|
__sqr (&mpt1, &mpt2, p);
|
||||||
k++;
|
k++;
|
||||||
}
|
}
|
||||||
if (j)
|
if (j)
|
||||||
|
@@ -687,6 +687,106 @@ __mul (const mp_no *x, const mp_no *y, mp_no *z, int p)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Square *X and store result in *Y. X and Y may not overlap. 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. This is a faster special case of
|
||||||
|
multiplication. */
|
||||||
|
void
|
||||||
|
__sqr (const mp_no *x, mp_no *y, int p)
|
||||||
|
{
|
||||||
|
long i, j, k, ip;
|
||||||
|
double u, yk;
|
||||||
|
|
||||||
|
/* Is z=0? */
|
||||||
|
if (__glibc_unlikely (X[0] == ZERO))
|
||||||
|
{
|
||||||
|
Y[0] = ZERO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need not iterate through all X's since it's pointless to
|
||||||
|
multiply zeroes. */
|
||||||
|
for (ip = p; ip > 0; ip--)
|
||||||
|
if (X[ip] != ZERO)
|
||||||
|
break;
|
||||||
|
|
||||||
|
k = (__glibc_unlikely (p < 3)) ? p + p : p + 3;
|
||||||
|
|
||||||
|
while (k > 2 * ip + 1)
|
||||||
|
Y[k--] = ZERO;
|
||||||
|
|
||||||
|
yk = ZERO;
|
||||||
|
|
||||||
|
while (k > p)
|
||||||
|
{
|
||||||
|
double yk2 = 0.0;
|
||||||
|
long lim = k / 2;
|
||||||
|
|
||||||
|
if (k % 2 == 0)
|
||||||
|
{
|
||||||
|
yk += X[lim] * X[lim];
|
||||||
|
lim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In __mul, this loop (and the one within the next while loop) run
|
||||||
|
between a range to calculate the mantissa as follows:
|
||||||
|
|
||||||
|
Z[k] = X[k] * Y[n] + X[k+1] * Y[n-1] ... + X[n-1] * Y[k+1]
|
||||||
|
+ X[n] * Y[k]
|
||||||
|
|
||||||
|
For X == Y, we can get away with summing halfway and doubling the
|
||||||
|
result. For cases where the range size is even, the mid-point needs
|
||||||
|
to be added separately (above). */
|
||||||
|
for (i = k - p, j = p; i <= lim; i++, j--)
|
||||||
|
yk2 += X[i] * X[j];
|
||||||
|
|
||||||
|
yk += 2.0 * yk2;
|
||||||
|
|
||||||
|
u = (yk + CUTTER) - CUTTER;
|
||||||
|
if (u > yk)
|
||||||
|
u -= RADIX;
|
||||||
|
Y[k--] = yk - u;
|
||||||
|
yk = u * RADIXI;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (k > 1)
|
||||||
|
{
|
||||||
|
double yk2 = 0.0;
|
||||||
|
long lim = k / 2;
|
||||||
|
|
||||||
|
if (k % 2 == 0)
|
||||||
|
{
|
||||||
|
yk += X[lim] * X[lim];
|
||||||
|
lim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Likewise for this loop. */
|
||||||
|
for (i = 1, j = k - 1; i <= lim; i++, j--)
|
||||||
|
yk2 += X[i] * X[j];
|
||||||
|
|
||||||
|
yk += 2.0 * yk2;
|
||||||
|
|
||||||
|
u = (yk + CUTTER) - CUTTER;
|
||||||
|
if (u > yk)
|
||||||
|
u -= RADIX;
|
||||||
|
Y[k--] = yk - u;
|
||||||
|
yk = u * RADIXI;
|
||||||
|
}
|
||||||
|
Y[k] = yk;
|
||||||
|
|
||||||
|
/* Squares are always positive. */
|
||||||
|
Y[0] = 1.0;
|
||||||
|
|
||||||
|
EY = 2 * EX;
|
||||||
|
/* Is there a carry beyond the most significant digit? */
|
||||||
|
if (__glibc_unlikely (Y[1] == ZERO))
|
||||||
|
{
|
||||||
|
for (i = 1; i <= p; i++)
|
||||||
|
Y[i] = Y[i + 1];
|
||||||
|
EY--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Invert *X and store in *Y. Relative error bound:
|
/* Invert *X and store in *Y. Relative error bound:
|
||||||
- For P = 2: 1.001 * R ^ (1 - P)
|
- For P = 2: 1.001 * R ^ (1 - P)
|
||||||
- For P = 3: 1.063 * R ^ (1 - P)
|
- For P = 3: 1.063 * R ^ (1 - P)
|
||||||
|
@@ -687,6 +687,106 @@ __mul (const mp_no *x, const mp_no *y, mp_no *z, int p)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Square *X and store result in *Y. X and Y may not overlap. 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. This is a faster special case of
|
||||||
|
multiplication. */
|
||||||
|
void
|
||||||
|
__sqr (const mp_no *x, mp_no *y, int p)
|
||||||
|
{
|
||||||
|
long i, j, k, ip;
|
||||||
|
double u, yk;
|
||||||
|
|
||||||
|
/* Is z=0? */
|
||||||
|
if (__glibc_unlikely (X[0] == ZERO))
|
||||||
|
{
|
||||||
|
Y[0] = ZERO;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We need not iterate through all X's since it's pointless to
|
||||||
|
multiply zeroes. */
|
||||||
|
for (ip = p; ip > 0; ip--)
|
||||||
|
if (X[ip] != ZERO)
|
||||||
|
break;
|
||||||
|
|
||||||
|
k = (__glibc_unlikely (p < 3)) ? p + p : p + 3;
|
||||||
|
|
||||||
|
while (k > 2 * ip + 1)
|
||||||
|
Y[k--] = ZERO;
|
||||||
|
|
||||||
|
yk = ZERO;
|
||||||
|
|
||||||
|
while (k > p)
|
||||||
|
{
|
||||||
|
double yk2 = 0.0;
|
||||||
|
long lim = k / 2;
|
||||||
|
|
||||||
|
if (k % 2 == 0)
|
||||||
|
{
|
||||||
|
yk += X[lim] * X[lim];
|
||||||
|
lim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In __mul, this loop (and the one within the next while loop) run
|
||||||
|
between a range to calculate the mantissa as follows:
|
||||||
|
|
||||||
|
Z[k] = X[k] * Y[n] + X[k+1] * Y[n-1] ... + X[n-1] * Y[k+1]
|
||||||
|
+ X[n] * Y[k]
|
||||||
|
|
||||||
|
For X == Y, we can get away with summing halfway and doubling the
|
||||||
|
result. For cases where the range size is even, the mid-point needs
|
||||||
|
to be added separately (above). */
|
||||||
|
for (i = k - p, j = p; i <= lim; i++, j--)
|
||||||
|
yk2 += X[i] * X[j];
|
||||||
|
|
||||||
|
yk += 2.0 * yk2;
|
||||||
|
|
||||||
|
u = (yk + CUTTER) - CUTTER;
|
||||||
|
if (u > yk)
|
||||||
|
u -= RADIX;
|
||||||
|
Y[k--] = yk - u;
|
||||||
|
yk = u * RADIXI;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (k > 1)
|
||||||
|
{
|
||||||
|
double yk2 = 0.0;
|
||||||
|
long lim = k / 2;
|
||||||
|
|
||||||
|
if (k % 2 == 0)
|
||||||
|
{
|
||||||
|
yk += X[lim] * X[lim];
|
||||||
|
lim--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Likewise for this loop. */
|
||||||
|
for (i = 1, j = k - 1; i <= lim; i++, j--)
|
||||||
|
yk2 += X[i] * X[j];
|
||||||
|
|
||||||
|
yk += 2.0 * yk2;
|
||||||
|
|
||||||
|
u = (yk + CUTTER) - CUTTER;
|
||||||
|
if (u > yk)
|
||||||
|
u -= RADIX;
|
||||||
|
Y[k--] = yk - u;
|
||||||
|
yk = u * RADIXI;
|
||||||
|
}
|
||||||
|
Y[k] = yk;
|
||||||
|
|
||||||
|
/* Squares are always positive. */
|
||||||
|
Y[0] = 1.0;
|
||||||
|
|
||||||
|
EY = 2 * EX;
|
||||||
|
/* Is there a carry beyond the most significant digit? */
|
||||||
|
if (__glibc_unlikely (Y[1] == ZERO))
|
||||||
|
{
|
||||||
|
for (i = 1; i <= p; i++)
|
||||||
|
Y[i] = Y[i + 1];
|
||||||
|
EY--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Invert *X and store in *Y. Relative error bound:
|
/* Invert *X and store in *Y. Relative error bound:
|
||||||
- For P = 2: 1.001 * R ^ (1 - P)
|
- For P = 2: 1.001 * R ^ (1 - P)
|
||||||
- For P = 3: 1.063 * R ^ (1 - P)
|
- For P = 3: 1.063 * R ^ (1 - P)
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#define __add __add_avx
|
#define __add __add_avx
|
||||||
#define __mul __mul_avx
|
#define __mul __mul_avx
|
||||||
|
#define __sqr __sqr_avx
|
||||||
#define __sub __sub_avx
|
#define __sub __sub_avx
|
||||||
#define __dbl_mp __dbl_mp_avx
|
#define __dbl_mp __dbl_mp_avx
|
||||||
#define __dvd __dvd_avx
|
#define __dvd __dvd_avx
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
#define __add __add_fma4
|
#define __add __add_fma4
|
||||||
#define __mul __mul_fma4
|
#define __mul __mul_fma4
|
||||||
|
#define __sqr __sqr_fma4
|
||||||
#define __sub __sub_fma4
|
#define __sub __sub_fma4
|
||||||
#define __dbl_mp __dbl_mp_fma4
|
#define __dbl_mp __dbl_mp_fma4
|
||||||
#define __dvd __dvd_fma4
|
#define __dvd __dvd_fma4
|
||||||
|
Reference in New Issue
Block a user