Esempio n. 1
0
File: utils.c Progetto: Enlik/mlt
void HSItoRGB(double H, double S, double I, int *r, int *g, int *b)
{
	double T,Rv,Gv,Bv;

	Rv=1+S*sin(H-2*M_PI/3);
	Gv=1+S*sin(H);
	Bv=1+S*sin(H+2*M_PI/3);
	T=255.999*I/2;
	*r=itrunc(Rv*T);
	*g=itrunc(Gv*T);
	*b=itrunc(Bv*T);
}
Esempio n. 2
0
T cos_pi_imp(T x, const Policy& pol)
{
   BOOST_MATH_STD_USING // ADL of std names
   // cos of pi*x:
   bool invert = false;
   if(x < 0.5)
      return cos(constants::pi<T>() * x);
   if(x < 1)
   {
      x = -x;
   }

   T rem = floor(x);
   if(itrunc(rem, pol) & 1)
      invert = !invert;
   rem = x - rem;
   if(rem > 0.5f)
   {
      rem = 1 - rem;
      invert = !invert;
   }
   if(rem == 0.5f)
      return 0;
   
   rem = cos(constants::pi<T>() * rem);
   return invert ? T(-rem) : rem;
}
Esempio n. 3
0
/* 
 * release an inode.
 * decrease the reference count, write updates to disk if nessary.
 * also check the link count, if zero, trucate it.
 * */
void iput(struct inode *ip){
    ushort dev;

    if(ip==NULL)
        panic("bad struct inode*");
    ip->i_flag |= I_LOCK;
    if (ip->i_count > 0) {
        ip->i_count--;
    }
    if (ip->i_count==0){
        if (ip->i_nlink==0) {
            itrunc(ip);
            ifree(ip->i_dev, ip->i_num);
        }
        // if it's a device file, the dev number is stored in zone[0].
        dev = ip->i_zone[0];
        switch (ip->i_mode & S_IFMT) {
            case S_IFBLK:
                (*bdevsw[MAJOR(dev)].d_close)(dev);
                break;
            case S_IFCHR:
                (*cdevsw[MAJOR(dev)].d_close)(dev);
                break;
        }
        iupdate(ip);
        ip->i_flag = 0;
        ip->i_num = 0;
    }
    unlk_ino(ip);
}
Esempio n. 4
0
inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
{
   BOOST_STATIC_ASSERT(!boost::is_integral<T>::value);
   BOOST_MATH_STD_USING // ADL of std names
   if((x == 0) && (n >= 0))
      return 0;
   if(x < 0)
   {
      //
      // For x < 0 we really have a rising factorial
      // modulo a possible change of sign:
      //
      return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol);
   }
   if(n == 0)
      return 1;
   if(x < 0.5f)
   {
      //
      // 1 + x below will throw away digits, so split up calculation:
      //
      if(n > max_factorial<T>::value - 2)
      {
         // If the two end of the range are far apart we have a ratio of two very large
         // numbers, split the calculation up into two blocks:
         T t1 = x * boost::math::falling_factorial(x - 1, max_factorial<T>::value - 2);
         T t2 = boost::math::falling_factorial(x - max_factorial<T>::value + 1, n - max_factorial<T>::value + 1);
         if(tools::max_value<T>() / fabs(t1) < fabs(t2))
            return boost::math::sign(t1) * boost::math::sign(t2) * policies::raise_overflow_error<T>("boost::math::falling_factorial<%1%>", 0, pol);
         return t1 * t2;
      }
      return x * boost::math::falling_factorial(x - 1, n - 1);
   }
   if(x <= n - 1)
   {
      //
      // x+1-n will be negative and tgamma_delta_ratio won't
      // handle it, split the product up into three parts:
      //
      T xp1 = x + 1;
      unsigned n2 = itrunc((T)floor(xp1), pol);
      if(n2 == xp1)
         return 0;
      T result = boost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
      x -= n2;
      result *= x;
      ++n2;
      if(n2 < n)
         result *= falling_factorial(x - 1, n - n2, pol);
      return result;
   }
   //
   // Simple case: just the ratio of two
   // (positive argument) gamma functions.
   // Note that we don't optimise this for small n,
   // because tgamma_delta_ratio is alreay optimised
   // for that use case:
   //
   return boost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
}
Esempio n. 5
0
inline T cyl_bessel_j_prime_imp(T v, T x, const Policy& pol)
{
   static const char* const function = "boost::math::cyl_bessel_j_prime<%1%>(%1%,%1%)";
   BOOST_MATH_STD_USING
   //
   // Prevent complex result:
   //
   if (x < 0 && floor(v) != v)
      return boost::math::policies::raise_domain_error<T>(
         function,
         "Got x = %1%, but function requires x >= 0", x, pol);
   //
   // Special cases for x == 0:
   //
   if (x == 0)
   {
      if (v == 1)
         return 0.5;
      else if (v == -1)
         return -0.5;
      else if (floor(v) == v || v > 1)
         return 0;
      else return boost::math::policies::raise_domain_error<T>(
         function,
         "Got x = %1%, but function is indeterminate for this order", x, pol);
   }
   //
   // Special case for large x: use asymptotic expansion:
   //
   if (boost::math::detail::asymptotic_bessel_derivative_large_x_limit(v, x))
      return boost::math::detail::asymptotic_bessel_j_derivative_large_x_2(v, x);
   //
   // Special case for small x: use Taylor series:
   //
   if ((abs(x) < 5) || (abs(v) > x * x / 4))
   {
      bool inversed = false;
      if (floor(v) == v && v < 0)
      {
         v = -v;
         if (itrunc(v, pol) & 1)
            inversed = true;
      }
      T r = boost::math::detail::bessel_j_derivative_small_z_series(v, x, pol);
      return inversed ? T(-r) : r;
   }
   //
   // Special case for v == 0:
   //
   if (v == 0)
      return -boost::math::detail::cyl_bessel_j_imp<T>(1, x, Tag(), pol);
   //
   // Default case:
   //
   return boost::math::detail::bessel_j_derivative_linear(v, x, Tag(), pol);
}
Esempio n. 6
0
T float_advance(T val, int distance, const Policy& pol)
{
   //
   // Error handling:
   //
   static const char* function = "float_advance<%1%>(%1%, int)";
   if(!(boost::math::isfinite)(val))
      return policies::raise_domain_error<T>(
         function,
         "Argument val must be finite, but got %1%", val, pol);

   if(val < 0)
      return -float_advance(-val, -distance, pol);
   if(distance == 0)
      return val;
   if(distance == 1)
      return float_next(val, pol);
   if(distance == -1)
      return float_prior(val, pol);
   BOOST_MATH_STD_USING
   int expon;
   frexp(val, &expon);
   T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon);
   if(val <= tools::min_value<T>())
   {
      limit = sign(T(distance)) * tools::min_value<T>();
   }
   T limit_distance = float_distance(val, limit);
   while(fabs(limit_distance) < abs(distance))
   {
      distance -= itrunc(limit_distance);
      val = limit;
      if(distance < 0) 
      {
         limit /= 2;
         expon--;
      }
      else
      {
         limit *= 2;
         expon++;
      }
      limit_distance = float_distance(val, limit);
   }
   if((0.5f == frexp(val, &expon)) && (distance < 0))
      --expon;
   T diff = 0;
   if(val != 0)
      diff = distance * ldexp(T(1), expon - tools::digits<T>());
   if(diff == 0)
      diff = distance * detail::get_smallest_value<T>();
   return val += diff;
}
 inline RealType cdf(const complemented2_type<hypergeometric_distribution<RealType, Policy>, U>& c)
 {
    BOOST_MATH_STD_USING
    static const char* function = "boost::math::cdf(const hypergeometric_distribution<%1%>&, const %1%&)";
    RealType r = static_cast<RealType>(c.param);
    unsigned u = itrunc(r, typename policies::normalise<Policy, policies::rounding_error<policies::ignore_error> >::type());
    if(u != r)
    {
       return boost::math::policies::raise_domain_error<RealType>(
          function, "Random variable out of range: must be an integer but got %1%", r, Policy());
    }
    return cdf(complement(c.dist, u));
 }
Esempio n. 8
0
/*
 * open a file. flag indicated opened type like O_RDONLY, O_TRUNC, O_CREAT and blah. And 
 * mode only used in the O_CREAT scenary, indicated the file (inode) type.
 *
 * each proc has got one user file table(p_ofile[NOFILE]), it's each entry is also a number,
 * indicated the number in the system file table(file[NFILE]). when user opened a file, it 
 * first allocate a user file table entry(aka. file descriptor), then attach it with a system
 * file table entry. It's reference count is increased in fork() or dup().
 * */
int do_open(char *path, uint flag, uint mode){
    struct inode *ip;
    struct file *fp;
    ushort dev;
    int fd;

    // on create a new file.
    if (flag & O_CREAT){
        ip = namei(path, 1);
        // if file is not existing yet.
        if (ip->i_nlink==0) {
            ip->i_mode = mode;
            ip->i_uid = cu->p_euid;
            ip->i_gid = cu->p_egid;
            ip->i_mtime = time();
            ip->i_nlink = 1;
            iupdate(ip);
        }
    }
    // an existing file.
    else {
        ip = namei(path, 0);
        if (ip == NULL){
            syserr(ENFILE);
            return -1;
        }
        // TODO: check access 
        // if it's a device file, the dev number is stored in zone[0].
        dev = ip->i_zone[0];
        switch(ip->i_mode & S_IFMT) {
            case S_IFBLK:
                (*bdevsw[MAJOR(dev)].d_open)(dev);
                break;
            case S_IFCHR:
                (*cdevsw[MAJOR(dev)].d_open)(dev);
                break;
        }
    } 
    if (((fd=ufalloc())<0) || (fp=falloc(fd))==NULL) {
        iput(ip);
        return -1;
    }
    if (flag & O_TRUNC){
        itrunc(ip);
    }
    unlk_ino(ip);
    fp->f_oflag = flag;
    fp->f_ino = ip;
    cu->p_fdflag[fd] = FD_CLOEXEC;
    return fd;
}
Esempio n. 9
0
/* reference of ip - 1 
 * if it is the last ref, this node can be recycle (ref = 1) (?)
 * and if this inode have no link to it (nlinks = 0)
 * free this inode in the disk
 */
void iput(struct inode *ip) {
    if (ip->ref == 1 && ip->flags & I_VALID && ip->nlinks == 0) {
    
        /* can not free a locked inode */
        ip->flags |= I_BUSY;
        itrunc(ip);

        _ifree(ip->dev, ip->ino);

        // ip-> ref == 0
        // ip->flags = 0;
    }
    ip->ref--;
}
Esempio n. 10
0
T gamma_imp(T z, const Policy& pol, const lanczos::undefined_lanczos& l)
{
   static const char* function = "boost::math::tgamma<%1%>(%1%)";
   BOOST_MATH_STD_USING
   if((z <= 0) && (floor(z) == z))
      return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
   if(z <= -20)
   {
      T result = gamma_imp(-z, pol, l) * sinpx(z);
      if((fabs(result) < 1) && (tools::max_value<T>() * fabs(result) < boost::math::constants::pi<T>()))
         return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
      result = -boost::math::constants::pi<T>() / result;
      if(result == 0)
         return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
      if((boost::math::fpclassify)(result) == (int)FP_SUBNORMAL)
         return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
      return result;
   }
   //
   // The upper gamma fraction is *very* slow for z < 6, actually it's very
   // slow to converge everywhere but recursing until z > 6 gets rid of the
   // worst of it's behaviour.
   //
   T prefix = 1;
   while(z < 6)
   {
      prefix /= z;
      z += 1;
   }
   BOOST_MATH_INSTRUMENT_CODE(prefix);
   if((floor(z) == z) && (z < max_factorial<T>::value))
   {
      prefix *= unchecked_factorial<T>(itrunc(z, pol) - 1);
   }
   else
   {
      prefix = prefix * pow(z / boost::math::constants::e<T>(), z);
      BOOST_MATH_INSTRUMENT_CODE(prefix);
      T sum = detail::lower_gamma_series(z, z, pol) / z;
      BOOST_MATH_INSTRUMENT_CODE(sum);
      sum += detail::upper_gamma_fraction(z, z, ::boost::math::policies::digits<T, Policy>());
      BOOST_MATH_INSTRUMENT_CODE(sum);
      if(fabs(tools::max_value<T>() / prefix) < fabs(sum))
         return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
      BOOST_MATH_INSTRUMENT_CODE((sum * prefix));
      return sum * prefix;
   }
   return prefix;
}
Esempio n. 11
0
/*
 * Drop a reference to an in-memory inode. If that was the last reference, the
 * inode cache entry can be recycled.
 *
 * If that was the last reference and the inode has no links to it, free the
 * inode (and its content) on disk.
 */
void iput(struct inode *ip)
{
	acquire(&icache.lock);
	if (ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0) {
		/* inode has no links: truncate and free inode. */
		if (ip->flags & I_BUSY)
			panic("iput busy");
		ip->flags |= I_BUSY;
		release(&icache.lock);
		itrunc(ip);
		ip->type = 0;
		iupdate(ip);
		acquire(&icache.lock);
		ip->flags = 0;
		wakeup(ip);
	}
	ip->ref--;
	release(&icache.lock);
}
Esempio n. 12
0
inline T falling_factorial_imp(T x, unsigned n, const Policy& pol)
{
   BOOST_STATIC_ASSERT(!lslboost::is_integral<T>::value);
   BOOST_MATH_STD_USING // ADL of std names
   if(x == 0)
      return 0;
   if(x < 0)
   {
      //
      // For x < 0 we really have a rising factorial
      // modulo a possible change of sign:
      //
      return (n&1 ? -1 : 1) * rising_factorial(-x, n, pol);
   }
   if(n == 0)
      return 1;
   if(x < n-1)
   {
      //
      // x+1-n will be negative and tgamma_delta_ratio won't
      // handle it, split the product up into three parts:
      //
      T xp1 = x + 1;
      unsigned n2 = itrunc((T)floor(xp1), pol);
      if(n2 == xp1)
         return 0;
      T result = lslboost::math::tgamma_delta_ratio(xp1, -static_cast<T>(n2), pol);
      x -= n2;
      result *= x;
      ++n2;
      if(n2 < n)
         result *= falling_factorial(x - 1, n - n2, pol);
      return result;
   }
   //
   // Simple case: just the ratio of two
   // (positive argument) gamma functions.
   // Note that we don't optimise this for small n,
   // because tgamma_delta_ratio is alreay optimised
   // for that use case:
   //
   return lslboost::math::tgamma_delta_ratio(x + 1, -static_cast<T>(n), pol);
}
Esempio n. 13
0
// Drop a reference to an in-memory inode.
// If that was the last reference, the inode cache entry can
// be recycled.
// If that was the last reference and the inode has no links
// to it, free the inode (and its content) on disk.
// All calls to iput() must be inside a transaction in
// case it has to free the inode.
void iput(struct inode* ip)
{
    // cprintf("iput  %d \n",ip->inum);

    acquire(&icache.lock);
    if (ip->ref == 1 && (ip->flags & I_VALID) && ip->nlink == 0) {
        // inode has no links and no other references: truncate and free.
        if (ip->flags & I_BUSY)
            panic("iput busy");
        ip->flags |= I_BUSY;
        release(&icache.lock);
        itrunc(ip);
        ip->type = 0;
        iupdate(ip);
        acquire(&icache.lock);
        ip->flags = 0;
        wakeup(ip);
    }
    ip->ref--;
    release(&icache.lock);
}
Esempio n. 14
0
         T non_central_t2_p(T v, T delta, T x, T y, const Policy& pol, T init_val)
         {
            BOOST_MATH_STD_USING
            //
            // Variables come first:
            //
            boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
            T errtol = policies::get_epsilon<T, Policy>();
            T d2 = delta * delta / 2;
            //
            // k is the starting point for iteration, and is the
            // maximum of the poisson weighting term, we don't
            // ever allow k == 0 as this can lead to catastrophic
            // cancellation errors later (test case is v = 1621286869049072.3
            // delta = 0.16212868690490723, x = 0.86987415482475994).
            //
            int k = itrunc(d2);
            T pois;
            if(k == 0) k = 1;
            // Starting Poisson weight:
            pois = gamma_p_derivative(T(k+1), d2, pol) 
               * tgamma_delta_ratio(T(k + 1), T(0.5f))
               * delta / constants::root_two<T>();
            if(pois == 0)
               return init_val;
            T xterm, beta;
            // Recurrance & starting beta terms:
            beta = x < y
               ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, false, true, &xterm)
               : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, true, true, &xterm);
            xterm *= y / (v / 2 + k);
            T poisf(pois), betaf(beta), xtermf(xterm);
            T sum = init_val;
            if((xterm == 0) && (beta == 0))
               return init_val;

            //
            // Backwards recursion first, this is the stable
            // direction for recursion:
            //
            boost::uintmax_t count = 0;
            T last_term = 0;
            for(int i = k; i >= 0; --i)
            {
               T term = beta * pois;
               sum += term;
               // Don't terminate on first term in case we "fixed" k above:
               if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol)
                  break;
               last_term = term;
               pois *= (i + 0.5f) / d2;
               beta += xterm;
               xterm *= (i) / (x * (v / 2 + i - 1));
               ++count;
            }
            last_term = 0;
            for(int i = k + 1; ; ++i)
            {
               poisf *= d2 / (i + 0.5f);
               xtermf *= (x * (v / 2 + i - 1)) / (i);
               betaf -= xtermf;
               T term = poisf * betaf;
               sum += term;
               if((fabs(last_term) > fabs(term)) && (fabs(term/sum) < errtol))
                  break;
               last_term = term;
               ++count;
               if(count > max_iter)
               {
                  return policies::raise_evaluation_error(
                     "cdf(non_central_t_distribution<%1%>, %1%)", 
                     "Series did not converge, closest value was %1%", sum, pol);
               }
            }
            return sum;
         }
Esempio n. 15
0
         T non_central_t2_q(T v, T delta, T x, T y, const Policy& pol, T init_val)
         {
            BOOST_MATH_STD_USING
            //
            // Variables come first:
            //
            boost::uintmax_t max_iter = policies::get_max_series_iterations<Policy>();
            T errtol = boost::math::policies::get_epsilon<T, Policy>();
            T d2 = delta * delta / 2;
            //
            // k is the starting point for iteration, and is the
            // maximum of the poisson weighting term, we don't allow
            // k == 0 as this can cause catastrophic cancellation errors
            // (test case is v = 561908036470413.25, delta = 0.056190803647041321,
            // x = 1.6155232703966216):
            //
            int k = itrunc(d2);
            if(k == 0) k = 1;
            // Starting Poisson weight:
            T pois;
            if((k < (int)(max_factorial<T>::value)) && (d2 < tools::log_max_value<T>()) && (log(d2) * k < tools::log_max_value<T>()))
            {
               //
               // For small k we can optimise this calculation by using
               // a simpler reduced formula:
               //
               pois = exp(-d2);
               pois *= pow(d2, static_cast<T>(k));
               pois /= boost::math::tgamma(T(k + 1 + 0.5), pol);
               pois *= delta / constants::root_two<T>();
            }
            else
            {
               pois = gamma_p_derivative(T(k+1), d2, pol) 
                  * tgamma_delta_ratio(T(k + 1), T(0.5f))
                  * delta / constants::root_two<T>();
            }
            if(pois == 0)
               return init_val;
            // Recurance term:
            T xterm;
            T beta;
            // Starting beta term:
            if(k != 0)
            {
               beta = x < y 
                  ? detail::ibeta_imp(T(k + 1), T(v / 2), x, pol, true, true, &xterm) 
                  : detail::ibeta_imp(T(v / 2), T(k + 1), y, pol, false, true, &xterm);

               xterm *= y / (v / 2 + k);
            }
            else
            {
               beta = pow(y, v / 2);
               xterm = beta;
            }
            T poisf(pois), betaf(beta), xtermf(xterm);
            T sum = init_val;
            if((xterm == 0) && (beta == 0))
               return init_val;

            //
            // Fused forward and backwards recursion:
            //
            boost::uintmax_t count = 0;
            T last_term = 0;
            for(int i = k + 1, j = k; ; ++i, --j)
            {
               poisf *= d2 / (i + 0.5f);
               xtermf *= (x * (v / 2 + i - 1)) / (i);
               betaf += xtermf;
               T term = poisf * betaf;

               if(j >= 0)
               {
                  term += beta * pois;
                  pois *= (j + 0.5f) / d2;
                  beta -= xterm;
                  xterm *= (j) / (x * (v / 2 + j - 1));
               }

               sum += term;
               // Don't terminate on first term in case we "fixed" the value of k above:
               if((fabs(last_term) > fabs(term)) && fabs(term/sum) < errtol)
                  break;
               last_term = term;
               if(count > max_iter)
               {
                  return policies::raise_evaluation_error(
                     "cdf(non_central_t_distribution<%1%>, %1%)", 
                     "Series did not converge, closest value was %1%", sum, pol);
               }
               ++count;
            }
            return sum;
         }
