Commit 1eba0867 by Jakub Jelinek Committed by Jakub Jelinek

re PR libquadmath/65757 (gfortran gives incorrect result for anint with real*16 argument)

	PR libquadmath/65757
	* quadmath-imp.h (math_opt_barrier, math_force_eval,
	math_narrow_eval, math_check_force_underflow,
	math_check_force_underflow_nonneg): Define.
	* math/ceilq.c: Backport changes from upstream glibc
	between 2012-11-01 and 2017-07-13.
	* math/remquoq.c: Likewise.
	* math/expq.c: Likewise.
	* math/llroundq.c: Likewise.
	* math/logq.c: Likewise.
	* math/atanq.c: Likewise.
	* math/nearbyintq.c: Likewise.
	* math/scalblnq.c: Likewise.
	* math/finiteq.c: Likewise.
	* math/atanhq.c: Likewise.
	* math/expm1q.c: Likewise.
	* math/sinhq.c: Likewise.
	* math/log10q.c: Likewise.
	* math/rintq.c: Likewise.
	* math/roundq.c: Likewise.
	* math/fmaq.c: Likewise.
	* math/erfq.c: Likewise.
	* math/log2q.c: Likewise.
	* math/lroundq.c: Likewise.
	* math/j1q.c: Likewise.
	* math/scalbnq.c: Likewise.
	* math/truncq.c: Likewise.
	* math/frexpq.c: Likewise.
	* math/sincosq.c: Likewise.
	* math/tanhq.c: Likewise.
	* math/asinq.c: Likewise.
	* math/coshq.c: Likewise.
	* math/j0q.c: Likewise.
	* math/asinhq.c: Likewise.
	* math/floorq.c: Likewise.
	* math/sinq_kernel.c: Likewise.
	* math/powq.c: Likewise.
	* math/hypotq.c: Likewise.
	* math/sincos_table.c: Likewise.
	* math/rem_pio2q.c: Likewise.
	* math/nextafterq.c: Likewise.
	* math/log1pq.c: Likewise.
	* math/sincosq_kernel.c: Likewise.
	* math/tanq.c: Likewise.
	* math/acosq.c: Likewise.
	* math/lrintq.c: Likewise.
	* math/llrintq.c: Likewise.

