[GiNaC-devel] [PATCH 5/8] tgamma, lgamma: convert to take cl_N as an argument; provide wrappers for GiNaC::numeric

Alexei Sheplyakov varg at theor.jinr.ru
Wed Mar 19 10:27:07 CET 2008


Implicit conversion from cl_N to numeric considered harmful, part 5.

---
 ginac/numeric.cpp |   58 +++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 41 insertions(+), 17 deletions(-)

diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp
index a06be42..704854c 100644
--- a/ginac/numeric.cpp
+++ b/ginac/numeric.cpp
@@ -1962,24 +1962,34 @@ lanczos_coeffs::lanczos_coeffs()
 	coeffs[3].swap(coeffs_120);
 }
 
+static const cln::float_format_t guess_precision(const cln::cl_N& x)
+{
+	cln::float_format_t prec = cln::default_float_format;
+	if (!instanceof(realpart(x), cln::cl_RA_ring))
+		prec = cln::float_format(cln::the<cln::cl_F>(realpart(x)));
+	if (!instanceof(imagpart(x), cln::cl_RA_ring))
+		prec = cln::float_format(cln::the<cln::cl_F>(imagpart(x)));
+	return prec;
+}
 
 /** The Gamma function.
  *  Use the Lanczos approximation. If the coefficients used here are not
  *  sufficiently many or sufficiently accurate, more can be calculated
  *  using the program doc/examples/lanczos.cpp. In that case, be sure to
  *  read the comments in that file. */
-const numeric lgamma(const numeric &x)
+const cln::cl_N lgamma_(const cln::cl_N &x)
 {
+	cln::float_format_t prec = guess_precision(x);
 	lanczos_coeffs lc;
-	if (lc.sufficiently_accurate(Digits)) {
-		cln::cl_N pi_val = cln::pi(cln::default_float_format);
-		if (x.real() < 0.5)
-			return log(pi_val) - log(sin(pi_val*x.to_cl_N()))
-				- lgamma(numeric(1).sub(x));
-		cln::cl_N A = lc.calc_lanczos_A(x.to_cl_N());
-		cln::cl_N temp = x.to_cl_N() + lc.get_order() - cln::cl_N(1)/2;
+	if (lc.sufficiently_accurate(prec)) {
+		cln::cl_N pi_val = cln::pi(prec);
+		if (realpart(x) < 0.5)
+			return cln::log(pi_val) - cln::log(sin(pi_val*x))
+				- lgamma_(1 - x);
+		cln::cl_N A = lc.calc_lanczos_A(x);
+		cln::cl_N temp = x + lc.get_order() - cln::cl_N(1)/2;
    	cln::cl_N result = log(cln::cl_I(2)*pi_val)/2
-		              + (x.to_cl_N()-cln::cl_N(1)/2)*log(temp)
+		              + (x-cln::cl_N(1)/2)*log(temp)
 		              - temp
 		              + log(A);
    	return result;
@@ -1988,17 +1998,25 @@ const numeric lgamma(const numeric &x)
 		throw dunno();
 }
 
-const numeric tgamma(const numeric &x)
+const numeric lgamma(const numeric &x)
+{
+	const cln::cl_N x_ = x.to_cl_N();
+	const cln::cl_N result = lgamma_(x_);
+	return numeric(result);
+}
+
+const cln::cl_N tgamma_(const cln::cl_N &x)
 {
+	cln::float_format_t prec = guess_precision(x);
 	lanczos_coeffs lc;
-	if (lc.sufficiently_accurate(Digits)) {
-		cln::cl_N pi_val = cln::pi(cln::default_float_format);
-		if (x.real() < 0.5)
-			return pi_val/(sin(pi_val*x))/(tgamma(numeric(1).sub(x)).to_cl_N());
-		cln::cl_N A = lc.calc_lanczos_A(x.to_cl_N());
-		cln::cl_N temp = x.to_cl_N() + lc.get_order() - cln::cl_N(1)/2;
+	if (lc.sufficiently_accurate(prec)) {
+		cln::cl_N pi_val = cln::pi(prec);
+		if (realpart(x) < 0.5)
+			return pi_val/(cln::sin(pi_val*x))/tgamma_(1 - x);
+		cln::cl_N A = lc.calc_lanczos_A(x);
+		cln::cl_N temp = x + lc.get_order() - cln::cl_N(1)/2;
    	cln::cl_N result
-			= sqrt(cln::cl_I(2)*pi_val) * expt(temp, x.to_cl_N()-cln::cl_N(1)/2)
+			= sqrt(cln::cl_I(2)*pi_val) * expt(temp, x - cln::cl_N(1)/2)
 			  * exp(-temp) * A;
    	return result;
 	}
@@ -2006,6 +2024,12 @@ const numeric tgamma(const numeric &x)
 		throw dunno();
 }
 
+const numeric tgamma(const numeric &x)
+{
+	const cln::cl_N x_ = x.to_cl_N();
+	const cln::cl_N result = tgamma_(x_);
+	return numeric(result);
+}
 
 /** The psi function (aka polygamma function).
  *  This is only a stub! */
-- 
1.5.4.2


-- 
All science is either physics or stamp collecting.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 827 bytes
Desc: Digital signature
URL: <http://www.ginac.de/pipermail/ginac-devel/attachments/20080319/24b27309/attachment.sig>


More information about the GiNaC-devel mailing list