inline T modf(const T& v, int* ipart, const Policy& pol)
{
   *ipart = itrunc(v, pol);
   return v - *ipart;
}
Esempio n. 17
0
inline int itrunc(const T& v)
{
   return itrunc(v, policies::policy<>());
}
Esempio n. 18
0
inline int itrunc(__gmp_expr<T,U> const& x, const Policy& pol)
{
   return itrunc(static_cast<mpfr_class>(x), pol);
}
Esempio n. 19
0
T float_advance(T val, int distance, const Policy& pol)
{
   BOOST_MATH_STD_USING
   //
   // Error handling:
   //
   static const char* function = "float_advance<%1%>(%1%, int)";

   int fpclass = (pdalboost::math::fpclassify)(val);

   if((fpclass == FP_NAN) || (fpclass == FP_INFINITE))
      return policies::raise_domain_error<T>(
         function,
         "Argument val must be finite, but got %1%", val, pol);

   if(val < 0)
      return -float_advance(-val, -distance, pol);
   if(distance == 0)
      return val;
   if(distance == 1)
      return float_next(val, pol);
   if(distance == -1)
      return float_prior(val, pol);

   if(fabs(val) < detail::get_min_shift_value<T>())
   {
      //
      // Special case: if the value of the least significant bit is a denorm, 
      // implement in terms of float_next/float_prior.
      // This avoids issues with the Intel SSE2 registers when the FTZ or DAZ flags are set.
      //
      if(distance > 0)
      {
         do{ val = float_next(val, pol); } while(--distance);
      }
      else
      {
         do{ val = float_prior(val, pol); } while(++distance);
      }
      return val;
   }

   int expon;
   frexp(val, &expon);
   T limit = ldexp((distance < 0 ? T(0.5f) : T(1)), expon);
   if(val <= tools::min_value<T>())
   {
      limit = sign(T(distance)) * tools::min_value<T>();
   }
   T limit_distance = float_distance(val, limit);
   while(fabs(limit_distance) < abs(distance))
   {
      distance -= itrunc(limit_distance);
      val = limit;
      if(distance < 0) 
      {
         limit /= 2;
         expon--;
      }
      else
      {
         limit *= 2;
         expon++;
      }
      limit_distance = float_distance(val, limit);
      if(distance && (limit_distance == 0))
      {
         policies::raise_evaluation_error<T>(function, "Internal logic failed while trying to increment floating point value %1%: most likely your FPU is in non-IEEE conforming mode.", val, pol);
      }
   }
   if((0.5f == frexp(val, &expon)) && (distance < 0))
      --expon;
   T diff = 0;
   if(val != 0)
      diff = distance * ldexp(T(1), expon - tools::digits<T>());
   if(diff == 0)
      diff = distance * detail::get_smallest_value<T>();
   return val += diff;
}
Esempio n. 20
0
T gamma_imp(T z, const Policy& pol, const L& l)
{
   BOOST_MATH_STD_USING

   T result = 1;

#ifdef BOOST_MATH_INSTRUMENT
   static bool b = false;
   if(!b)
   {
      std::cout << "tgamma_imp called with " << typeid(z).name() << " " << typeid(l).name() << std::endl;
      b = true;
   }
#endif
   static const char* function = "boost::math::tgamma<%1%>(%1%)";

   if(z <= 0)
   {
      if(floor(z) == z)
         return policies::raise_pole_error<T>(function, "Evaluation of tgamma at a negative integer %1%.", z, pol);
      if(z <= -20)
      {
         result = gamma_imp(-z, pol, l) * sinpx(z);
         if((fabs(result) < 1) && (tools::max_value<T>() * fabs(result) < boost::math::constants::pi<T>()))
            return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
         result = -boost::math::constants::pi<T>() / result;
         if(result == 0)
            return policies::raise_underflow_error<T>(function, "Result of tgamma is too small to represent.", pol);
         if((boost::math::fpclassify)(result) == (int)FP_SUBNORMAL)
            return policies::raise_denorm_error<T>(function, "Result of tgamma is denormalized.", result, pol);
         return result;
      }

      // shift z to > 1:
      while(z < 0)
      {
         result /= z;
         z += 1;
      }
   }
   if((floor(z) == z) && (z < max_factorial<T>::value))
   {
      result *= unchecked_factorial<T>(itrunc(z, pol) - 1);
   }
   else
   {
      result *= L::lanczos_sum(z);
      if(z * log(z) > tools::log_max_value<T>())
      {
         // we're going to overflow unless this is done with care:
         T zgh = (z + static_cast<T>(L::g()) - boost::math::constants::half<T>());
         if(log(zgh) * z / 2 > tools::log_max_value<T>())
            return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
         T hp = pow(zgh, (z / 2) - T(0.25));
         result *= hp / exp(zgh);
         if(tools::max_value<T>() / hp < result)
            return policies::raise_overflow_error<T>(function, "Result of tgamma is too large to represent.", pol);
         result *= hp;
      }
      else
      {
         T zgh = (z + static_cast<T>(L::g()) - boost::math::constants::half<T>());
         result *= pow(zgh, z - boost::math::constants::half<T>()) / exp(zgh);
      }
   }
   return result;
}