From-SVN: r250343
parent 564e405c
2017-07-19 Jakub Jelinek <jakub@redhat.com>
PR libquadmath/65757
* quadmath-imp.h (math_opt_barrier, math_force_eval,
math_narrow_eval, math_check_force_underflow,
math_check_force_underflow_nonneg): Define.
* math/ceilq.c: Backport changes from upstream glibc
between 2012-11-01 and 2017-07-13.
* math/remquoq.c: Likewise.
* math/expq.c: Likewise.
* math/llroundq.c: Likewise.
* math/logq.c: Likewise.
* math/atanq.c: Likewise.
* math/nearbyintq.c: Likewise.
* math/scalblnq.c: Likewise.
* math/finiteq.c: Likewise.
* math/atanhq.c: Likewise.
* math/expm1q.c: Likewise.
* math/sinhq.c: Likewise.
* math/log10q.c: Likewise.
* math/rintq.c: Likewise.
* math/roundq.c: Likewise.
* math/fmaq.c: Likewise.
* math/erfq.c: Likewise.
* math/log2q.c: Likewise.
* math/lroundq.c: Likewise.
* math/j1q.c: Likewise.
* math/scalbnq.c: Likewise.
* math/truncq.c: Likewise.
* math/frexpq.c: Likewise.
* math/sincosq.c: Likewise.
* math/tanhq.c: Likewise.
* math/asinq.c: Likewise.
* math/coshq.c: Likewise.
* math/j0q.c: Likewise.
* math/asinhq.c: Likewise.
* math/floorq.c: Likewise.
* math/sinq_kernel.c: Likewise.
* math/powq.c: Likewise.
* math/hypotq.c: Likewise.
* math/sincos_table.c: Likewise.
* math/rem_pio2q.c: Likewise.
* math/nextafterq.c: Likewise.
* math/log1pq.c: Likewise.
* math/sincosq_kernel.c: Likewise.
* math/tanq.c: Likewise.
* math/acosq.c: Likewise.
* math/lrintq.c: Likewise.
* math/llrintq.c: Likewise.
2017-02-09 Gerald Pfeifer <gerald@pfeifer.com> 2017-02-09 Gerald Pfeifer <gerald@pfeifer.com>
* configure.ac (ACX_BUGURL): Update. * configure.ac (ACX_BUGURL): Update.
......
...@@ -172,7 +172,7 @@ acosq (__float128 x) ...@@ -172,7 +172,7 @@ acosq (__float128 x)
} }
else if (ix < 0x3ffe0000) /* |x| < 0.5 */ else if (ix < 0x3ffe0000) /* |x| < 0.5 */
{ {
if (ix < 0x3fc60000) /* |x| < 2**-57 */ if (ix < 0x3f8e0000) /* |x| < 2**-113 */
return pio2_hi + pio2_lo; return pio2_hi + pio2_lo;
if (ix < 0x3ffde000) /* |x| < .4375 */ if (ix < 0x3ffde000) /* |x| < .4375 */
{ {
......
...@@ -46,6 +46,7 @@ asinhq (__float128 x) ...@@ -46,6 +46,7 @@ asinhq (__float128 x)
return x + x; /* x is inf or NaN */ return x + x; /* x is inf or NaN */
if (ix < 0x3fc70000) if (ix < 0x3fc70000)
{ /* |x| < 2^ -56 */ { /* |x| < 2^ -56 */
math_check_force_underflow (x);
if (huge + x > one) if (huge + x > one)
return x; /* return x inexact except 0 */ return x; /* return x inexact except 0 */
} }
......
...@@ -151,8 +151,10 @@ asinq (__float128 x) ...@@ -151,8 +151,10 @@ asinq (__float128 x)
{ {
if (ix < 0x3fc60000) /* |x| < 2**-57 */ if (ix < 0x3fc60000) /* |x| < 2**-57 */
{ {
if (huge + x > one) math_check_force_underflow (x);
return x; /* return x with inexact if x!=0 */ __float128 force_inexact = huge + x;
math_force_eval (force_inexact);
return x; /* return x with inexact if x!=0 */
} }
else else
{ {
......
...@@ -55,7 +55,11 @@ atanhq (__float128 x) ...@@ -55,7 +55,11 @@ atanhq (__float128 x)
else else
return (x-x)/(x-x); return (x-x)/(x-x);
} }
if(ix<0x3fc60000 && (huge+x)>zero) return x; /* x < 2^-57 */ if(ix<0x3fc60000 && (huge+x)>zero) /* x < 2^-57 */
{
math_check_force_underflow (x);
return x;
}
if(ix<0x3ffe0000) { /* x < 0.5 */ if(ix<0x3ffe0000) { /* x < 0.5 */
t = u.value+u.value; t = u.value+u.value;
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
* *
*/ */
/* Copyright 2001 by Stephen L. Moshier <moshier@na-net.ornl.gov> /* Copyright 2001 by Stephen L. Moshier <moshier@na-net.ornl.gov>
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -167,7 +167,7 @@ static const __float128 ...@@ -167,7 +167,7 @@ static const __float128
q4 = 2.173623741810414221251136181221172551416E1Q; q4 = 2.173623741810414221251136181221172551416E1Q;
/* q5 = 1.000000000000000000000000000000000000000E0 */ /* q5 = 1.000000000000000000000000000000000000000E0 */
static const long double huge = 1.0e4930Q; static const __float128 huge = 1.0e4930Q;
__float128 __float128
atanq (__float128 x) atanq (__float128 x)
...@@ -200,6 +200,7 @@ atanq (__float128 x) ...@@ -200,6 +200,7 @@ atanq (__float128 x)
if (k <= 0x3fc50000) /* |x| < 2**-58 */ if (k <= 0x3fc50000) /* |x| < 2**-58 */
{ {
math_check_force_underflow (x);
/* Raise inexact. */ /* Raise inexact. */
if (huge + x > 0.0) if (huge + x > 0.0)
return x; return x;
......
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#include "quadmath-imp.h" #include "quadmath-imp.h"
static const __float128 huge = 1.0e4930Q;
__float128 __float128
ceilq (__float128 x) ceilq (__float128 x)
{ {
...@@ -25,18 +23,15 @@ ceilq (__float128 x) ...@@ -25,18 +23,15 @@ ceilq (__float128 x)
GET_FLT128_WORDS64(i0,i1,x); GET_FLT128_WORDS64(i0,i1,x);
j0 = ((i0>>48)&0x7fff)-0x3fff; j0 = ((i0>>48)&0x7fff)-0x3fff;
if(j0<48) { if(j0<48) {
if(j0<0) { /* raise inexact if x != 0 */ if(j0<0) {
if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ /* return 0*sign(x) if |x|<1 */
if(i0<0) {i0=0x8000000000000000ULL;i1=0;} if(i0<0) {i0=0x8000000000000000ULL;i1=0;}
else if((i0|i1)!=0) { i0=0x3fff000000000000ULL;i1=0;} else if((i0|i1)!=0) { i0=0x3fff000000000000ULL;i1=0;}
}
} else { } else {
i = (0x0000ffffffffffffULL)>>j0; i = (0x0000ffffffffffffULL)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */ if(((i0&i)|i1)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */ if(i0>0) i0 += (0x0001000000000000LL)>>j0;
if(i0>0) i0 += (0x0001000000000000LL)>>j0; i0 &= (~i); i1=0;
i0 &= (~i); i1=0;
}
} }
} else if (j0>111) { } else if (j0>111) {
if(j0==0x4000) return x+x; /* inf or NaN */ if(j0==0x4000) return x+x; /* inf or NaN */
...@@ -44,17 +39,15 @@ ceilq (__float128 x) ...@@ -44,17 +39,15 @@ ceilq (__float128 x)
} else { } else {
i = -1ULL>>(j0-48); i = -1ULL>>(j0-48);
if((i1&i)==0) return x; /* x is integral */ if((i1&i)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */ if(i0>0) {
if(i0>0) { if(j0==48) i0+=1;
if(j0==48) i0+=1; else {
else { j = i1+(1LL<<(112-j0));
j = i1+(1LL<<(112-j0)); if(j<i1) i0 +=1 ; /* got a carry */
if(j<i1) i0 +=1 ; /* got a carry */ i1=j;
i1=j;
}
} }
i1 &= (~i);
} }
i1 &= (~i);
} }
SET_FLT128_WORDS64(x,i0,i1); SET_FLT128_WORDS64(x,i0,i1);
return x; return x;
......
...@@ -76,10 +76,10 @@ coshq (__float128 x) ...@@ -76,10 +76,10 @@ coshq (__float128 x)
/* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expq(|x|)) */ /* |x| in [0,0.5*ln2], return 1+expm1l(|x|)^2/(2*expq(|x|)) */
if (ex < 0x3ffd62e4) /* 0.3465728759765625 */ if (ex < 0x3ffd62e4) /* 0.3465728759765625 */
{ {
if (ex < 0x3fb80000) /* |x| < 2^-116 */
return one; /* cosh(tiny) = 1 */
t = expm1q (u.value); t = expm1q (u.value);
w = one + t; w = one + t;
if (ex < 0x3fb80000) /* |x| < 2^-116 */
return w; /* cosh(tiny) = 1 */
return one + (t * t) / (w + w); return one + (t * t) / (w + w);
} }
......
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
/* Modifications and expansions for 128-bit long double are /* Modifications and expansions for 128-bit long double are
Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov> Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov>
and are incorporated herein by permission of the author. The author and are incorporated herein by permission of the author. The author
reserves the right to distribute this material elsewhere under different reserves the right to distribute this material elsewhere under different
copying permissions. These modifications are distributed here under copying permissions. These modifications are distributed here under
the following terms: the following terms:
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
...@@ -96,6 +96,7 @@ ...@@ -96,6 +96,7 @@
* erfc/erf(NaN) is NaN * erfc/erf(NaN) is NaN
*/ */
#include <errno.h>
#include "quadmath-imp.h" #include "quadmath-imp.h"
...@@ -142,13 +143,10 @@ deval (__float128 x, const __float128 *p, int n) ...@@ -142,13 +143,10 @@ deval (__float128 x, const __float128 *p, int n)
static const __float128 static const __float128
tiny = 1e-4931Q, tiny = 1e-4931Q,
half = 0.5Q,
one = 1.0Q, one = 1.0Q,
two = 2.0Q, two = 2.0Q,
/* 2/sqrt(pi) - 1 */ /* 2/sqrt(pi) - 1 */
efx = 1.2837916709551257389615890312154517168810E-1Q, efx = 1.2837916709551257389615890312154517168810E-1Q;
/* 8 * (2/sqrt(pi) - 1) */
efx8 = 1.0270333367641005911692712249723613735048E0Q;
/* erf(x) = x + x R(x^2) /* erf(x) = x + x R(x^2)
...@@ -773,6 +771,8 @@ erfq (__float128 x) ...@@ -773,6 +771,8 @@ erfq (__float128 x)
if (ix >= 0x3fff0000) /* |x| >= 1.0 */ if (ix >= 0x3fff0000) /* |x| >= 1.0 */
{ {
if (ix >= 0x40030000 && sign > 0)
return one; /* x >= 16, avoid spurious underflow from erfc. */
y = erfcq (x); y = erfcq (x);
return (one - y); return (one - y);
/* return (one - erfcq (x)); */ /* return (one - erfcq (x)); */
...@@ -785,7 +785,12 @@ erfq (__float128 x) ...@@ -785,7 +785,12 @@ erfq (__float128 x)
if (ix < 0x3fc60000) /* |x|<2**-57 */ if (ix < 0x3fc60000) /* |x|<2**-57 */
{ {
if (ix < 0x00080000) if (ix < 0x00080000)
return 0.125 * (8.0 * x + efx8 * x); /*avoid underflow */ {
/* Avoid spurious underflow. */
__float128 ret = 0.0625 * (16.0 * x + (16.0 * efx) * x);
math_check_force_underflow (ret);
return ret;
}
return x + efx * x; return x + efx * x;
} }
y = a + a * neval (z, TN1, NTN1) / deval (z, TD1, NTD1); y = a + a * neval (z, TN1, NTN1) / deval (z, TD1, NTD1);
...@@ -867,7 +872,7 @@ erfcq (__float128 x) ...@@ -867,7 +872,7 @@ erfcq (__float128 x)
y = C19b + z * neval (z, RNr19, NRNr19) / deval (z, RDr19, NRDr19); y = C19b + z * neval (z, RNr19, NRNr19) / deval (z, RDr19, NRDr19);
y += C19a; y += C19a;
break; break;
case 9: default: /* i == 9. */
z = x - 1.125Q; z = x - 1.125Q;
y = C20b + z * neval (z, RNr20, NRNr20) / deval (z, RDr20, NRDr20); y = C20b + z * neval (z, RNr20, NRNr20) / deval (z, RDr20, NRDr20);
y += C20a; y += C20a;
...@@ -921,14 +926,22 @@ erfcq (__float128 x) ...@@ -921,14 +926,22 @@ erfcq (__float128 x)
z = u.value; z = u.value;
r = expq (-z * z - 0.5625) * expq ((z - x) * (z + x) + p); r = expq (-z * z - 0.5625) * expq ((z - x) * (z + x) + p);
if ((sign & 0x80000000) == 0) if ((sign & 0x80000000) == 0)
return r / x; {
__float128 ret = r / x;
if (ret == 0)
errno = ERANGE;
return ret;
}
else else
return two - r / x; return two - r / x;
} }
else else
{ {
if ((sign & 0x80000000) == 0) if ((sign & 0x80000000) == 0)
return tiny * tiny; {
errno = ERANGE;
return tiny * tiny;
}
else else
return two - tiny; return two - tiny;
} }
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
* *
*/ */
/* Copyright 2001 by Stephen L. Moshier /* Copyright 2001 by Stephen L. Moshier
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -82,8 +82,6 @@ static const __float128 ...@@ -82,8 +82,6 @@ static const __float128
C1 = 6.93145751953125E-1Q, C1 = 6.93145751953125E-1Q,
C2 = 1.428606820309417232121458176568075500134E-6Q, C2 = 1.428606820309417232121458176568075500134E-6Q,
/* ln (2^16384 * (1 - 2^-113)) */
maxlog = 1.1356523406294143949491931077970764891253E4Q,
/* ln 2^-114 */ /* ln 2^-114 */
minarg = -7.9018778583833765273564461846232128760607E1Q; minarg = -7.9018778583833765273564461846232128760607E1Q;
...@@ -108,33 +106,30 @@ expm1q (__float128 x) ...@@ -108,33 +106,30 @@ expm1q (__float128 x)
} }
if (ix >= 0x7fff0000) if (ix >= 0x7fff0000)
{ {
/* Infinity. */ /* Infinity (which must be negative infinity). */
if (((ix & 0xffff) | u.words32.w1 | u.words32.w2 | u.words32.w3) == 0) if (((ix & 0xffff) | u.words32.w1 | u.words32.w2 | u.words32.w3) == 0)
{ return -1.0Q;
if (sign) /* NaN. Invalid exception if signaling. */
return -1.0Q; return x + x;
else
return x;
}
/* NaN. No invalid exception. */
return x;
} }
/* expm1(+- 0) = +- 0. */ /* expm1(+- 0) = +- 0. */
if ((ix == 0) && (u.words32.w1 | u.words32.w2 | u.words32.w3) == 0) if ((ix == 0) && (u.words32.w1 | u.words32.w2 | u.words32.w3) == 0)
return x; return x;
/* Overflow. */
if (x > maxlog)
{
errno = ERANGE;
return (HUGE_VALQ * HUGE_VALQ);
}
/* Minimum value. */ /* Minimum value. */
if (x < minarg) if (x < minarg)
return (4.0/HUGE_VALQ - 1.0Q); return (4.0/HUGE_VALQ - 1.0Q);
/* Avoid internal underflow when result does not underflow, while
ensuring underflow (without returning a zero of the wrong sign)
when the result does underflow. */
if (fabsq (x) < 0x1p-113Q)
{
math_check_force_underflow (x);
return x;
}
/* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */ /* Express x = ln 2 (k + remainder), remainder not exceeding 1/2. */
xx = C1 + C2; /* ln 2. */ xx = C1 + C2; /* ln 2. */
px = floorq (0.5 + x / xx); px = floorq (0.5 + x / xx);
......
/* Quad-precision floating point e^x. /* Quad-precision floating point e^x.
Copyright (C) 1999 Free Software Foundation, Inc. Copyright (C) 1999-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jj@ultra.linux.cz> Contributed by Jakub Jelinek <jj@ultra.linux.cz>
Partly based on double-precision code Partly based on double-precision code
...@@ -1075,7 +1075,7 @@ static const __float128 C[] = { ...@@ -1075,7 +1075,7 @@ static const __float128 C[] = {
#define TWO15 C[11] #define TWO15 C[11]
32768.0Q, 32768.0Q,
/* Chebyshev polynom coeficients for (exp(x)-1)/x */ /* Chebyshev polynom coefficients for (exp(x)-1)/x */
#define P1 C[12] #define P1 C[12]
#define P2 C[13] #define P2 C[13]
#define P3 C[14] #define P3 C[14]
...@@ -1142,7 +1142,7 @@ expq (__float128 x) ...@@ -1142,7 +1142,7 @@ expq (__float128 x)
* __expq_table[T_EXPL_RES2 + tval2]; * __expq_table[T_EXPL_RES2 + tval2];
n_i = (int)n; n_i = (int)n;
/* 'unsafe' is 1 iff n_1 != 0. */ /* 'unsafe' is 1 iff n_1 != 0. */
unsafe = abs(n_i) >= -FLT128_MIN_EXP - 1; unsafe = abs(n_i) >= 15000;
ex2_u.ieee.exponent += n_i >> unsafe; ex2_u.ieee.exponent += n_i >> unsafe;
/* Compute scale = 2^n_1. */ /* Compute scale = 2^n_1. */
...@@ -1179,7 +1179,7 @@ expq (__float128 x) ...@@ -1179,7 +1179,7 @@ expq (__float128 x)
ex3_u.d = (result - ex2_u.d) - x22 * ex2_u.d; ex3_u.d = (result - ex2_u.d) - x22 * ex2_u.d;
ex2_u.d = result; ex2_u.d = result;
ex3_u.ieee.exponent += LDBL_MANT_DIG + 15 + IEEE854_LONG_DOUBLE_BIAS ex3_u.ieee.exponent += LDBL_MANT_DIG + 15 + IEEE854_LONG_DOUBLE_BIAS
- ex2_u.ieee.exponent; - ex2_u.ieee.exponent;
n_i = abs (ex3_u.d); n_i = abs (ex3_u.d);
n_i = (n_i + 1) / 2; n_i = (n_i + 1) / 2;
#ifdef USE_FENV_H #ifdef USE_FENV_H
...@@ -1196,7 +1196,11 @@ expq (__float128 x) ...@@ -1196,7 +1196,11 @@ expq (__float128 x)
if (!unsafe) if (!unsafe)
return result; return result;
else else
return result * scale_u.value; {
result *= scale_u.value;
math_check_force_underflow_nonneg (result);
return result;
}
} }
/* Exceptional cases: */ /* Exceptional cases: */
else if (__builtin_isless (x, himark)) else if (__builtin_isless (x, himark))
......
...@@ -25,6 +25,6 @@ finiteq (const __float128 x) ...@@ -25,6 +25,6 @@ finiteq (const __float128 x)
{ {
int64_t hx; int64_t hx;
GET_FLT128_MSW64(hx,x); GET_FLT128_MSW64(hx,x);
return (int)((uint64_t)((hx&0x7fffffffffffffffLL) return (int)((uint64_t)((hx&0x7fff000000000000LL)
-0x7fff000000000000LL)>>63); -0x7fff000000000000LL)>>63);
} }
...@@ -15,8 +15,6 @@ ...@@ -15,8 +15,6 @@
#include "quadmath-imp.h" #include "quadmath-imp.h"
static const __float128 huge = 1.0e4930Q;
__float128 __float128
floorq (__float128 x) floorq (__float128 x)
{ {
...@@ -25,19 +23,16 @@ floorq (__float128 x) ...@@ -25,19 +23,16 @@ floorq (__float128 x)
GET_FLT128_WORDS64(i0,i1,x); GET_FLT128_WORDS64(i0,i1,x);
j0 = ((i0>>48)&0x7fff)-0x3fff; j0 = ((i0>>48)&0x7fff)-0x3fff;
if(j0<48) { if(j0<48) {
if(j0<0) { /* raise inexact if x != 0 */ if(j0<0) {
if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */ /* return 0*sign(x) if |x|<1 */
if(i0>=0) {i0=i1=0;} if(i0>=0) {i0=i1=0;}
else if(((i0&0x7fffffffffffffffLL)|i1)!=0) else if(((i0&0x7fffffffffffffffLL)|i1)!=0)
{ i0=0xbfff000000000000ULL;i1=0;} { i0=0xbfff000000000000ULL;i1=0;}
}
} else { } else {
i = (0x0000ffffffffffffULL)>>j0; i = (0x0000ffffffffffffULL)>>j0;
if(((i0&i)|i1)==0) return x; /* x is integral */ if(((i0&i)|i1)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */ if(i0<0) i0 += (0x0001000000000000LL)>>j0;
if(i0<0) i0 += (0x0001000000000000LL)>>j0; i0 &= (~i); i1=0;
i0 &= (~i); i1=0;
}
} }
} else if (j0>111) { } else if (j0>111) {
if(j0==0x4000) return x+x; /* inf or NaN */ if(j0==0x4000) return x+x; /* inf or NaN */
...@@ -45,17 +40,15 @@ floorq (__float128 x) ...@@ -45,17 +40,15 @@ floorq (__float128 x)
} else { } else {
i = -1ULL>>(j0-48); i = -1ULL>>(j0-48);
if((i1&i)==0) return x; /* x is integral */ if((i1&i)==0) return x; /* x is integral */
if(huge+x>0.0) { /* raise inexact flag */ if(i0<0) {
if(i0<0) { if(j0==48) i0+=1;
if(j0==48) i0+=1; else {
else { j = i1+(1LL<<(112-j0));
j = i1+(1LL<<(112-j0)); if(j<i1) i0 +=1 ; /* got a carry */
if(j<i1) i0 +=1 ; /* got a carry */ i1=j;
i1=j;
}
} }
i1 &= (~i);
} }
i1 &= (~i);
} }
SET_FLT128_WORDS64(x,i0,i1); SET_FLT128_WORDS64(x,i0,i1);
return x; return x;
......
/* Compute x * y + z as ternary operation. /* Compute x * y + z as ternary operation.
Copyright (C) 2010-2012 Free Software Foundation, Inc. Copyright (C) 2010-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2010. Contributed by Jakub Jelinek <jakub@redhat.com>, 2010.
...@@ -97,8 +97,8 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -97,8 +97,8 @@ fmaq (__float128 x, __float128 y, __float128 z)
&& w.ieee.mant_low == 0 && w.ieee.mant_low == 0
&& w.ieee.mant_high == 0))) && w.ieee.mant_high == 0)))
{ {
volatile __float128 force_underflow = x * y; __float128 force_underflow = x * y;
(void) force_underflow; math_force_eval (force_underflow);
} }
return v.value * 0x1p-114Q; return v.value * 0x1p-114Q;
} }
...@@ -161,15 +161,15 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -161,15 +161,15 @@ fmaq (__float128 x, __float128 y, __float128 z)
<= IEEE854_FLOAT128_BIAS + FLT128_MANT_DIG) */ <= IEEE854_FLOAT128_BIAS + FLT128_MANT_DIG) */
{ {
if (u.ieee.exponent > v.ieee.exponent) if (u.ieee.exponent > v.ieee.exponent)
u.ieee.exponent += 2 * FLT128_MANT_DIG; u.ieee.exponent += 2 * FLT128_MANT_DIG + 2;
else else
v.ieee.exponent += 2 * FLT128_MANT_DIG; v.ieee.exponent += 2 * FLT128_MANT_DIG + 2;
if (w.ieee.exponent <= 4 * FLT128_MANT_DIG + 4) if (w.ieee.exponent <= 4 * FLT128_MANT_DIG + 6)
{ {
if (w.ieee.exponent) if (w.ieee.exponent)
w.ieee.exponent += 2 * FLT128_MANT_DIG; w.ieee.exponent += 2 * FLT128_MANT_DIG + 2;
else else
w.value *= 0x1p226Q; w.value *= 0x1p228Q;
adjust = -1; adjust = -1;
} }
/* Otherwise x * y should just affect inexact /* Otherwise x * y should just affect inexact
...@@ -182,7 +182,10 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -182,7 +182,10 @@ fmaq (__float128 x, __float128 y, __float128 z)
/* Ensure correct sign of exact 0 + 0. */ /* Ensure correct sign of exact 0 + 0. */
if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0)) if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0))
return x * y + z; {
x = math_opt_barrier (x);
return x * y + z;
}
#ifdef USE_FENV_H #ifdef USE_FENV_H
fenv_t env; fenv_t env;
...@@ -208,24 +211,24 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -208,24 +211,24 @@ fmaq (__float128 x, __float128 y, __float128 z)
t1 = m1 - t1; t1 = m1 - t1;
t2 = z - t2; t2 = z - t2;
__float128 a2 = t1 + t2; __float128 a2 = t1 + t2;
/* Ensure the arithmetic is not scheduled after feclearexcept call. */
math_force_eval (m2);
math_force_eval (a2);
#ifdef USE_FENV_H #ifdef USE_FENV_H
feclearexcept (FE_INEXACT); feclearexcept (FE_INEXACT);
#endif #endif
/* If the result is an exact zero, ensure it has the correct /* If the result is an exact zero, ensure it has the correct sign. */
sign. */
if (a1 == 0 && m2 == 0) if (a1 == 0 && m2 == 0)
{ {
#ifdef USE_FENV_H #ifdef USE_FENV_H
feupdateenv (&env); feupdateenv (&env);
#endif #endif
/* Ensure that round-to-nearest value of z + m1 is not /* Ensure that round-to-nearest value of z + m1 is not reused. */
reused. */ z = math_opt_barrier (z);
asm volatile ("" : "=m" (z) : "m" (z));
return z + m1; return z + m1;
} }
#ifdef USE_FENV_H #ifdef USE_FENV_H
fesetround (FE_TOWARDZERO); fesetround (FE_TOWARDZERO);
#endif #endif
...@@ -273,19 +276,19 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -273,19 +276,19 @@ fmaq (__float128 x, __float128 y, __float128 z)
/* If a1 + u.value is exact, the only rounding happens during /* If a1 + u.value is exact, the only rounding happens during
scaling down. */ scaling down. */
if (j == 0) if (j == 0)
return v.value * 0x1p-226Q; return v.value * 0x1p-228Q;
/* If result rounded to zero is not subnormal, no double /* If result rounded to zero is not subnormal, no double
rounding will occur. */ rounding will occur. */
if (v.ieee.exponent > 226) if (v.ieee.exponent > 228)
return (a1 + u.value) * 0x1p-226Q; return (a1 + u.value) * 0x1p-228Q;
/* If v.value * 0x1p-226Q with round to zero is a subnormal above /* If v.value * 0x1p-228Q with round to zero is a subnormal above
or equal to FLT128_MIN / 2, then v.value * 0x1p-226Q shifts mantissa or equal to FLT128_MIN / 2, then v.value * 0x1p-228Q shifts mantissa
down just by 1 bit, which means v.ieee.mant_low |= j would down just by 1 bit, which means v.ieee.mant_low |= j would
change the round bit, not sticky or guard bit. change the round bit, not sticky or guard bit.
v.value * 0x1p-226Q never normalizes by shifting up, v.value * 0x1p-228Q never normalizes by shifting up,
so round bit plus sticky bit should be already enough so round bit plus sticky bit should be already enough
for proper rounding. */ for proper rounding. */
if (v.ieee.exponent == 226) if (v.ieee.exponent == 228)
{ {
/* If the exponent would be in the normal range when /* If the exponent would be in the normal range when
rounding to normal precision with unbounded exponent rounding to normal precision with unbounded exponent
...@@ -295,8 +298,8 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -295,8 +298,8 @@ fmaq (__float128 x, __float128 y, __float128 z)
if (TININESS_AFTER_ROUNDING) if (TININESS_AFTER_ROUNDING)
{ {
w.value = a1 + u.value; w.value = a1 + u.value;
if (w.ieee.exponent == 227) if (w.ieee.exponent == 229)
return w.value * 0x1p-226Q; return w.value * 0x1p-228Q;
} }
/* v.ieee.mant_low & 2 is LSB bit of the result before rounding, /* v.ieee.mant_low & 2 is LSB bit of the result before rounding,
v.ieee.mant_low & 1 is the round bit and j is our sticky v.ieee.mant_low & 1 is the round bit and j is our sticky
...@@ -305,11 +308,11 @@ fmaq (__float128 x, __float128 y, __float128 z) ...@@ -305,11 +308,11 @@ fmaq (__float128 x, __float128 y, __float128 z)
w.ieee.mant_low = ((v.ieee.mant_low & 3) << 1) | j; w.ieee.mant_low = ((v.ieee.mant_low & 3) << 1) | j;
w.ieee.negative = v.ieee.negative; w.ieee.negative = v.ieee.negative;
v.ieee.mant_low &= ~3U; v.ieee.mant_low &= ~3U;
v.value *= 0x1p-226Q; v.value *= 0x1p-228Q;
w.value *= 0x1p-2Q; w.value *= 0x1p-2Q;
return v.value + w.value; return v.value + w.value;
} }
v.ieee.mant_low |= j; v.ieee.mant_low |= j;
return v.value * 0x1p-226Q; return v.value * 0x1p-228Q;
} }
} }
...@@ -35,7 +35,7 @@ frexpq (__float128 x, int *eptr) ...@@ -35,7 +35,7 @@ frexpq (__float128 x, int *eptr)
GET_FLT128_WORDS64(hx,lx,x); GET_FLT128_WORDS64(hx,lx,x);
ix = 0x7fffffffffffffffULL&hx; ix = 0x7fffffffffffffffULL&hx;
*eptr = 0; *eptr = 0;
if(ix>=0x7fff000000000000ULL||((ix|lx)==0)) return x; /* 0,inf,nan */ if(ix>=0x7fff000000000000ULL||((ix|lx)==0)) return x + x;/* 0,inf,nan */
if (ix<0x0001000000000000ULL) { /* subnormal */ if (ix<0x0001000000000000ULL) { /* subnormal */
x *= two114; x *= two114;
GET_FLT128_MSW64(hx,x); GET_FLT128_MSW64(hx,x);
......
...@@ -89,6 +89,17 @@ hypotq (__float128 x, __float128 y) ...@@ -89,6 +89,17 @@ hypotq (__float128 x, __float128 y)
b *= t1; b *= t1;
a *= t1; a *= t1;
k -= 16382; k -= 16382;
GET_FLT128_MSW64 (ha, a);
GET_FLT128_MSW64 (hb, b);
if (hb > ha)
{
t1 = a;
a = b;
b = t1;
j = ha;
ha = hb;
hb = j;
}
} else { /* scale a and b by 2^9600 */ } else { /* scale a and b by 2^9600 */
ha += 0x2580000000000000LL; /* a *= 2^9600 */ ha += 0x2580000000000000LL; /* a *= 2^9600 */
hb += 0x2580000000000000LL; /* b *= 2^9600 */ hb += 0x2580000000000000LL; /* b *= 2^9600 */
...@@ -119,6 +130,8 @@ hypotq (__float128 x, __float128 y) ...@@ -119,6 +130,8 @@ hypotq (__float128 x, __float128 y)
t1 = 1.0Q; t1 = 1.0Q;
GET_FLT128_MSW64(high,t1); GET_FLT128_MSW64(high,t1);
SET_FLT128_MSW64(t1,high+(k<<48)); SET_FLT128_MSW64(t1,high+(k<<48));
return t1*w; w *= t1;
math_check_force_underflow_nonneg (w);
return w;
} else return w; } else return w;
} }
...@@ -681,7 +681,7 @@ j0q (__float128 x) ...@@ -681,7 +681,7 @@ j0q (__float128 x)
if (! finiteq (x)) if (! finiteq (x))
{ {
if (x != x) if (x != x)
return x; return x + x;
else else
return 0.0Q; return 0.0Q;
} }
...@@ -691,6 +691,8 @@ j0q (__float128 x) ...@@ -691,6 +691,8 @@ j0q (__float128 x)
xx = fabsq (x); xx = fabsq (x);
if (xx <= 2.0Q) if (xx <= 2.0Q)
{ {
if (xx < 0x1p-57Q)
return 1.0Q;
/* 0 <= x <= 2 */ /* 0 <= x <= 2 */
z = xx * xx; z = xx * xx;
p = z * z * neval (z, J0_2N, NJ0_2N) / deval (z, J0_2D, NJ0_2D); p = z * z * neval (z, J0_2N, NJ0_2N) / deval (z, J0_2D, NJ0_2D);
...@@ -699,6 +701,28 @@ j0q (__float128 x) ...@@ -699,6 +701,28 @@ j0q (__float128 x)
return p; return p;
} }
/* X = x - pi/4
cos(X) = cos(x) cos(pi/4) + sin(x) sin(pi/4)
= 1/sqrt(2) * (cos(x) + sin(x))
sin(X) = sin(x) cos(pi/4) - cos(x) sin(pi/4)
= 1/sqrt(2) * (sin(x) - cos(x))
sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
cf. Fdlibm. */
sincosq (xx, &s, &c);
ss = s - c;
cc = s + c;
if (xx <= FLT128_MAX / 2.0Q)
{
z = -cosq (xx + xx);
if ((s * c) < 0)
cc = z / ss;
else
ss = z / cc;
}
if (xx > 0x1p256Q)
return ONEOSQPI * cc / sqrtq (xx);
xinv = 1.0Q / xx; xinv = 1.0Q / xx;
z = xinv * xinv; z = xinv * xinv;
if (xinv <= 0.25) if (xinv <= 0.25)
...@@ -760,21 +784,6 @@ j0q (__float128 x) ...@@ -760,21 +784,6 @@ j0q (__float128 x)
p = 1.0Q + z * p; p = 1.0Q + z * p;
q = z * xinv * q; q = z * xinv * q;
q = q - 0.125Q * xinv; q = q - 0.125Q * xinv;
/* X = x - pi/4
cos(X) = cos(x) cos(pi/4) + sin(x) sin(pi/4)
= 1/sqrt(2) * (cos(x) + sin(x))
sin(X) = sin(x) cos(pi/4) - cos(x) sin(pi/4)
= 1/sqrt(2) * (sin(x) - cos(x))
sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
cf. Fdlibm. */
sincosq (xx, &s, &c);
ss = s - c;
cc = s + c;
z = - cosq (xx + xx);
if ((s * c) < 0)
cc = z / ss;
else
ss = z / cc;
z = ONEOSQPI * (p * cc - q * ss) / sqrtq (xx); z = ONEOSQPI * (p * cc - q * ss) / sqrtq (xx);
return z; return z;
} }
...@@ -817,17 +826,12 @@ y0q (__float128 x) ...@@ -817,17 +826,12 @@ y0q (__float128 x)
__float128 xx, xinv, z, p, q, c, s, cc, ss; __float128 xx, xinv, z, p, q, c, s, cc, ss;
if (! finiteq (x)) if (! finiteq (x))
{ return 1 / (x + x * x);
if (x != x)
return x;
else
return 0.0Q;
}
if (x <= 0.0Q) if (x <= 0.0Q)
{ {
if (x < 0.0Q) if (x < 0.0Q)
return (zero / (zero * x)); return (zero / (zero * x));
return -HUGE_VALQ + x; return -1 / zero; /* -inf and divide by zero exception. */
} }
xx = fabsq (x); xx = fabsq (x);
if (xx <= 0x1p-57) if (xx <= 0x1p-57)
...@@ -841,6 +845,28 @@ y0q (__float128 x) ...@@ -841,6 +845,28 @@ y0q (__float128 x)
return p; return p;
} }
/* X = x - pi/4
cos(X) = cos(x) cos(pi/4) + sin(x) sin(pi/4)
= 1/sqrt(2) * (cos(x) + sin(x))
sin(X) = sin(x) cos(pi/4) - cos(x) sin(pi/4)
= 1/sqrt(2) * (sin(x) - cos(x))
sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
cf. Fdlibm. */
sincosq (x, &s, &c);
ss = s - c;
cc = s + c;
if (xx <= FLT128_MAX / 2.0Q)
{
z = -cosq (x + x);
if ((s * c) < 0)
cc = z / ss;
else
ss = z / cc;
}
if (xx > 0x1p256Q)
return ONEOSQPI * ss / sqrtq (x);
xinv = 1.0Q / xx; xinv = 1.0Q / xx;
z = xinv * xinv; z = xinv * xinv;
if (xinv <= 0.25) if (xinv <= 0.25)
...@@ -902,21 +928,6 @@ y0q (__float128 x) ...@@ -902,21 +928,6 @@ y0q (__float128 x)
p = 1.0Q + z * p; p = 1.0Q + z * p;
q = z * xinv * q; q = z * xinv * q;
q = q - 0.125Q * xinv; q = q - 0.125Q * xinv;
/* X = x - pi/4
cos(X) = cos(x) cos(pi/4) + sin(x) sin(pi/4)
= 1/sqrt(2) * (cos(x) + sin(x))
sin(X) = sin(x) cos(pi/4) - cos(x) sin(pi/4)
= 1/sqrt(2) * (sin(x) - cos(x))
sin(x) +- cos(x) = -cos(2x)/(sin(x) -+ cos(x))
cf. Fdlibm. */
sincosq (x, &s, &c);
ss = s - c;
cc = s + c;
z = - cosq (x + x);
if ((s * c) < 0)
cc = z / ss;
else
ss = z / cc;
z = ONEOSQPI * (p * ss + q * cc) / sqrtq (x); z = ONEOSQPI * (p * ss + q * cc) / sqrtq (x);
return z; return z;
} }
...@@ -95,6 +95,7 @@ ...@@ -95,6 +95,7 @@
License along with this library; if not, write to the Free Software License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <errno.h>
#include "quadmath-imp.h" #include "quadmath-imp.h"
/* 1 / sqrt(pi) */ /* 1 / sqrt(pi) */
...@@ -687,13 +688,21 @@ j1q (__float128 x) ...@@ -687,13 +688,21 @@ j1q (__float128 x)
if (! finiteq (x)) if (! finiteq (x))
{ {
if (x != x) if (x != x)
return x; return x + x;
else else
return 0.0Q; return 0.0Q;
} }
if (x == 0.0Q) if (x == 0.0Q)
return x; return x;
xx = fabsq (x); xx = fabsq (x);
if (xx <= 0x1p-58Q)
{
__float128 ret = x * 0.5Q;
math_check_force_underflow (ret);
if (ret == 0)
errno = ERANGE;
return ret;
}
if (xx <= 2.0Q) if (xx <= 2.0Q)
{ {
/* 0 <= x <= 2 */ /* 0 <= x <= 2 */
...@@ -705,6 +714,32 @@ j1q (__float128 x) ...@@ -705,6 +714,32 @@ j1q (__float128 x)
return p; return p;
} }
/* X = x - 3 pi/4
cos(X) = cos(x) cos(3 pi/4) + sin(x) sin(3 pi/4)
= 1/sqrt(2) * (-cos(x) + sin(x))
sin(X) = sin(x) cos(3 pi/4) - cos(x) sin(3 pi/4)
= -1/sqrt(2) * (sin(x) + cos(x))
cf. Fdlibm. */
sincosq (xx, &s, &c);
ss = -s - c;
cc = s - c;
if (xx <= FLT128_MAX / 2.0Q)
{
z = cosq (xx + xx);
if ((s * c) > 0)
cc = z / ss;
else
ss = z / cc;
}
if (xx > 0x1p256Q)
{
z = ONEOSQPI * cc / sqrtq (xx);
if (x < 0)
z = -z;
return z;
}
xinv = 1.0Q / xx; xinv = 1.0Q / xx;
z = xinv * xinv; z = xinv * xinv;
if (xinv <= 0.25) if (xinv <= 0.25)
...@@ -766,20 +801,6 @@ j1q (__float128 x) ...@@ -766,20 +801,6 @@ j1q (__float128 x)
p = 1.0Q + z * p; p = 1.0Q + z * p;
q = z * q; q = z * q;
q = q * xinv + 0.375Q * xinv; q = q * xinv + 0.375Q * xinv;
/* X = x - 3 pi/4
cos(X) = cos(x) cos(3 pi/4) + sin(x) sin(3 pi/4)
= 1/sqrt(2) * (-cos(x) + sin(x))
sin(X) = sin(x) cos(3 pi/4) - cos(x) sin(3 pi/4)
= -1/sqrt(2) * (sin(x) + cos(x))
cf. Fdlibm. */
sincosq (xx, &s, &c);
ss = -s - c;
cc = s - c;
z = cosq (xx + xx);
if ((s * c) > 0)
cc = z / ss;
else
ss = z / cc;
z = ONEOSQPI * (p * cc - q * ss) / sqrtq (xx); z = ONEOSQPI * (p * cc - q * ss) / sqrtq (xx);
if (x < 0) if (x < 0)
z = -z; z = -z;
...@@ -823,24 +844,25 @@ y1q (__float128 x) ...@@ -823,24 +844,25 @@ y1q (__float128 x)
__float128 xx, xinv, z, p, q, c, s, cc, ss; __float128 xx, xinv, z, p, q, c, s, cc, ss;
if (! finiteq (x)) if (! finiteq (x))
{ return 1 / (x + x * x);
if (x != x)
return x;
else
return 0.0Q;
}
if (x <= 0.0Q) if (x <= 0.0Q)
{ {
if (x < 0.0Q) if (x < 0.0Q)
return (zero / (zero * x)); return (zero / (zero * x));
return -HUGE_VALQ + x; return -1 / zero; /* -inf and divide by zero exception. */
} }
xx = fabsq (x); xx = fabsq (x);
if (xx <= 0x1p-114) if (xx <= 0x1p-114)
return -TWOOPI / x; {
z = -TWOOPI / x;
if (isinfq (z))
errno = ERANGE;
return z;
}
if (xx <= 2.0Q) if (xx <= 2.0Q)
{ {
/* 0 <= x <= 2 */ /* 0 <= x <= 2 */
/* FIXME: SET_RESTORE_ROUNDL (FE_TONEAREST); */
z = xx * xx; z = xx * xx;
p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D); p = xx * neval (z, Y0_2N, NY0_2N) / deval (z, Y0_2D, NY0_2D);
p = -TWOOPI / xx + p; p = -TWOOPI / xx + p;
...@@ -848,6 +870,27 @@ y1q (__float128 x) ...@@ -848,6 +870,27 @@ y1q (__float128 x)
return p; return p;
} }
/* X = x - 3 pi/4
cos(X) = cos(x) cos(3 pi/4) + sin(x) sin(3 pi/4)
= 1/sqrt(2) * (-cos(x) + sin(x))
sin(X) = sin(x) cos(3 pi/4) - cos(x) sin(3 pi/4)
= -1/sqrt(2) * (sin(x) + cos(x))
cf. Fdlibm. */
sincosq (xx, &s, &c);
ss = -s - c;
cc = s - c;
if (xx <= FLT128_MAX / 2.0Q)
{
z = cosq (xx + xx);
if ((s * c) > 0)
cc = z / ss;
else
ss = z / cc;
}
if (xx > 0x1p256Q)
return ONEOSQPI * ss / sqrtq (xx);
xinv = 1.0Q / xx; xinv = 1.0Q / xx;
z = xinv * xinv; z = xinv * xinv;
if (xinv <= 0.25) if (xinv <= 0.25)
...@@ -909,20 +952,6 @@ y1q (__float128 x) ...@@ -909,20 +952,6 @@ y1q (__float128 x)
p = 1.0Q + z * p; p = 1.0Q + z * p;
q = z * q; q = z * q;
q = q * xinv + 0.375Q * xinv; q = q * xinv + 0.375Q * xinv;
/* X = x - 3 pi/4
cos(X) = cos(x) cos(3 pi/4) + sin(x) sin(3 pi/4)
= 1/sqrt(2) * (-cos(x) + sin(x))
sin(X) = sin(x) cos(3 pi/4) - cos(x) sin(3 pi/4)
= -1/sqrt(2) * (sin(x) + cos(x))
cf. Fdlibm. */
sincosq (xx, &s, &c);
ss = -s - c;
cc = s - c;
z = cosq (xx + xx);
if ((s * c) > 0)
cc = z / ss;
else
ss = z / cc;
z = ONEOSQPI * (p * ss + q * cc) / sqrtq (xx); z = ONEOSQPI * (p * ss + q * cc) / sqrtq (xx);
return z; return z;
} }
/* Round argument to nearest integral value according to current rounding /* Round argument to nearest integral value according to current rounding
direction. direction.
Copyright (C) 1997, 1999, 2006 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -33,7 +33,7 @@ llrintq (__float128 x) ...@@ -33,7 +33,7 @@ llrintq (__float128 x)
{ {
int32_t j0; int32_t j0;
uint64_t i0,i1; uint64_t i0,i1;
volatile __float128 w; __float128 w;
__float128 t; __float128 t;
long long int result; long long int result;
int sx; int sx;
...@@ -46,8 +46,23 @@ llrintq (__float128 x) ...@@ -46,8 +46,23 @@ llrintq (__float128 x)
if (j0 < (int32_t) (8 * sizeof (long long int)) - 1) if (j0 < (int32_t) (8 * sizeof (long long int)) - 1)
{ {
w = two112[sx] + x; #if defined FE_INVALID || defined FE_INEXACT
t = w - two112[sx]; /* X < LLONG_MAX + 1 implied by J0 < 63. */
if (x > (__float128) LLONG_MAX)
{
/* In the event of overflow we must raise the "invalid"
exception, but not "inexact". */
t = nearbyintq (x);
#ifdef USE_FENV_H
feraiseexcept (t == LLONG_MAX ? FE_INEXACT : FE_INVALID);
#endif
}
else
#endif
{
w = two112[sx] + x;
t = w - two112[sx];
}
GET_FLT128_WORDS64 (i0, i1, t); GET_FLT128_WORDS64 (i0, i1, t);
j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
i0 &= 0x0000ffffffffffffLL; i0 &= 0x0000ffffffffffffLL;
...@@ -62,6 +77,24 @@ llrintq (__float128 x) ...@@ -62,6 +77,24 @@ llrintq (__float128 x)
} }
else else
{ {
/* The number is too large. Unless it rounds to LLONG_MIN,
FE_INVALID must be raised and the return value is
unspecified. */
#if defined FE_INVALID || defined FE_INEXACT
if (x < (__float128) LLONG_MIN
&& x > (__float128) LLONG_MIN - 1.0Q)
{
/* If truncation produces LLONG_MIN, the cast will not raise
the exception, but may raise "inexact". */
t = nearbyintq (x);
#ifdef USE_FENV_H
feraiseexcept (t == LLONG_MIN ? FE_INEXACT : FE_INVALID);
#endif
return LLONG_MIN;
}
#endif
/* The number is too large. It is left implementation defined /* The number is too large. It is left implementation defined
what happens. */ what happens. */
return (long long int) x; return (long long int) x;
......
/* Round __float128 value to long long int. /* Round __float128 value to long long int.
Copyright (C) 1997, 1999, 2004 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -59,13 +59,32 @@ llroundq (__float128 x) ...@@ -59,13 +59,32 @@ llroundq (__float128 x)
if (j0 == 48) if (j0 == 48)
result = (long long int) i0; result = (long long int) i0;
else else
result = ((long long int) i0 << (j0 - 48)) | (j >> (112 - j0)); {
result = ((long long int) i0 << (j0 - 48)) | (j >> (112 - j0));
#if defined FE_INVALID && defined USE_FENV_H
if (sign == 1 && result == LLONG_MIN)
/* Rounding brought the value out of range. */
feraiseexcept (FE_INVALID);
#endif
}
} }
} }
else else
{ {
/* The number is too large. It is left implementation defined /* The number is too large. Unless it rounds to LLONG_MIN,
what happens. */ FE_INVALID must be raised and the return value is
unspecified. */
#ifdef FE_INVALID
if (x <= (__float128) LLONG_MIN - 0.5Q)
{
/* If truncation produces LLONG_MIN, the cast will not raise
the exception, but may raise "inexact". */
#ifdef USE_FENV_H
feraiseexcept (FE_INVALID);
#endif
return LLONG_MIN;
}
#endif
return (long long int) x; return (long long int) x;
} }
......
...@@ -188,12 +188,15 @@ log10q (__float128 x) ...@@ -188,12 +188,15 @@ log10q (__float128 x)
/* Test for domain */ /* Test for domain */
GET_FLT128_WORDS64 (hx, lx, x); GET_FLT128_WORDS64 (hx, lx, x);
if (((hx & 0x7fffffffffffffffLL) | lx) == 0) if (((hx & 0x7fffffffffffffffLL) | lx) == 0)
return (-1.0Q / (x - x)); return (-1.0Q / fabsq (x)); /* log10l(+-0)=-inf */
if (hx < 0) if (hx < 0)
return (x - x) / (x - x); return (x - x) / (x - x);
if (hx >= 0x7fff000000000000LL) if (hx >= 0x7fff000000000000LL)
return (x + x); return (x + x);
if (x == 1.0Q)
return 0.0Q;
/* separate mantissa from exponent */ /* separate mantissa from exponent */
/* Note, frexp is used so that denormal numbers /* Note, frexp is used so that denormal numbers
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
* IEEE -1, 8 100000 1.9e-34 4.3e-35 * IEEE -1, 8 100000 1.9e-34 4.3e-35
*/ */
/* Copyright 2001 by Stephen L. Moshier /* Copyright 2001 by Stephen L. Moshier
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -128,8 +128,8 @@ log1pq (__float128 xm1) ...@@ -128,8 +128,8 @@ log1pq (__float128 xm1)
/* Test for NaN or infinity input. */ /* Test for NaN or infinity input. */
u.value = xm1; u.value = xm1;
hx = u.words32.w0; hx = u.words32.w0;
if (hx >= 0x7fff0000) if ((hx & 0x7fffffff) >= 0x7fff0000)
return xm1; return xm1 + fabsq (xm1);
/* log1p(+- 0) = +- 0. */ /* log1p(+- 0) = +- 0. */
if (((hx & 0x7fffffff) == 0) if (((hx & 0x7fffffff) == 0)
...@@ -138,17 +138,21 @@ log1pq (__float128 xm1) ...@@ -138,17 +138,21 @@ log1pq (__float128 xm1)
if ((hx & 0x7fffffff) < 0x3f8e0000) if ((hx & 0x7fffffff) < 0x3f8e0000)
{ {
math_check_force_underflow (xm1);
if ((int) xm1 == 0) if ((int) xm1 == 0)
return xm1; return xm1;
} }
x = xm1 + 1.0Q; if (xm1 >= 0x1p113Q)
x = xm1;
else
x = xm1 + 1.0Q;
/* log1p(-1) = -inf */ /* log1p(-1) = -inf */
if (x <= 0.0Q) if (x <= 0.0Q)
{ {
if (x == 0.0Q) if (x == 0.0Q)
return (-1.0Q / (x - x)); return (-1.0Q / zero); /* log1p(-1) = -inf */
else else
return (zero / (x - x)); return (zero / (x - x));
} }
......
...@@ -181,12 +181,15 @@ log2q (__float128 x) ...@@ -181,12 +181,15 @@ log2q (__float128 x)
/* Test for domain */ /* Test for domain */
GET_FLT128_WORDS64 (hx, lx, x); GET_FLT128_WORDS64 (hx, lx, x);
if (((hx & 0x7fffffffffffffffLL) | lx) == 0) if (((hx & 0x7fffffffffffffffLL) | lx) == 0)
return (-1.0Q / (x - x)); return (-1.0Q / fabsq (x)); /* log2l(+-0)=-inf */
if (hx < 0) if (hx < 0)
return (x - x) / (x - x); return (x - x) / (x - x);
if (hx >= 0x7fff000000000000LL) if (hx >= 0x7fff000000000000LL)
return (x + x); return (x + x);
if (x == 1.0Q)
return 0.0Q;
/* separate mantissa from exponent */ /* separate mantissa from exponent */
/* Note, frexp is used so that denormal numbers /* Note, frexp is used so that denormal numbers
......
...@@ -212,9 +212,8 @@ logq (__float128 x) ...@@ -212,9 +212,8 @@ logq (__float128 x)
} }
/* Extract exponent and reduce domain to 0.703125 <= u < 1.40625 */ /* Extract exponent and reduce domain to 0.703125 <= u < 1.40625 */
e = (int) (m >> 16) - (int) 0x3ffe; u.value = frexpq (x, &e);
m &= 0xffff; m = u.words32.w0 & 0xffff;
u.words32.w0 = m | 0x3ffe0000;
m |= 0x10000; m |= 0x10000;
/* Find lookup table index k from high order bits of the significand. */ /* Find lookup table index k from high order bits of the significand. */
if (m < 0x16800) if (m < 0x16800)
...@@ -241,6 +240,8 @@ logq (__float128 x) ...@@ -241,6 +240,8 @@ logq (__float128 x)
/* On this interval the table is not used due to cancellation error. */ /* On this interval the table is not used due to cancellation error. */
if ((x <= 1.0078125Q) && (x >= 0.9921875Q)) if ((x <= 1.0078125Q) && (x >= 0.9921875Q))
{ {
if (x == 1.0Q)
return 0.0Q;
z = x - 1.0Q; z = x - 1.0Q;
k = 64; k = 64;
t.value = 1.0Q; t.value = 1.0Q;
......
/* Round argument to nearest integral value according to current rounding /* Round argument to nearest integral value according to current rounding
direction. direction.
Copyright (C) 1997, 1999, 2004, 2006 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -33,7 +33,7 @@ lrintq (__float128 x) ...@@ -33,7 +33,7 @@ lrintq (__float128 x)
{ {
int32_t j0; int32_t j0;
uint64_t i0,i1; uint64_t i0,i1;
volatile __float128 w; __float128 w;
__float128 t; __float128 t;
long int result; long int result;
int sx; int sx;
...@@ -44,25 +44,57 @@ lrintq (__float128 x) ...@@ -44,25 +44,57 @@ lrintq (__float128 x)
i0 &= 0x0000ffffffffffffLL; i0 &= 0x0000ffffffffffffLL;
i0 |= 0x0001000000000000LL; i0 |= 0x0001000000000000LL;
if (j0 < 48) if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
{ {
w = two112[sx] + x; if (j0 < 48)
t = w - two112[sx]; {
GET_FLT128_WORDS64 (i0, i1, t); #if defined FE_INVALID || defined FE_INEXACT
j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; /* X < LONG_MAX + 1 implied by J0 < 31. */
i0 &= 0x0000ffffffffffffLL; if (sizeof (long int) == 4
i0 |= 0x0001000000000000LL; && x > (__float128) LONG_MAX)
{
/* In the event of overflow we must raise the "invalid"
exception, but not "inexact". */
t = nearbyintq (x);
#ifdef USE_FENV_H
feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
#endif
}
else
#endif
{
w = two112[sx] + x;
t = w - two112[sx];
}
GET_FLT128_WORDS64 (i0, i1, t);
j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
i0 &= 0x0000ffffffffffffLL;
i0 |= 0x0001000000000000LL;
result = (j0 < 0 ? 0 : i0 >> (48 - j0)); result = (j0 < 0 ? 0 : i0 >> (48 - j0));
} }
else if (j0 < (int32_t) (8 * sizeof (long int)) - 1) else if (j0 >= 112)
{
if (j0 >= 112)
result = ((long int) i0 << (j0 - 48)) | (i1 << (j0 - 112)); result = ((long int) i0 << (j0 - 48)) | (i1 << (j0 - 112));
else else
{ {
w = two112[sx] + x; #if defined FE_INVALID || defined FE_INEXACT
t = w - two112[sx]; /* X < LONG_MAX + 1 implied by J0 < 63. */
if (sizeof (long int) == 8
&& x > (__float128) LONG_MAX)
{
/* In the event of overflow we must raise the "invalid"
exception, but not "inexact". */
t = nearbyintq (x);
#ifdef USE_FENV_H
feraiseexcept (t == LONG_MAX ? FE_INEXACT : FE_INVALID);
#endif
}
else
#endif
{
w = two112[sx] + x;
t = w - two112[sx];
}
GET_FLT128_WORDS64 (i0, i1, t); GET_FLT128_WORDS64 (i0, i1, t);
j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
i0 &= 0x0000ffffffffffffLL; i0 &= 0x0000ffffffffffffLL;
...@@ -76,8 +108,22 @@ lrintq (__float128 x) ...@@ -76,8 +108,22 @@ lrintq (__float128 x)
} }
else else
{ {
/* The number is too large. It is left implementation defined /* The number is too large. Unless it rounds to LONG_MIN,
what happens. */ FE_INVALID must be raised and the return value is
unspecified. */
#if defined FE_INVALID || defined FE_INEXACT
if (x < (__float128) LONG_MIN
&& x > (__float128) LONG_MIN - 1.0Q)
{
/* If truncation produces LONG_MIN, the cast will not raise
the exception, but may raise "inexact". */
t = nearbyintq (x);
#ifdef USE_FENV_H
feraiseexcept (t == LONG_MIN ? FE_INEXACT : FE_INVALID);
#endif
return LONG_MIN;
}
#endif
return (long int) x; return (long int) x;
} }
......
/* Round __float128 value to long int. /* Round __float128 value to long int.
Copyright (C) 1997, 1999, 2004 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
...@@ -36,19 +36,26 @@ lroundq (__float128 x) ...@@ -36,19 +36,26 @@ lroundq (__float128 x)
i0 &= 0x0000ffffffffffffLL; i0 &= 0x0000ffffffffffffLL;
i0 |= 0x0001000000000000LL; i0 |= 0x0001000000000000LL;
if (j0 < 48) if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
{ {
if (j0 < 0) if (j0 < 48)
return j0 < -1 ? 0 : sign;
else
{ {
i0 += 0x0000800000000000LL >> j0; if (j0 < 0)
result = i0 >> (48 - j0); return j0 < -1 ? 0 : sign;
else
{
i0 += 0x0000800000000000LL >> j0;
result = i0 >> (48 - j0);
#if defined FE_INVALID && defined USE_FENV_H
if (sizeof (long int) == 4
&& sign == 1
&& result == LONG_MIN)
/* Rounding brought the value out of range. */
feraiseexcept (FE_INVALID);
#endif
}
} }
} else if (j0 >= 112)
else if (j0 < (int32_t) (8 * sizeof (long int)) - 1)
{
if (j0 >= 112)
result = ((long int) i0 << (j0 - 48)) | (i1 << (j0 - 112)); result = ((long int) i0 << (j0 - 48)) | (i1 << (j0 - 112));
else else
{ {
...@@ -59,13 +66,34 @@ lroundq (__float128 x) ...@@ -59,13 +66,34 @@ lroundq (__float128 x)
if (j0 == 48) if (j0 == 48)
result = (long int) i0; result = (long int) i0;
else else
result = ((long int) i0 << (j0 - 48)) | (j >> (112 - j0)); {
result = ((long int) i0 << (j0 - 48)) | (j >> (112 - j0));
#if defined FE_INVALID && defined USE_FENV_H
if (sizeof (long int) == 8
&& sign == 1
&& result == LONG_MIN)
/* Rounding brought the value out of range. */
feraiseexcept (FE_INVALID);
#endif
}
} }
} }
else else
{ {
/* The number is too large. It is left implementation defined /* The number is too large. Unless it rounds to LONG_MIN,
what happens. */ FE_INVALID must be raised and the return value is
unspecified. */
#ifdef FE_INVALID
if (x <= (__float128) LONG_MIN - 0.5Q)
{
/* If truncation produces LONG_MIN, the cast will not raise
the exception, but may raise "inexact". */
#ifdef USE_FENV_H
feraiseexcept (FE_INVALID);
#endif
return LONG_MIN;
}
#endif
return (long int) x; return (long int) x;
} }
......
...@@ -44,7 +44,7 @@ nearbyintq(__float128 x) ...@@ -44,7 +44,7 @@ nearbyintq(__float128 x)
fenv_t env; fenv_t env;
#endif #endif
int64_t i0,j0,sx; int64_t i0,j0,sx;
uint64_t i1; uint64_t i1 __attribute__ ((unused));
__float128 w,t; __float128 w,t;
GET_FLT128_WORDS64(i0,i1,x); GET_FLT128_WORDS64(i0,i1,x);
sx = (((uint64_t)i0)>>63); sx = (((uint64_t)i0)>>63);
...@@ -56,6 +56,7 @@ nearbyintq(__float128 x) ...@@ -56,6 +56,7 @@ nearbyintq(__float128 x)
#endif #endif
w = TWO112[sx]+x; w = TWO112[sx]+x;
t = w-TWO112[sx]; t = w-TWO112[sx];
math_force_eval (t);
#ifdef USE_FENV_H #ifdef USE_FENV_H
fesetenv (&env); fesetenv (&env);
#endif #endif
...@@ -72,6 +73,7 @@ nearbyintq(__float128 x) ...@@ -72,6 +73,7 @@ nearbyintq(__float128 x)
#endif #endif
w = TWO112[sx]+x; w = TWO112[sx]+x;
t = w-TWO112[sx]; t = w-TWO112[sx];
math_force_eval (t);
#ifdef USE_FENV_H #ifdef USE_FENV_H
fesetenv (&env); fesetenv (&env);
#endif #endif
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
* ==================================================== * ====================================================
*/ */
#include <errno.h>
#include "quadmath-imp.h" #include "quadmath-imp.h"
__float128 __float128
...@@ -54,9 +55,15 @@ nextafterq (__float128 x, __float128 y) ...@@ -54,9 +55,15 @@ nextafterq (__float128 x, __float128 y)
} }
} }
hy = hx&0x7fff000000000000LL; hy = hx&0x7fff000000000000LL;
if(hy==0x7fff000000000000LL) return x+x;/* overflow */ if(hy==0x7fff000000000000LL) {
__float128 u = x + x; /* overflow */
math_force_eval (u);
errno = ERANGE;
}
if(hy==0) { if(hy==0) {
/* here we should raise an underflow flag */ __float128 u = x*x; /* underflow */
math_force_eval (u); /* raise underflow flag */
errno = ERANGE;
} }
SET_FLT128_WORDS64(x,hx,lx); SET_FLT128_WORDS64(x,hx,lx);
return x; return x;
......
...@@ -147,7 +147,7 @@ __float128 ...@@ -147,7 +147,7 @@ __float128
powq (__float128 x, __float128 y) powq (__float128 x, __float128 y)
{ {
__float128 z, ax, z_h, z_l, p_h, p_l; __float128 z, ax, z_h, z_l, p_h, p_l;
__float128 y1, t1, t2, r, s, t, u, v, w; __float128 y1, t1, t2, r, s, sgn, t, u, v, w;
__float128 s2, s_h, s_l, t_h, t_l, ay; __float128 s2, s_h, s_l, t_h, t_l, ay;
int32_t i, j, k, yisint, n; int32_t i, j, k, yisint, n;
uint32_t ix, iy; uint32_t ix, iy;
...@@ -261,6 +261,11 @@ powq (__float128 x, __float128 y) ...@@ -261,6 +261,11 @@ powq (__float128 x, __float128 y)
if (((((uint32_t) hx >> 31) - 1) | yisint) == 0) if (((((uint32_t) hx >> 31) - 1) | yisint) == 0)
return (x - x) / (x - x); return (x - x) / (x - x);
/* sgn (sign of result -ve**odd) = -1 else = 1 */
sgn = one;
if (((((u_int32_t) hx >> 31) - 1) | (yisint - 1)) == 0)
sgn = -one; /* (-ve)**(odd int) */
/* |y| is huge. /* |y| is huge.
2^-16495 = 1/2 of smallest representable value. 2^-16495 = 1/2 of smallest representable value.
If (1 - 1/131072)^y underflows, y > 1.4986e9 */ If (1 - 1/131072)^y underflows, y > 1.4986e9 */
...@@ -276,9 +281,9 @@ powq (__float128 x, __float128 y) ...@@ -276,9 +281,9 @@ powq (__float128 x, __float128 y)
} }
/* over/underflow if x is not close to one */ /* over/underflow if x is not close to one */
if (ix < 0x3ffeffff) if (ix < 0x3ffeffff)
return (hy < 0) ? huge * huge : tiny * tiny; return (hy < 0) ? sgn * huge * huge : sgn * tiny * tiny;
if (ix > 0x3fff0000) if (ix > 0x3fff0000)
return (hy > 0) ? huge * huge : tiny * tiny; return (hy > 0) ? sgn * huge * huge : sgn * tiny * tiny;
} }
ay = y > 0 ? y : -y; ay = y > 0 ? y : -y;
...@@ -365,11 +370,6 @@ powq (__float128 x, __float128 y) ...@@ -365,11 +370,6 @@ powq (__float128 x, __float128 y)
t1 = o.value; t1 = o.value;
t2 = z_l - (((t1 - t) - dp_h[k]) - z_h); t2 = z_l - (((t1 - t) - dp_h[k]) - z_h);
/* s (sign of result -ve**odd) = -1 else = 1 */
s = one;
if (((((uint32_t) hx >> 31) - 1) | (yisint - 1)) == 0)
s = -one; /* (-ve)**(odd int) */
/* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */ /* split up y into y1+y2 and compute (y1+y2)*(t1+t2) */
y1 = y; y1 = y;
o.value = y1; o.value = y1;
...@@ -385,11 +385,11 @@ powq (__float128 x, __float128 y) ...@@ -385,11 +385,11 @@ powq (__float128 x, __float128 y)
{ {
/* if z > 16384 */ /* if z > 16384 */
if (((j - 0x400d0000) | o.words32.w1 | o.words32.w2 | o.words32.w3) != 0) if (((j - 0x400d0000) | o.words32.w1 | o.words32.w2 | o.words32.w3) != 0)
return s * huge * huge; /* overflow */ return sgn * huge * huge; /* overflow */
else else
{ {
if (p_l + ovt > z - p_h) if (p_l + ovt > z - p_h)
return s * huge * huge; /* overflow */ return sgn * huge * huge; /* overflow */
} }
} }
else if ((j & 0x7fffffff) >= 0x400d01b9) /* z <= -16495 */ else if ((j & 0x7fffffff) >= 0x400d01b9) /* z <= -16495 */
...@@ -397,11 +397,11 @@ powq (__float128 x, __float128 y) ...@@ -397,11 +397,11 @@ powq (__float128 x, __float128 y)
/* z < -16495 */ /* z < -16495 */
if (((j - 0xc00d01bc) | o.words32.w1 | o.words32.w2 | o.words32.w3) if (((j - 0xc00d01bc) | o.words32.w1 | o.words32.w2 | o.words32.w3)
!= 0) != 0)
return s * tiny * tiny; /* underflow */ return sgn * tiny * tiny; /* underflow */
else else
{ {
if (p_l <= z - p_h) if (p_l <= z - p_h)
return s * tiny * tiny; /* underflow */ return sgn * tiny * tiny; /* underflow */
} }
} }
/* compute 2**(p_h+p_l) */ /* compute 2**(p_h+p_l) */
...@@ -434,11 +434,15 @@ powq (__float128 x, __float128 y) ...@@ -434,11 +434,15 @@ powq (__float128 x, __float128 y)
j = o.words32.w0; j = o.words32.w0;
j += (n << 16); j += (n << 16);
if ((j >> 16) <= 0) if ((j >> 16) <= 0)
z = scalbnq (z, n); /* subnormal output */ {
z = scalbnq (z, n); /* subnormal output */
__float128 force_underflow = z * z;
math_force_eval (force_underflow);
}
else else
{ {
o.words32.w0 = j; o.words32.w0 = j;
z = o.value; z = o.value;
} }
return s * z; return sgn * z;
} }
/* Compute remainder and a congruent to the quotient. /* Compute remainder and a congruent to the quotient.
Copyright (C) 1997, 1999, 2002 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
...@@ -49,7 +49,7 @@ remquoq (__float128 x, __float128 y, int *quo) ...@@ -49,7 +49,7 @@ remquoq (__float128 x, __float128 y, int *quo)
if (hy <= 0x7ffbffffffffffffLL) if (hy <= 0x7ffbffffffffffffLL)
x = fmodq (x, 8 * y); /* now x < 8y */ x = fmodq (x, 8 * y); /* now x < 8y */
if (((hx - hy) | (lx - ly)) == 0) if (((hx - hy) | (lx - ly)) == 0)
{ {
*quo = qs ? -1 : 1; *quo = qs ? -1 : 1;
...@@ -60,12 +60,12 @@ remquoq (__float128 x, __float128 y, int *quo) ...@@ -60,12 +60,12 @@ remquoq (__float128 x, __float128 y, int *quo)
y = fabsq (y); y = fabsq (y);
cquo = 0; cquo = 0;
if (x >= 4 * y) if (hy <= 0x7ffcffffffffffffLL && x >= 4 * y)
{ {
x -= 4 * y; x -= 4 * y;
cquo += 4; cquo += 4;
} }
if (x >= 2 * y) if (hy <= 0x7ffdffffffffffffLL && x >= 2 * y)
{ {
x -= 2 * y; x -= 2 * y;
cquo += 2; cquo += 2;
...@@ -101,6 +101,9 @@ remquoq (__float128 x, __float128 y, int *quo) ...@@ -101,6 +101,9 @@ remquoq (__float128 x, __float128 y, int *quo)
*quo = qs ? -cquo : cquo; *quo = qs ? -cquo : cquo;
/* Ensure correct sign of zero result in round-downward mode. */
if (x == 0.0Q)
x = 0.0Q;
if (sx) if (sx)
x = -x; x = -x;
return x; return x;
......
...@@ -35,7 +35,7 @@ __float128 ...@@ -35,7 +35,7 @@ __float128
rintq (__float128 x) rintq (__float128 x)
{ {
int64_t i0,j0,sx; int64_t i0,j0,sx;
uint64_t i1; uint64_t i1 __attribute__ ((unused));
__float128 w,t; __float128 w,t;
GET_FLT128_WORDS64(i0,i1,x); GET_FLT128_WORDS64(i0,i1,x);
sx = (((uint64_t)i0)>>63); sx = (((uint64_t)i0)>>63);
......
/* Round __float128 to integer away from zero. /* Round __float128 to integer away from zero.
Copyright (C) 1997, 1999 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
...@@ -21,9 +21,6 @@ ...@@ -21,9 +21,6 @@
#include "quadmath-imp.h" #include "quadmath-imp.h"
static const __float128 huge = 1.0E4930Q;
__float128 __float128
roundq (__float128 x) roundq (__float128 x)
{ {
...@@ -32,17 +29,14 @@ roundq (__float128 x) ...@@ -32,17 +29,14 @@ roundq (__float128 x)
GET_FLT128_WORDS64 (i0, i1, x); GET_FLT128_WORDS64 (i0, i1, x);
j0 = ((i0 >> 48) & 0x7fff) - 0x3fff; j0 = ((i0 >> 48) & 0x7fff) - 0x3fff;
if (j0 < 31) if (j0 < 48)
{ {
if (j0 < 0) if (j0 < 0)
{ {
if (huge + x > 0.0) i0 &= 0x8000000000000000ULL;
{ if (j0 == -1)
i0 &= 0x8000000000000000ULL; i0 |= 0x3fff000000000000LL;
if (j0 == -1) i1 = 0;
i0 |= 0x3fff000000000000LL;
i1 = 0;
}
} }
else else
{ {
...@@ -50,13 +44,9 @@ roundq (__float128 x) ...@@ -50,13 +44,9 @@ roundq (__float128 x)
if (((i0 & i) | i1) == 0) if (((i0 & i) | i1) == 0)
/* X is integral. */ /* X is integral. */
return x; return x;
if (huge + x > 0.0) i0 += 0x0000800000000000LL >> j0;
{ i0 &= ~i;
/* Raise inexact if x != 0. */ i1 = 0;
i0 += 0x0000800000000000LL >> j0;
i0 &= ~i;
i1 = 0;
}
} }
} }
else if (j0 > 111) else if (j0 > 111)
...@@ -74,14 +64,10 @@ roundq (__float128 x) ...@@ -74,14 +64,10 @@ roundq (__float128 x)
/* X is integral. */ /* X is integral. */
return x; return x;
if (huge + x > 0.0) uint64_t j = i1 + (1LL << (111 - j0));
{ if (j < i1)
/* Raise inexact if x != 0. */ i0 += 1;
uint64_t j = i1 + (1LL << (111 - j0)); i1 = j;
if (j < i1)
i0 += 1;
i1 = j;
}
i1 &= ~i; i1 &= ~i;
} }
......
/* scalblnq.c -- __float128 version of s_scalbn.c. /* scalblnq.c -- __float128 version of s_scalbn.c.
* Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz. * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
*/ */
/* /*
* ==================================================== * ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
......
/* scalbnq.c -- __float128 version of s_scalbn.c. /* scalbnq.c -- __float128 version of s_scalbn.c.
* Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz. * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
*/ */
/* /*
* ==================================================== * ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
......
/* Quad-precision floating point sine and cosine tables. /* Quad-precision floating point sine and cosine tables.
Copyright (C) 1999 Free Software Foundation, Inc. Copyright (C) 1999-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jj@ultra.linux.cz> Contributed by Jakub Jelinek <jj@ultra.linux.cz>
...@@ -37,7 +37,7 @@ const __float128 __sincosq_table[] = { ...@@ -37,7 +37,7 @@ const __float128 __sincosq_table[] = {
/* sin(x) = 0.25dc50bc95711d0d9787d108fd438cf5959ee0bfb7a1e36e8b1a112968f356657420e9cc9ea */ /* sin(x) = 0.25dc50bc95711d0d9787d108fd438cf5959ee0bfb7a1e36e8b1a112968f356657420e9cc9ea */
1.47892995873409608580026675734609314e-01Q, /* 3ffc2ee285e4ab88e86cbc3e8847ea1c */ 1.47892995873409608580026675734609314e-01Q, /* 3ffc2ee285e4ab88e86cbc3e8847ea1c */
9.74950446464233268291647449768590886e-36Q, /* 3f8a9eb2b3dc17f6f43c6dd16342252d */ 9.74950446464233268291647449768590886e-36Q, /* 3f8a9eb2b3dc17f6f43c6dd16342252d */
/* x = 1.56250000000000000000000000000000000e-01 3ffc4000000000000000000000000000 */ /* x = 1.56250000000000000000000000000000000e-01 3ffc4000000000000000000000000000 */
/* cos(x) = 0.fce1a053e621438b6d60c76e8c45bf0a9dc71aa16f922acc10e95144ec796a249813c9cb649 */ /* cos(x) = 0.fce1a053e621438b6d60c76e8c45bf0a9dc71aa16f922acc10e95144ec796a249813c9cb649 */
9.87817783816471944100503034363211317e-01Q, /* 3ffef9c340a7cc428716dac18edd188b */ 9.87817783816471944100503034363211317e-01Q, /* 3ffef9c340a7cc428716dac18edd188b */
......
/* Compute sine and cosine of argument. /* Compute sine and cosine of argument.
Copyright (C) 1997, 1999 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>. Jakub Jelinek <jj@ultra.linux.cz>.
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */ 02111-1307 USA. */
#include <errno.h>
#include "quadmath-imp.h" #include "quadmath-imp.h"
void void
...@@ -37,6 +38,8 @@ sincosq (__float128 x, __float128 *sinx, __float128 *cosx) ...@@ -37,6 +38,8 @@ sincosq (__float128 x, __float128 *sinx, __float128 *cosx)
{ {
/* sin(Inf or NaN) is NaN */ /* sin(Inf or NaN) is NaN */
*sinx = *cosx = x - x; *sinx = *cosx = x - x;
if (isinfq (x))
errno = EDOM;
} }
else else
{ {
......
/* Quad-precision floating point sine and cosine on <-pi/4,pi/4>. /* Quad-precision floating point sine and cosine on <-pi/4,pi/4>.
Copyright (C) 1999 Free Software Foundation, Inc. Copyright (C) 1999-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jj@ultra.linux.cz> Contributed by Jakub Jelinek <jj@ultra.linux.cz>
...@@ -110,12 +110,15 @@ __quadmath_kernel_sincosq(__float128 x, __float128 y, __float128 *sinx, ...@@ -110,12 +110,15 @@ __quadmath_kernel_sincosq(__float128 x, __float128 y, __float128 *sinx,
/* Argument is small enough to approximate it by a Chebyshev /* Argument is small enough to approximate it by a Chebyshev
polynomial of degree 16(17). */ polynomial of degree 16(17). */
if (tix < 0x3fc60000) /* |x| < 2^-57 */ if (tix < 0x3fc60000) /* |x| < 2^-57 */
if (!((int)x)) /* generate inexact */ {
{ math_check_force_underflow (x);
*sinx = x; if (!((int)x)) /* generate inexact */
*cosx = ONE; {
return; *sinx = x;
} *cosx = ONE;
return;
}
}
z = x * x; z = x * x;
*sinx = x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ *sinx = x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+
z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8)))))))));
......
...@@ -85,8 +85,11 @@ sinhq (__float128 x) ...@@ -85,8 +85,11 @@ sinhq (__float128 x)
if (ix <= 0x40044000) if (ix <= 0x40044000)
{ {
if (ix < 0x3fc60000) /* |x| < 2^-57 */ if (ix < 0x3fc60000) /* |x| < 2^-57 */
if (shuge + x > one) {
return x; /* sinh(tiny) = tiny with inexact */ math_check_force_underflow (x);
if (shuge + x > one)
return x; /* sinh(tiny) = tiny with inexact */
}
t = expm1q (u.value); t = expm1q (u.value);
if (ix < 0x3fff0000) if (ix < 0x3fff0000)
return h * (2.0Q * t - t * t / (t + one)); return h * (2.0Q * t - t * t / (t + one));
......
...@@ -90,7 +90,10 @@ __quadmath_kernel_sinq (__float128 x, __float128 y, int iy) ...@@ -90,7 +90,10 @@ __quadmath_kernel_sinq (__float128 x, __float128 y, int iy)
/* Argument is small enough to approximate it by a Chebyshev /* Argument is small enough to approximate it by a Chebyshev
polynomial of degree 17. */ polynomial of degree 17. */
if (tix < 0x3fc60000) /* |x| < 2^-57 */ if (tix < 0x3fc60000) /* |x| < 2^-57 */
if (!((int)x)) return x; /* generate inexact */ {
math_check_force_underflow (x);
if (!((int)x)) return x; /* generate inexact */
}
z = x * x; z = x * x;
return x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+ return x + (x * (z*(SIN1+z*(SIN2+z*(SIN3+z*(SIN4+
z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8))))))))); z*(SIN5+z*(SIN6+z*(SIN7+z*SIN8)))))))));
......
...@@ -72,7 +72,10 @@ tanhq (__float128 x) ...@@ -72,7 +72,10 @@ tanhq (__float128 x)
if (u.value == 0) if (u.value == 0)
return x; /* x == +- 0 */ return x; /* x == +- 0 */
if (ix < 0x3fc60000) /* |x| < 2^-57 */ if (ix < 0x3fc60000) /* |x| < 2^-57 */
return x * (one + tiny); /* tanh(small) = small */ {
math_check_force_underflow (x);
return x * (one + tiny); /* tanh(small) = small */
}
u.words32.w0 = ix; /* Absolute value of x. */ u.words32.w0 = ix; /* Absolute value of x. */
if (ix >= 0x3fff0000) if (ix >= 0x3fff0000)
{ /* |x| >= 1 */ { /* |x| >= 1 */
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
/* /*
Long double expansions are Long double expansions are
Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov> Copyright (C) 2001 Stephen L. Moshier <moshier@na-net.ornl.gov>
and are incorporated herein by permission of the author. The author and are incorporated herein by permission of the author. The author
reserves the right to distribute this material elsewhere under different reserves the right to distribute this material elsewhere under different
copying permissions. These modifications are distributed here under copying permissions. These modifications are distributed here under
the following terms: the following terms:
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
...@@ -99,8 +99,13 @@ __quadmath_kernel_tanq (__float128 x, __float128 y, int iy) ...@@ -99,8 +99,13 @@ __quadmath_kernel_tanq (__float128 x, __float128 y, int iy)
if ((ix | u.words32.w1 | u.words32.w2 | u.words32.w3 if ((ix | u.words32.w1 | u.words32.w2 | u.words32.w3
| (iy + 1)) == 0) | (iy + 1)) == 0)
return one / fabsq (x); return one / fabsq (x);
else if (iy == 1)
{
math_check_force_underflow (x);
return x;
}
else else
return (iy == 1) ? x : -one / x; return -one / x;
} }
} }
if (ix >= 0x3ffe5942) /* |x| >= 0.6743316650390625 */ if (ix >= 0x3ffe5942) /* |x| >= 0.6743316650390625 */
...@@ -163,7 +168,7 @@ __quadmath_kernel_tanq (__float128 x, __float128 y, int iy) ...@@ -163,7 +168,7 @@ __quadmath_kernel_tanq (__float128 x, __float128 y, int iy)
/* tanq.c -- __float128 version of s_tan.c. /* tanq.c -- __float128 version of s_tan.c.
* Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz. * Conversion to IEEE quad long double by Jakub Jelinek, jj@ultra.linux.cz.
*/ */
/* @(#)s_tan.c 5.1 93/09/24 */ /* @(#)s_tan.c 5.1 93/09/24 */
/* /*
* ==================================================== * ====================================================
......
/* Truncate argument to nearest integral value not larger than the argument. /* Truncate argument to nearest integral value not larger than the argument.
Copyright (C) 1997, 1999 Free Software Foundation, Inc. Copyright (C) 1997-2017 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
Jakub Jelinek <jj@ultra.linux.cz>, 1999. Jakub Jelinek <jj@ultra.linux.cz>, 1999.
The GNU C Library is free software; you can redistribute it and/or The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
......
...@@ -186,4 +186,45 @@ do { \ ...@@ -186,4 +186,45 @@ do { \
__builtin_fpclassify (QUADFP_NAN, QUADFP_INFINITE, QUADFP_NORMAL, \ __builtin_fpclassify (QUADFP_NAN, QUADFP_INFINITE, QUADFP_NORMAL, \
QUADFP_SUBNORMAL, QUADFP_ZERO, x) QUADFP_SUBNORMAL, QUADFP_ZERO, x)
#ifndef math_opt_barrier
# define math_opt_barrier(x) \
({ __typeof (x) __x = (x); __asm ("" : "+m" (__x)); __x; })
# define math_force_eval(x) \
({ __typeof (x) __x = (x); __asm __volatile__ ("" : : "m" (__x)); })
#endif
/* math_narrow_eval reduces its floating-point argument to the range
and precision of its semantic type. (The original evaluation may
still occur with excess range and precision, so the result may be
affected by double rounding.) */
#define math_narrow_eval(x) (x)
/* If X (which is not a NaN) is subnormal, force an underflow
exception. */
#define math_check_force_underflow(x) \
do \
{ \
__float128 force_underflow_tmp = (x); \
if (fabsq (force_underflow_tmp) < FLT128_MIN) \
{ \
__float128 force_underflow_tmp2 \
= force_underflow_tmp * force_underflow_tmp; \
math_force_eval (force_underflow_tmp2); \
} \
} \
while (0)
/* Likewise, but X is also known to be nonnegative. */
#define math_check_force_underflow_nonneg(x) \
do \
{ \
__float128 force_underflow_tmp = (x); \
if (force_underflow_tmp < FLT128_MIN) \
{ \
__float128 force_underflow_tmp2 \
= force_underflow_tmp * force_underflow_tmp; \
math_force_eval (force_underflow_tmp2); \
} \
} \
while (0)
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment