예제 #1
0
FLOAT
M_DECL_FUNC (__fdim) (FLOAT x, FLOAT y)
{
  if (islessequal (x, y))
    return 0;

  FLOAT r = math_narrow_eval (x - y);
  if (isinf (r) && !isinf (x) && !isinf (y))
    __set_errno (ERANGE);

  return r;
}
예제 #2
0
float
__gamma_productf (float x, float x_eps, int n, float *eps)
{
  double x_full = (double) x + (double) x_eps;
  double ret = x_full;
  for (int i = 1; i < n; i++)
    ret *= x_full + i;

  float fret = math_narrow_eval ((float) ret);
  *eps = (ret - fret) / fret;

  return fret;
}
예제 #3
0
_Float32x
__f32xsubf64 (_Float64 x, _Float64 y)
{
  /* To avoid double rounding, set double precision for the subtraction.
     math_narrow_eval is still needed to eliminate excess range in the
     case of overflow.  If the result of the subtraction is in the
     subnormal range for double, it is exact, so no issues of double
     rounding for subnormals arise.  */
  fpu_control_t cw, cw_double;
  _FPU_GETCW (cw);
  cw_double = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
  _FPU_SETCW (cw_double);
  _Float32x ret = math_narrow_eval (x - y);
  _FPU_SETCW (cw);
  CHECK_NARROW_SUB (ret, x, y);
  return ret;
}
예제 #4
0
float
__exp2f (float x)
{
  uint32_t abstop;
  uint64_t ki, t;
  /* double_t for better performance on targets with FLT_EVAL_METHOD==2.  */
  double_t kd, xd, z, r, r2, y, s;

  xd = (double_t) x;
  abstop = top12 (x) & 0x7ff;
  if (__glibc_unlikely (abstop >= top12 (128.0f)))
    {
      /* |x| >= 128 or x is nan.  */
      if (asuint (x) == asuint (-INFINITY))
	return 0.0f;
      if (abstop >= top12 (INFINITY))
	return x + x;
      if (x > 0.0f)
	return __math_oflowf (0);
      if (x <= -150.0f)
	return __math_uflowf (0);
#if WANT_ERRNO_UFLOW
      if (x < -149.0f)
	return __math_may_uflowf (0);
#endif
    }

  /* x = k/N + r with r in [-1/(2N), 1/(2N)] and int k.  */
  kd = math_narrow_eval ((double) (xd + SHIFT)); /* Needs to be double.  */
  ki = asuint64 (kd);
  kd -= SHIFT; /* k/N for int k.  */
  r = xd - kd;

  /* exp2(x) = 2^(k/N) * 2^r ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */
  t = T[ki % N];
  t += ki << (52 - EXP2F_TABLE_BITS);
  s = asdouble (t);
  z = C[0] * r + C[1];
  r2 = r * r;
  y = C[2] * r + 1;
  y = z * r2 + y;
  y = y * s;
  return (float) y;
}
예제 #5
0
파일: s_fdim.c 프로젝트: kraj/glibc
double
__fdim (double x, double y)
{
    if (islessequal (x, y))
        return 0.0;

    /* To avoid double rounding, set double precision for the
       subtraction.  math_narrow_eval is still needed to eliminate
       excess range in the case of overflow.  If the result of the
       subtraction is in the subnormal range for double, it is exact, so
       no issues of double rounding for subnormals arise.  */
    fpu_control_t cw, cw_double;
    _FPU_GETCW (cw);
    cw_double = (cw & ~_FPU_EXTENDED) | _FPU_DOUBLE;
    _FPU_SETCW (cw_double);
    double r = math_narrow_eval (x - y);
    _FPU_SETCW (cw);
    if (isinf (r) && !isinf (x) && !isinf (y))
        __set_errno (ERANGE);

    return r;
}
예제 #6
0
float
__ieee754_sinhf(float x)
{
	float t,w,h;
	int32_t ix,jx;

	GET_FLOAT_WORD(jx,x);
	ix = jx&0x7fffffff;

    /* x is INF or NaN */
	if(__builtin_expect(ix>=0x7f800000, 0)) return x+x;

	h = 0.5;
	if (jx<0) h = -h;
    /* |x| in [0,22], return sign(x)*0.5*(E+E/(E+1))) */
	if (ix < 0x41b00000) {		/* |x|<22 */
	    if (__builtin_expect(ix<0x31800000, 0)) {	/* |x|<2**-28 */
		math_check_force_underflow (x);
		if(shuge+x>one) return x;/* sinh(tiny) = tiny with inexact */
	    }
	    t = __expm1f(fabsf(x));
	    if(ix<0x3f800000) return h*((float)2.0*t-t*t/(t+one));
	    return h*(t+t/(t+one));
	}

    /* |x| in [22, log(maxdouble)] return 0.5*exp(|x|) */
	if (ix < 0x42b17180)  return h*__ieee754_expf(fabsf(x));

    /* |x| in [log(maxdouble), overflowthresold] */
	if (ix<=0x42b2d4fc) {
	    w = __ieee754_expf((float)0.5*fabsf(x));
	    t = h*w;
	    return t*w;
	}

    /* |x| > overflowthresold, sinh(x) overflow */
	return math_narrow_eval (x*shuge);
}
예제 #7
0
float
__ieee754_lgammaf_r(float x, int *signgamp)
{
	float t,y,z,nadj,p,p1,p2,p3,q,r,w;
	int i,hx,ix;

	GET_FLOAT_WORD(hx,x);

    /* purge off +-inf, NaN, +-0, and negative arguments */
	*signgamp = 1;
	ix = hx&0x7fffffff;
	if(__builtin_expect(ix>=0x7f800000, 0)) return x*x;
	if(__builtin_expect(ix==0, 0))
	  {
	    if (hx < 0)
	      *signgamp = -1;
	    return one/fabsf(x);
	  }
	if(__builtin_expect(ix<0x30800000, 0)) {
	    /* |x|<2**-30, return -log(|x|) */
	    if(hx<0) {
		*signgamp = -1;
		return -__ieee754_logf(-x);
	    } else return -__ieee754_logf(x);
	}
	if(hx<0) {
	    if(ix>=0x4b000000)	/* |x|>=2**23, must be -integer */
		return x/zero;
	    if (ix > 0x40000000 /* X < 2.0f.  */
		&& ix < 0x41700000 /* X > -15.0f.  */)
		return __lgamma_negf (x, signgamp);
	    t = sin_pif(x);
	    if(t==zero) return one/fabsf(t); /* -integer */
	    nadj = __ieee754_logf(pi/fabsf(t*x));
	    if(t<zero) *signgamp = -1;
	    x = -x;
	}

    /* purge off 1 and 2 */
	if (ix==0x3f800000||ix==0x40000000) r = 0;
    /* for x < 2.0 */
	else if(ix<0x40000000) {
	    if(ix<=0x3f666666) {	/* lgamma(x) = lgamma(x+1)-log(x) */
		r = -__ieee754_logf(x);
		if(ix>=0x3f3b4a20) {y = one-x; i= 0;}
		else if(ix>=0x3e6d3308) {y= x-(tc-one); i=1;}
		else {y = x; i=2;}
	    } else {
		r = zero;
		if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */
		else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */
		else {y=x-one;i=2;}
	    }
	    switch(i) {
	      case 0:
		z = y*y;
		p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
		p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
		p  = y*p1+p2;
		r  += (p-(float)0.5*y); break;
	      case 1:
		z = y*y;
		w = z*y;
		p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12)));	/* parallel comp */
		p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
		p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
		p  = z*p1-(tt-w*(p2+y*p3));
		r += (tf + p); break;
	      case 2:
		p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
		p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
		r += (-(float)0.5*y + p1/p2);
	    }
	}
	else if(ix<0x41000000) {			/* x < 8.0 */
	    i = (int)x;
	    t = zero;
	    y = x-(float)i;
	    p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
	    q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
	    r = half*y+p/q;
	    z = one;	/* lgamma(1+s) = log(s) + lgamma(s) */
	    switch(i) {
	    case 7: z *= (y+(float)6.0);	/* FALLTHRU */
	    case 6: z *= (y+(float)5.0);	/* FALLTHRU */
	    case 5: z *= (y+(float)4.0);	/* FALLTHRU */
	    case 4: z *= (y+(float)3.0);	/* FALLTHRU */
	    case 3: z *= (y+(float)2.0);	/* FALLTHRU */
		    r += __ieee754_logf(z); break;
	    }
    /* 8.0 <= x < 2**26 */
	} else if (ix < 0x4c800000) {
	    t = __ieee754_logf(x);
	    z = one/x;
	    y = z*z;
	    w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
	    r = (x-half)*(t-one)+w;
	} else
    /* 2**26 <= x <= inf */
	    r =  math_narrow_eval (x*(__ieee754_logf(x)-one));
	/* NADJ is set for negative arguments but not otherwise,
	   resulting in warnings that it may be used uninitialized
	   although in the cases where it is used it has always been
	   set.  */
	DIAG_PUSH_NEEDS_COMMENT;
#if __GNUC_PREREQ (4, 7)
	DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wmaybe-uninitialized");
#else
	DIAG_IGNORE_NEEDS_COMMENT (4.9, "-Wuninitialized");
#endif
	if(hx<0) r = nadj - r;
	DIAG_POP_NEEDS_COMMENT;
	return r;
}
예제 #8
0
double
__ieee754_j1 (double x)
{
  double z, s, c, ss, cc, r, u, v, y, r1, r2, s1, s2, s3, z2, z4;
  int32_t hx, ix;

  GET_HIGH_WORD (hx, x);
  ix = hx & 0x7fffffff;
  if (__glibc_unlikely (ix >= 0x7ff00000))
    return one / x;
  y = fabs (x);
  if (ix >= 0x40000000)         /* |x| >= 2.0 */
    {
      __sincos (y, &s, &c);
      ss = -s - c;
      cc = s - c;
      if (ix < 0x7fe00000)           /* make sure y+y not overflow */
	{
	  z = __cos (y + y);
	  if ((s * c) > zero)
	    cc = z / ss;
	  else
	    ss = z / cc;
	}
      /*
       * j1(x) = 1/sqrt(pi) * (P(1,x)*cc - Q(1,x)*ss) / sqrt(x)
       * y1(x) = 1/sqrt(pi) * (P(1,x)*ss + Q(1,x)*cc) / sqrt(x)
       */
      if (ix > 0x48000000)
	z = (invsqrtpi * cc) / sqrt (y);
      else
	{
	  u = pone (y); v = qone (y);
	  z = invsqrtpi * (u * cc - v * ss) / sqrt (y);
	}
      if (hx < 0)
	return -z;
      else
	return z;
    }
  if (__glibc_unlikely (ix < 0x3e400000))                  /* |x|<2**-27 */
    {
      if (huge + x > one)                 /* inexact if x!=0 necessary */
	{
	  double ret = math_narrow_eval (0.5 * x);
	  math_check_force_underflow (ret);
	  if (ret == 0 && x != 0)
	    __set_errno (ERANGE);
	  return ret;
	}
    }
  z = x * x;
  r1 = z * R[0]; z2 = z * z;
  r2 = R[1] + z * R[2]; z4 = z2 * z2;
  r = r1 + z2 * r2 + z4 * R[3];
  r *= x;
  s1 = one + z * S[1];
  s2 = S[2] + z * S[3];
  s3 = S[4] + z * S[5];
  s = s1 + z2 * s2 + z4 * s3;
  return (x * 0.5 + r / s);
}
예제 #9
0
static float
gammaf_positive (float x, int *exp2_adj)
{
  int local_signgam;
  if (x < 0.5f)
    {
      *exp2_adj = 0;
      return __ieee754_expf (__ieee754_lgammaf_r (x + 1, &local_signgam)) / x;
    }
  else if (x <= 1.5f)
    {
      *exp2_adj = 0;
      return __ieee754_expf (__ieee754_lgammaf_r (x, &local_signgam));
    }
  else if (x < 2.5f)
    {
      *exp2_adj = 0;
      float x_adj = x - 1;
      return (__ieee754_expf (__ieee754_lgammaf_r (x_adj, &local_signgam))
	      * x_adj);
    }
  else
    {
      float eps = 0;
      float x_eps = 0;
      float x_adj = x;
      float prod = 1;
      if (x < 4.0f)
	{
	  /* Adjust into the range for applying Stirling's
	     approximation.  */
	  float n = __ceilf (4.0f - x);
	  x_adj = math_narrow_eval (x + n);
	  x_eps = (x - (x_adj - n));
	  prod = __gamma_productf (x_adj - n, x_eps, n, &eps);
	}
      /* The result is now gamma (X_ADJ + X_EPS) / (PROD * (1 + EPS)).
	 Compute gamma (X_ADJ + X_EPS) using Stirling's approximation,
	 starting by computing pow (X_ADJ, X_ADJ) with a power of 2
	 factored out.  */
      float exp_adj = -eps;
      float x_adj_int = __roundf (x_adj);
      float x_adj_frac = x_adj - x_adj_int;
      int x_adj_log2;
      float x_adj_mant = __frexpf (x_adj, &x_adj_log2);
      if (x_adj_mant < (float) M_SQRT1_2)
	{
	  x_adj_log2--;
	  x_adj_mant *= 2.0f;
	}
      *exp2_adj = x_adj_log2 * (int) x_adj_int;
      float ret = (__ieee754_powf (x_adj_mant, x_adj)
		   * __ieee754_exp2f (x_adj_log2 * x_adj_frac)
		   * __ieee754_expf (-x_adj)
		   * __ieee754_sqrtf (2 * (float) M_PI / x_adj)
		   / prod);
      exp_adj += x_eps * __ieee754_logf (x_adj);
      float bsum = gamma_coeff[NCOEFF - 1];
      float x_adj2 = x_adj * x_adj;
      for (size_t i = 1; i <= NCOEFF - 1; i++)
	bsum = bsum / x_adj2 + gamma_coeff[NCOEFF - 1 - i];
      exp_adj += bsum / x_adj;
      return ret + ret * __expm1f (exp_adj);
    }
}
예제 #10
0
float
__ieee754_gammaf_r (float x, int *signgamp)
{
  int32_t hx;
  float ret;

  GET_FLOAT_WORD (hx, x);

  if (__glibc_unlikely ((hx & 0x7fffffff) == 0))
    {
      /* Return value for x == 0 is Inf with divide by zero exception.  */
      *signgamp = 0;
      return 1.0 / x;
    }
  if (__builtin_expect (hx < 0, 0)
      && (u_int32_t) hx < 0xff800000 && __rintf (x) == x)
    {
      /* Return value for integer x < 0 is NaN with invalid exception.  */
      *signgamp = 0;
      return (x - x) / (x - x);
    }
  if (__glibc_unlikely (hx == 0xff800000))
    {
      /* x == -Inf.  According to ISO this is NaN.  */
      *signgamp = 0;
      return x - x;
    }
  if (__glibc_unlikely ((hx & 0x7f800000) == 0x7f800000))
    {
      /* Positive infinity (return positive infinity) or NaN (return
	 NaN).  */
      *signgamp = 0;
      return x + x;
    }

  if (x >= 36.0f)
    {
      /* Overflow.  */
      *signgamp = 0;
      ret = math_narrow_eval (FLT_MAX * FLT_MAX);
      return ret;
    }
  else
    {
      SET_RESTORE_ROUNDF (FE_TONEAREST);
      if (x > 0.0f)
	{
	  *signgamp = 0;
	  int exp2_adj;
	  float tret = gammaf_positive (x, &exp2_adj);
	  ret = __scalbnf (tret, exp2_adj);
	}
      else if (x >= -FLT_EPSILON / 4.0f)
	{
	  *signgamp = 0;
	  ret = 1.0f / x;
	}
      else
	{
	  float tx = __truncf (x);
	  *signgamp = (tx == 2.0f * __truncf (tx / 2.0f)) ? -1 : 1;
	  if (x <= -42.0f)
	    /* Underflow.  */
	    ret = FLT_MIN * FLT_MIN;
	  else
	    {
	      float frac = tx - x;
	      if (frac > 0.5f)
		frac = 1.0f - frac;
	      float sinpix = (frac <= 0.25f
			      ? __sinf ((float) M_PI * frac)
			      : __cosf ((float) M_PI * (0.5f - frac)));
	      int exp2_adj;
	      float tret = (float) M_PI / (-x * sinpix
					   * gammaf_positive (-x, &exp2_adj));
	      ret = __scalbnf (tret, -exp2_adj);
	      math_check_force_underflow_nonneg (ret);
	    }
	}
      ret = math_narrow_eval (ret);
    }
  if (isinf (ret) && x != 0)
    {
      if (*signgamp < 0)
	{
	  ret = math_narrow_eval (-__copysignf (FLT_MAX, ret) * FLT_MAX);
	  ret = -ret;
	}
      else
	ret = math_narrow_eval (__copysignf (FLT_MAX, ret) * FLT_MAX);
      return ret;
    }
  else if (ret == 0)
    {
      if (*signgamp < 0)
	{
	  ret = math_narrow_eval (-__copysignf (FLT_MIN, ret) * FLT_MIN);
	  ret = -ret;
	}
      else
	ret = math_narrow_eval (__copysignf (FLT_MIN, ret) * FLT_MIN);
      return ret;
    }
  else
    return ret;
}
예제 #11
0
float
__lgamma_negf (float x, int *signgamp)
{
  /* Determine the half-integer region X lies in, handle exact
     integers and determine the sign of the result.  */
  int i = __floorf (-2 * x);
  if ((i & 1) == 0 && i == -2 * x)
    return 1.0f / 0.0f;
  float xn = ((i & 1) == 0 ? -i / 2 : (-i - 1) / 2);
  i -= 4;
  *signgamp = ((i & 2) == 0 ? -1 : 1);

  SET_RESTORE_ROUNDF (FE_TONEAREST);

  /* Expand around the zero X0 = X0_HI + X0_LO.  */
  float x0_hi = lgamma_zeros[i][0], x0_lo = lgamma_zeros[i][1];
  float xdiff = x - x0_hi - x0_lo;

  /* For arguments in the range -3 to -2, use polynomial
     approximations to an adjusted version of the gamma function.  */
  if (i < 2)
    {
      int j = __floorf (-8 * x) - 16;
      float xm = (-33 - 2 * j) * 0.0625f;
      float x_adj = x - xm;
      size_t deg = poly_deg[j];
      size_t end = poly_end[j];
      float g = poly_coeff[end];
      for (size_t j = 1; j <= deg; j++)
	g = g * x_adj + poly_coeff[end - j];
      return __log1pf (g * xdiff / (x - xn));
    }

  /* The result we want is log (sinpi (X0) / sinpi (X))
     + log (gamma (1 - X0) / gamma (1 - X)).  */
  float x_idiff = fabsf (xn - x), x0_idiff = fabsf (xn - x0_hi - x0_lo);
  float log_sinpi_ratio;
  if (x0_idiff < x_idiff * 0.5f)
    /* Use log not log1p to avoid inaccuracy from log1p of arguments
       close to -1.  */
    log_sinpi_ratio = __ieee754_logf (lg_sinpi (x0_idiff)
				      / lg_sinpi (x_idiff));
  else
    {
      /* Use log1p not log to avoid inaccuracy from log of arguments
	 close to 1.  X0DIFF2 has positive sign if X0 is further from
	 XN than X is from XN, negative sign otherwise.  */
      float x0diff2 = ((i & 1) == 0 ? xdiff : -xdiff) * 0.5f;
      float sx0d2 = lg_sinpi (x0diff2);
      float cx0d2 = lg_cospi (x0diff2);
      log_sinpi_ratio = __log1pf (2 * sx0d2
				  * (-sx0d2 + cx0d2 * lg_cotpi (x_idiff)));
    }

  float log_gamma_ratio;
  float y0 = math_narrow_eval (1 - x0_hi);
  float y0_eps = -x0_hi + (1 - y0) - x0_lo;
  float y = math_narrow_eval (1 - x);
  float y_eps = -x + (1 - y);
  /* We now wish to compute LOG_GAMMA_RATIO
     = log (gamma (Y0 + Y0_EPS) / gamma (Y + Y_EPS)).  XDIFF
     accurately approximates the difference Y0 + Y0_EPS - Y -
     Y_EPS.  Use Stirling's approximation.  */
  float log_gamma_high
    = (xdiff * __log1pf ((y0 - e_hi - e_lo + y0_eps) / e_hi)
       + (y - 0.5f + y_eps) * __log1pf (xdiff / y));
  /* Compute the sum of (B_2k / 2k(2k-1))(Y0^-(2k-1) - Y^-(2k-1)).  */
  float y0r = 1 / y0, yr = 1 / y;
  float y0r2 = y0r * y0r, yr2 = yr * yr;
  float rdiff = -xdiff / (y * y0);
  float bterm[NCOEFF];
  float dlast = rdiff, elast = rdiff * yr * (yr + y0r);
  bterm[0] = dlast * lgamma_coeff[0];
  for (size_t j = 1; j < NCOEFF; j++)
    {
      float dnext = dlast * y0r2 + elast;
      float enext = elast * yr2;
      bterm[j] = dnext * lgamma_coeff[j];
      dlast = dnext;
      elast = enext;
    }
  float log_gamma_low = 0;
  for (size_t j = 0; j < NCOEFF; j++)
    log_gamma_low += bterm[NCOEFF - 1 - j];
  log_gamma_ratio = log_gamma_high + log_gamma_low;

  return log_sinpi_ratio + log_gamma_ratio;
}