]> www.ginac.de Git - ginac.git/blobdiff - ginac/numeric.cpp
- Changed policy: look for cln/cln.h instead of CLN/cln.h, reflecting an
[ginac.git] / ginac / numeric.cpp
index 472d9c31034de58b38dfd40dbfd2da8ff0790962..c23d46a2408700b83b78fd541c59b516cd0091b6 100644 (file)
@@ -7,7 +7,7 @@
  *  of special functions or implement the interface to the bignum package. */
 
 /*
- *  GiNaC Copyright (C) 1999 Johannes Gutenberg University Mainz, Germany
+ *  GiNaC Copyright (C) 1999-2000 Johannes Gutenberg University Mainz, Germany
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 
 #include <vector>
 #include <stdexcept>
+#include <string>
+#include <strstream>   //!!
 
 #include "numeric.h"
 #include "ex.h"
 #include "config.h"
+#include "archive.h"
 #include "debugmsg.h"
 #include "utils.h"
 
 // CLN should not pollute the global namespace, hence we include it here
-// instead of in some header file where it would propagate to other parts:
+// instead of in some header file where it would propagate to other parts.
+// Also, we only need a subset of CLN, so we don't include the complete cln.h:
 #ifdef HAVE_CLN_CLN_H
-#include <CLN/cln.h>
+#include <cln/cl_integer_io.h>
+#include <cln/cl_integer_ring.h>
+#include <cln/cl_rational_io.h>
+#include <cln/cl_rational_ring.h>
+#include <cln/cl_lfloat_class.h>
+#include <cln/cl_lfloat_io.h>
+#include <cln/cl_real_io.h>
+#include <cln/cl_real_ring.h>
+#include <cln/cl_complex_io.h>
+#include <cln/cl_complex_ring.h>
+#include <cln/cl_numtheory.h>
 #else
-#include <cln.h>
+#include <cl_integer_io.h>
+#include <cl_integer_ring.h>
+#include <cl_rational_io.h>
+#include <cl_rational_ring.h>
+#include <cl_lfloat_class.h>
+#include <cl_lfloat_io.h>
+#include <cl_real_io.h>
+#include <cl_real_ring.h>
+#include <cl_complex_io.h>
+#include <cl_complex_ring.h>
+#include <cl_numtheory.h>
 #endif
 
 #ifndef NO_GINAC_NAMESPACE
@@ -48,6 +72,8 @@ namespace GiNaC {
 // linker has no problems finding text symbols for numerator or denominator
 //#define SANE_LINKER
 
+GINAC_IMPLEMENT_REGISTERED_CLASS(numeric, basic)
+
 //////////
 // default constructor, destructor, copy constructor assignment
 // operator and helpers
@@ -72,13 +98,13 @@ numeric::~numeric()
     destroy(0);
 }
 
-numeric::numeric(numeric const & other)
+numeric::numeric(const numeric & other)
 {
     debugmsg("numeric copy constructor", LOGLEVEL_CONSTRUCT);
     copy(other);
 }
 
-numeric const & numeric::operator=(numeric const & other)
+const numeric & numeric::operator=(const numeric & other)
 {
     debugmsg("numeric operator=", LOGLEVEL_ASSIGNMENT);
     if (this != &other) {
@@ -90,7 +116,7 @@ numeric const & numeric::operator=(numeric const & other)
 
 // protected
 
-void numeric::copy(numeric const & other)
+void numeric::copy(const numeric & other)
 {
     basic::copy(other);
     value = new cl_N(*other.value);
@@ -201,6 +227,60 @@ numeric::numeric(cl_N const & z) : basic(TINFO_numeric)
             status_flags::hash_calculated);
 }
 
+//////////
+// archiving
+//////////
+
+/** Construct object from archive_node. */
+numeric::numeric(const archive_node &n, const lst &sym_lst) : inherited(n, sym_lst)
+{
+    debugmsg("numeric constructor from archive_node", LOGLEVEL_CONSTRUCT);
+    value = new cl_N;
+#if 0  //!!
+    // This is how it should be implemented but we have no istringstream here...
+    string str;
+    if (n.find_string("number", str)) {
+        istringstream s(str);
+        s >> *value;
+    }
+#else
+    // Workaround for the above: read from strstream
+    string str;
+    if (n.find_string("number", str)) {
+        istrstream f(str.c_str(), str.size() + 1);
+        f >> *value;
+    }
+#endif
+    calchash();
+    setflag(status_flags::evaluated|
+            status_flags::hash_calculated);
+}
+
+/** Unarchive the object. */
+ex numeric::unarchive(const archive_node &n, const lst &sym_lst)
+{
+    return (new numeric(n, sym_lst))->setflag(status_flags::dynallocated);
+}
+
+/** Archive the object. */
+void numeric::archive(archive_node &n) const
+{
+    inherited::archive(n);
+#if 0  //!!
+    // This is how it should be implemented but we have no ostringstream here...
+    ostringstream s;
+    s << *value;
+    n.add_string("number", s.str());
+#else
+    // Workaround for the above: write to strstream
+    char buf[1024];
+    ostrstream f(buf, 1024);
+    f << *value << ends;
+    string str(buf);
+    n.add_string("number", str);
+#endif
+}
+
 //////////
 // functions overriding virtual functions from bases classes
 //////////
@@ -213,19 +293,11 @@ basic * numeric::duplicate() const
     return new numeric(*this);
 }
 
-// The method printraw doesn't do much, it simply uses CLN's operator<<() for
-// output, which is ugly but reliable. Examples:
-// 2+2i 
-void numeric::printraw(ostream & os) const
-{
-    debugmsg("numeric printraw", LOGLEVEL_PRINT);
-    os << "numeric(" << *value << ")";
-}
-
-// The method print adds to the output so it blends more consistently together
-// with the other routines and produces something compatible to Maple input.
 void numeric::print(ostream & os, unsigned upper_precedence) const
 {
+    // The method print adds to the output so it blends more consistently
+    // together with the other routines and produces something compatible to
+    // ginsh input.
     debugmsg("numeric print", LOGLEVEL_PRINT);
     if (is_real()) {
         // case 1, real:  x  or  -x
@@ -276,6 +348,14 @@ void numeric::print(ostream & os, unsigned upper_precedence) const
     }
 }
 
+
+void numeric::printraw(ostream & os) const
+{
+    // The method printraw doesn't do much, it simply uses CLN's operator<<()
+    // for output, which is ugly but reliable. e.g: 2+2i
+    debugmsg("numeric printraw", LOGLEVEL_PRINT);
+    os << "numeric(" << *value << ")";
+}
 void numeric::printtree(ostream & os, unsigned indent) const
 {
     debugmsg("numeric printtree", LOGLEVEL_PRINT);
@@ -379,7 +459,7 @@ ex numeric::evalf(int level) const
 int numeric::compare_same_type(basic const & other) const
 {
     GINAC_ASSERT(is_exactly_of_type(other, numeric));
-    numeric const & o = static_cast<numeric &>(const_cast<basic &>(other));
+    const numeric & o = static_cast<numeric &>(const_cast<basic &>(other));
 
     if (*value == *o.value) {
         return 0;
@@ -391,7 +471,7 @@ int numeric::compare_same_type(basic const & other) const
 bool numeric::is_equal_same_type(basic const & other) const
 {
     GINAC_ASSERT(is_exactly_of_type(other,numeric));
-    numeric const *o = static_cast<numeric const *>(&other);
+    const numeric *o = static_cast<const numeric *>(&other);
     
     return is_equal(*o);
 }
@@ -424,21 +504,21 @@ unsigned numeric::calchash(void) const
 
 /** Numerical addition method.  Adds argument to *this and returns result as
  *  a new numeric object. */
-numeric numeric::add(numeric const & other) const
+numeric numeric::add(const numeric & other) const
 {
     return numeric((*value)+(*other.value));
 }
 
 /** Numerical subtraction method.  Subtracts argument from *this and returns
  *  result as a new numeric object. */
-numeric numeric::sub(numeric const & other) const
+numeric numeric::sub(const numeric & other) const
 {
     return numeric((*value)-(*other.value));
 }
 
 /** Numerical multiplication method.  Multiplies *this and argument and returns
  *  result as a new numeric object. */
-numeric numeric::mul(numeric const & other) const
+numeric numeric::mul(const numeric & other) const
 {
     static const numeric * _num1p=&_num1();
     if (this==_num1p) {
@@ -453,14 +533,14 @@ numeric numeric::mul(numeric const & other) const
  *  a new numeric object.
  *
  *  @exception overflow_error (division by zero) */
-numeric numeric::div(numeric const & other) const
+numeric numeric::div(const numeric & other) const
 {
     if (::zerop(*other.value))
         throw (std::overflow_error("division by zero"));
     return numeric((*value)/(*other.value));
 }
 
-numeric numeric::power(numeric const & other) const
+numeric numeric::power(const numeric & other) const
 {
     static const numeric * _num1p=&_num1();
     if (&other==_num1p)
@@ -476,19 +556,19 @@ numeric numeric::inverse(void) const
     return numeric(::recip(*value));  // -> CLN
 }
 
-numeric const & numeric::add_dyn(numeric const & other) const
+const numeric & numeric::add_dyn(const numeric & other) const
 {
-    return static_cast<numeric const &>((new numeric((*value)+(*other.value)))->
+    return static_cast<const numeric &>((new numeric((*value)+(*other.value)))->
                                         setflag(status_flags::dynallocated));
 }
 
-numeric const & numeric::sub_dyn(numeric const & other) const
+const numeric & numeric::sub_dyn(const numeric & other) const
 {
-    return static_cast<numeric const &>((new numeric((*value)-(*other.value)))->
+    return static_cast<const numeric &>((new numeric((*value)-(*other.value)))->
                                         setflag(status_flags::dynallocated));
 }
 
-numeric const & numeric::mul_dyn(numeric const & other) const
+const numeric & numeric::mul_dyn(const numeric & other) const
 {
     static const numeric * _num1p=&_num1();
     if (this==_num1p) {
@@ -496,55 +576,55 @@ numeric const & numeric::mul_dyn(numeric const & other) const
     } else if (&other==_num1p) {
         return *this;
     }
-    return static_cast<numeric const &>((new numeric((*value)*(*other.value)))->
+    return static_cast<const numeric &>((new numeric((*value)*(*other.value)))->
                                         setflag(status_flags::dynallocated));
 }
 
-numeric const & numeric::div_dyn(numeric const & other) const
+const numeric & numeric::div_dyn(const numeric & other) const
 {
     if (::zerop(*other.value))
         throw (std::overflow_error("division by zero"));
-    return static_cast<numeric const &>((new numeric((*value)/(*other.value)))->
+    return static_cast<const numeric &>((new numeric((*value)/(*other.value)))->
                                         setflag(status_flags::dynallocated));
 }
 
-numeric const & numeric::power_dyn(numeric const & other) const
+const numeric & numeric::power_dyn(const numeric & other) const
 {
     static const numeric * _num1p=&_num1();
     if (&other==_num1p)
         return *this;
     if (::zerop(*value) && other.is_real() && ::minusp(realpart(*other.value)))
         throw (std::overflow_error("division by zero"));
-    return static_cast<numeric const &>((new numeric(::expt(*value,*other.value)))->
+    return static_cast<const numeric &>((new numeric(::expt(*value,*other.value)))->
                                         setflag(status_flags::dynallocated));
 }
 
-numeric const & numeric::operator=(int i)
+const numeric & numeric::operator=(int i)
 {
     return operator=(numeric(i));
 }
 
-numeric const & numeric::operator=(unsigned int i)
+const numeric & numeric::operator=(unsigned int i)
 {
     return operator=(numeric(i));
 }
 
-numeric const & numeric::operator=(long i)
+const numeric & numeric::operator=(long i)
 {
     return operator=(numeric(i));
 }
 
-numeric const & numeric::operator=(unsigned long i)
+const numeric & numeric::operator=(unsigned long i)
 {
     return operator=(numeric(i));
 }
 
-numeric const & numeric::operator=(double d)
+const numeric & numeric::operator=(double d)
 {
     return operator=(numeric(d));
 }
 
-numeric const & numeric::operator=(char const * s)
+const numeric & numeric::operator=(char const * s)
 {
     return operator=(numeric(s));
 }
@@ -553,7 +633,7 @@ numeric const & numeric::operator=(char const * s)
  *  csgn(x)==0 for x==0, csgn(x)==1 for Re(x)>0 or Re(x)=0 and Im(x)>0,
  *  csgn(x)==-1 for Re(x)<0 or Re(x)=0 and Im(x)<0.
  *
- *  @see numeric::compare(numeric const & other) */
+ *  @see numeric::compare(const numeric & other) */
 int numeric::csgn(void) const
 {
     if (is_zero())
@@ -578,7 +658,7 @@ int numeric::csgn(void) const
  *
  *  @return csgn(*this-other)
  *  @see numeric::csgn(void) */
-int numeric::compare(numeric const & other) const
+int numeric::compare(const numeric & other) const
 {
     // Comparing two real numbers?
     if (is_real() && other.is_real())
@@ -594,7 +674,7 @@ int numeric::compare(numeric const & other) const
     }
 }
 
-bool numeric::is_equal(numeric const & other) const
+bool numeric::is_equal(const numeric & other) const
 {
     return (*value == *other.value);
 }
@@ -672,12 +752,12 @@ bool numeric::is_real(void) const
     return ::instanceof(*value, cl_R_ring);  // -> CLN
 }
 
-bool numeric::operator==(numeric const & other) const
+bool numeric::operator==(const numeric & other) const
 {
     return (*value == *other.value);  // -> CLN
 }
 
-bool numeric::operator!=(numeric const & other) const
+bool numeric::operator!=(const numeric & other) const
 {
     return (*value != *other.value);  // -> CLN
 }
@@ -713,7 +793,7 @@ bool numeric::is_crational(void) const
 /** Numerical comparison: less.
  *
  *  @exception invalid_argument (complex inequality) */ 
-bool numeric::operator<(numeric const & other) const
+bool numeric::operator<(const numeric & other) const
 {
     if (is_real() && other.is_real())
         return (bool)(The(cl_R)(*value) < The(cl_R)(*other.value));  // -> CLN
@@ -724,7 +804,7 @@ bool numeric::operator<(numeric const & other) const
 /** Numerical comparison: less or equal.
  *
  *  @exception invalid_argument (complex inequality) */ 
-bool numeric::operator<=(numeric const & other) const
+bool numeric::operator<=(const numeric & other) const
 {
     if (is_real() && other.is_real())
         return (bool)(The(cl_R)(*value) <= The(cl_R)(*other.value));  // -> CLN
@@ -735,7 +815,7 @@ bool numeric::operator<=(numeric const & other) const
 /** Numerical comparison: greater.
  *
  *  @exception invalid_argument (complex inequality) */ 
-bool numeric::operator>(numeric const & other) const
+bool numeric::operator>(const numeric & other) const
 {
     if (is_real() && other.is_real())
         return (bool)(The(cl_R)(*value) > The(cl_R)(*other.value));  // -> CLN
@@ -746,7 +826,7 @@ bool numeric::operator>(numeric const & other) const
 /** Numerical comparison: greater or equal.
  *
  *  @exception invalid_argument (complex inequality) */  
-bool numeric::operator>=(numeric const & other) const
+bool numeric::operator>=(const numeric & other) const
 {
     if (is_real() && other.is_real())
         return (bool)(The(cl_R)(*value) >= The(cl_R)(*other.value));  // -> CLN
@@ -928,7 +1008,7 @@ const numeric I = numeric(complex(cl_I(0),cl_I(1)));
 /** Exponential function.
  *
  *  @return  arbitrary precision numerical exp(x). */
-numeric exp(numeric const & x)
+numeric exp(const numeric & x)
 {
     return ::exp(*x.value);  // -> CLN
 }
@@ -938,7 +1018,7 @@ numeric exp(numeric const & x)
  *  @param z complex number
  *  @return  arbitrary precision numerical log(x).
  *  @exception overflow_error (logarithmic singularity) */
-numeric log(numeric const & z)
+numeric log(const numeric & z)
 {
     if (z.is_zero())
         throw (std::overflow_error("log(): logarithmic singularity"));
@@ -948,7 +1028,7 @@ numeric log(numeric const & z)
 /** Numeric sine (trigonometric function).
  *
  *  @return  arbitrary precision numerical sin(x). */
-numeric sin(numeric const & x)
+numeric sin(const numeric & x)
 {
     return ::sin(*x.value);  // -> CLN
 }
@@ -956,7 +1036,7 @@ numeric sin(numeric const & x)
 /** Numeric cosine (trigonometric function).
  *
  *  @return  arbitrary precision numerical cos(x). */
-numeric cos(numeric const & x)
+numeric cos(const numeric & x)
 {
     return ::cos(*x.value);  // -> CLN
 }
@@ -964,7 +1044,7 @@ numeric cos(numeric const & x)
 /** Numeric tangent (trigonometric function).
  *
  *  @return  arbitrary precision numerical tan(x). */
-numeric tan(numeric const & x)
+numeric tan(const numeric & x)
 {
     return ::tan(*x.value);  // -> CLN
 }
@@ -972,7 +1052,7 @@ numeric tan(numeric const & x)
 /** Numeric inverse sine (trigonometric function).
  *
  *  @return  arbitrary precision numerical asin(x). */
-numeric asin(numeric const & x)
+numeric asin(const numeric & x)
 {
     return ::asin(*x.value);  // -> CLN
 }
@@ -980,7 +1060,7 @@ numeric asin(numeric const & x)
 /** Numeric inverse cosine (trigonometric function).
  *
  *  @return  arbitrary precision numerical acos(x). */
-numeric acos(numeric const & x)
+numeric acos(const numeric & x)
 {
     return ::acos(*x.value);  // -> CLN
 }
@@ -990,7 +1070,7 @@ numeric acos(numeric const & x)
  *  @param z complex number
  *  @return atan(z)
  *  @exception overflow_error (logarithmic singularity) */
-numeric atan(numeric const & x)
+numeric atan(const numeric & x)
 {
     if (!x.is_real() &&
         x.real().is_zero() &&
@@ -1004,7 +1084,7 @@ numeric atan(numeric const & x)
  *  @param x real number
  *  @param y real number
  *  @return atan(y/x) */
-numeric atan(numeric const & y, numeric const & x)
+numeric atan(const numeric & y, const numeric & x)
 {
     if (x.is_real() && y.is_real())
         return ::atan(realpart(*x.value), realpart(*y.value));  // -> CLN
@@ -1015,7 +1095,7 @@ numeric atan(numeric const & y, numeric const & x)
 /** Numeric hyperbolic sine (trigonometric function).
  *
  *  @return  arbitrary precision numerical sinh(x). */
-numeric sinh(numeric const & x)
+numeric sinh(const numeric & x)
 {
     return ::sinh(*x.value);  // -> CLN
 }
@@ -1023,7 +1103,7 @@ numeric sinh(numeric const & x)
 /** Numeric hyperbolic cosine (trigonometric function).
  *
  *  @return  arbitrary precision numerical cosh(x). */
-numeric cosh(numeric const & x)
+numeric cosh(const numeric & x)
 {
     return ::cosh(*x.value);  // -> CLN
 }
@@ -1031,7 +1111,7 @@ numeric cosh(numeric const & x)
 /** Numeric hyperbolic tangent (trigonometric function).
  *
  *  @return  arbitrary precision numerical tanh(x). */
-numeric tanh(numeric const & x)
+numeric tanh(const numeric & x)
 {
     return ::tanh(*x.value);  // -> CLN
 }
@@ -1039,7 +1119,7 @@ numeric tanh(numeric const & x)
 /** Numeric inverse hyperbolic sine (trigonometric function).
  *
  *  @return  arbitrary precision numerical asinh(x). */
-numeric asinh(numeric const & x)
+numeric asinh(const numeric & x)
 {
     return ::asinh(*x.value);  // -> CLN
 }
@@ -1047,7 +1127,7 @@ numeric asinh(numeric const & x)
 /** Numeric inverse hyperbolic cosine (trigonometric function).
  *
  *  @return  arbitrary precision numerical acosh(x). */
-numeric acosh(numeric const & x)
+numeric acosh(const numeric & x)
 {
     return ::acosh(*x.value);  // -> CLN
 }
@@ -1055,14 +1135,14 @@ numeric acosh(numeric const & x)
 /** Numeric inverse hyperbolic tangent (trigonometric function).
  *
  *  @return  arbitrary precision numerical atanh(x). */
-numeric atanh(numeric const & x)
+numeric atanh(const numeric & x)
 {
     return ::atanh(*x.value);  // -> CLN
 }
 
 /** Numeric evaluation of Riemann's Zeta function.  Currently works only for
  *  integer arguments. */
-numeric zeta(numeric const & x)
+numeric zeta(const numeric & x)
 {
     // A dirty hack to allow for things like zeta(3.0), since CLN currently
     // only knows about integer arguments and zeta(3).evalf() automatically
@@ -1082,7 +1162,7 @@ numeric zeta(numeric const & x)
 
 /** The gamma function.
  *  This is only a stub! */
-numeric gamma(numeric const & x)
+numeric gamma(const numeric & x)
 {
     clog << "gamma(" << x
          << "): Does anybody know good way to calculate this numerically?"
@@ -1092,7 +1172,7 @@ numeric gamma(numeric const & x)
 
 /** The psi function (aka polygamma function).
  *  This is only a stub! */
-numeric psi(numeric const & x)
+numeric psi(const numeric & x)
 {
     clog << "psi(" << x
          << "): Does anybody know good way to calculate this numerically?"
@@ -1102,7 +1182,7 @@ numeric psi(numeric const & x)
 
 /** The psi functions (aka polygamma functions).
  *  This is only a stub! */
-numeric psi(numeric const & n, numeric const & x)
+numeric psi(const numeric & n, const numeric & x)
 {
     clog << "psi(" << n << "," << x
          << "): Does anybody know good way to calculate this numerically?"
@@ -1113,7 +1193,7 @@ numeric psi(numeric const & n, numeric const & x)
 /** Factorial combinatorial function.
  *
  *  @exception range_error (argument must be integer >= 0) */
-numeric factorial(numeric const & nn)
+numeric factorial(const numeric & nn)
 {
     if (!nn.is_nonneg_integer())
         throw (std::range_error("numeric::factorial(): argument must be integer >= 0"));
@@ -1124,73 +1204,24 @@ numeric factorial(numeric const & nn)
  *  useful in cases, like for exact results of Gamma(n+1/2) for instance.)
  *
  *  @param n  integer argument >= -1
- *  @return n!! == n * (n-2) * (n-4) * ... * ({1|2}) with 0!! == 1 == (-1)!!
+ *  @return n!! == n * (n-2) * (n-4) * ... * ({1|2}) with 0!! == (-1)!! == 1
  *  @exception range_error (argument must be integer >= -1) */
-numeric doublefactorial(numeric const & nn)
+numeric doublefactorial(const numeric & nn)
 {
-    // META-NOTE:  The whole shit here will become obsolete and may be moved
-    // out once CLN learns about double factorial, which should be as soon as
-    // 1.0.3 rolls out!
-    
-    // We store the results separately for even and odd arguments.  This has
-    // the advantage that we don't have to compute any even result at all if
-    // the function is always called with odd arguments and vice versa.  There
-    // is no tradeoff involved in this, it is guaranteed to save time as well
-    // as memory.  (If this is not enough justification consider the Gamma
-    // function of half integer arguments: it only needs odd doublefactorials.)
-    static vector<numeric> evenresults;
-    static int highest_evenresult = -1;
-    static vector<numeric> oddresults;
-    static int highest_oddresult = -1;
-    
     if (nn == numeric(-1)) {
         return _num1();
     }
     if (!nn.is_nonneg_integer()) {
         throw (std::range_error("numeric::doublefactorial(): argument must be integer >= -1"));
     }
-    if (nn.is_even()) {
-        int n = nn.div(_num2()).to_int();
-        if (n <= highest_evenresult) {
-            return evenresults[n];
-        }
-        if (evenresults.capacity() < (unsigned)(n+1)) {
-            evenresults.reserve(n+1);
-        }
-        if (highest_evenresult < 0) {
-            evenresults.push_back(_num1());
-            highest_evenresult=0;
-        }
-        for (int i=highest_evenresult+1; i<=n; i++) {
-            evenresults.push_back(numeric(evenresults[i-1].mul(numeric(i*2))));
-        }
-        highest_evenresult=n;
-        return evenresults[n];
-    } else {
-        int n = nn.sub(_num1()).div(_num2()).to_int();
-        if (n <= highest_oddresult) {
-            return oddresults[n];
-        }
-        if (oddresults.capacity() < (unsigned)n) {
-            oddresults.reserve(n+1);
-        }
-        if (highest_oddresult < 0) {
-            oddresults.push_back(_num1());
-            highest_oddresult=0;
-        }
-        for (int i=highest_oddresult+1; i<=n; i++) {
-            oddresults.push_back(numeric(oddresults[i-1].mul(numeric(i*2+1))));
-        }
-        highest_oddresult=n;
-        return oddresults[n];
-    }
+    return numeric(::doublefactorial(nn.to_int()));  // -> CLN
 }
 
 /** The Binomial coefficients.  It computes the binomial coefficients.  For
  *  integer n and k and positive n this is the number of ways of choosing k
  *  objects from n distinct objects.  If n is negative, the formula
  *  binomial(n,k) == (-1)^k*binomial(k-n-1,k) is used to compute the result. */
-numeric binomial(numeric const & n, numeric const & k)
+numeric binomial(const numeric & n, const numeric & k)
 {
     if (n.is_integer() && k.is_integer()) {
         if (n.is_nonneg_integer()) {
@@ -1212,7 +1243,7 @@ numeric binomial(numeric const & n, numeric const & k)
  *
  *  @return the nth Bernoulli number (a rational number).
  *  @exception range_error (argument must be integer >= 0) */
-numeric bernoulli(numeric const & nn)
+numeric bernoulli(const numeric & nn)
 {
     if (!nn.is_integer() || nn.is_negative())
         throw (std::range_error("numeric::bernoulli(): argument must be integer >= 0"));
@@ -1250,7 +1281,7 @@ numeric bernoulli(numeric const & nn)
 }
 
 /** Absolute value. */
-numeric abs(numeric const & x)
+numeric abs(const numeric & x)
 {
     return ::abs(*x.value);  // -> CLN
 }
@@ -1262,7 +1293,7 @@ numeric abs(numeric const & x)
  *
  *  @return a mod b in the range [0,abs(b)-1] with sign of b if both are
  *  integer, 0 otherwise. */
-numeric mod(numeric const & a, numeric const & b)
+numeric mod(const numeric & a, const numeric & b)
 {
     if (a.is_integer() && b.is_integer())
         return ::mod(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
@@ -1274,7 +1305,7 @@ numeric mod(numeric const & a, numeric const & b)
  *  Equivalent to Maple's mods.
  *
  *  @return a mod b in the range [-iquo(abs(m)-1,2), iquo(abs(m),2)]. */
-numeric smod(numeric const & a, numeric const & b)
+numeric smod(const numeric & a, const numeric & b)
 {
     //  FIXME: Should this become a member function?
     if (a.is_integer() && b.is_integer()) {
@@ -1290,7 +1321,7 @@ numeric smod(numeric const & a, numeric const & b)
  *  sign of a or is zero.
  *
  *  @return remainder of a/b if both are integer, 0 otherwise. */
-numeric irem(numeric const & a, numeric const & b)
+numeric irem(const numeric & a, const numeric & b)
 {
     if (a.is_integer() && b.is_integer())
         return ::rem(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
@@ -1305,7 +1336,7 @@ numeric irem(numeric const & a, numeric const & b)
  *
  *  @return remainder of a/b and quotient stored in q if both are integer,
  *  0 otherwise. */
-numeric irem(numeric const & a, numeric const & b, numeric & q)
+numeric irem(const numeric & a, const numeric & b, numeric & q)
 {
     if (a.is_integer() && b.is_integer()) {  // -> CLN
         cl_I_div_t rem_quo = truncate2(The(cl_I)(*a.value), The(cl_I)(*b.value));
@@ -1322,7 +1353,7 @@ numeric irem(numeric const & a, numeric const & b, numeric & q)
  *  Equivalent to Maple's iquo as far as sign conventions are concerned.
  *  
  *  @return truncated quotient of a/b if both are integer, 0 otherwise. */
-numeric iquo(numeric const & a, numeric const & b)
+numeric iquo(const numeric & a, const numeric & b)
 {
     if (a.is_integer() && b.is_integer())
         return truncate1(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
@@ -1336,7 +1367,7 @@ numeric iquo(numeric const & a, numeric const & b)
  *
  *  @return truncated quotient of a/b and remainder stored in r if both are
  *  integer, 0 otherwise. */
-numeric iquo(numeric const & a, numeric const & b, numeric & r)
+numeric iquo(const numeric & a, const numeric & b, numeric & r)
 {
     if (a.is_integer() && b.is_integer()) {  // -> CLN
         cl_I_div_t rem_quo = truncate2(The(cl_I)(*a.value), The(cl_I)(*b.value));
@@ -1356,13 +1387,13 @@ numeric iquo(numeric const & a, numeric const & b, numeric & r)
  *  @return square root of z. Branch cut along negative real axis, the negative
  *  real axis itself where imag(z)==0 and real(z)<0 belongs to the upper part
  *  where imag(z)>0. */
-numeric sqrt(numeric const & z)
+numeric sqrt(const numeric & z)
 {
     return ::sqrt(*z.value);  // -> CLN
 }
 
 /** Integer numeric square root. */
-numeric isqrt(numeric const & x)
+numeric isqrt(const numeric & x)
 {
     if (x.is_integer()) {
         cl_I root;
@@ -1376,7 +1407,7 @@ numeric isqrt(numeric const & x)
  *   
  *  @return  The GCD of two numbers if both are integer, a numerical 1
  *  if they are not. */
-numeric gcd(numeric const & a, numeric const & b)
+numeric gcd(const numeric & a, const numeric & b)
 {
     if (a.is_integer() && b.is_integer())
         return ::gcd(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
@@ -1388,7 +1419,7 @@ numeric gcd(numeric const & a, numeric const & b)
  *   
  *  @return  The LCM of two numbers if both are integer, the product of those
  *  two numbers if they are not. */
-numeric lcm(numeric const & a, numeric const & b)
+numeric lcm(const numeric & a, const numeric & b)
 {
     if (a.is_integer() && b.is_integer())
         return ::lcm(The(cl_I)(*a.value), The(cl_I)(*b.value));  // -> CLN
@@ -1419,7 +1450,7 @@ _numeric_digits::_numeric_digits()
 {
     assert(!too_late);
     too_late = true;
-    cl_default_float_format = cl_float_format(17); 
+    cl_default_float_format = cl_float_format(17);
 }
 
 _numeric_digits& _numeric_digits::operator=(long prec)