X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fnumeric.cpp;h=ef2784172107f22965381b271e2fafcd92d7bbca;hp=ae0478584f1050acd624603df8df094fd3c85235;hb=0baf17b2c0f044ae0cdc305bb38316a282ce2b99;hpb=b075df9ab3eb2ebf0b5108caaeedd66526d95e58 diff --git a/ginac/numeric.cpp b/ginac/numeric.cpp index ae047858..ef278417 100644 --- a/ginac/numeric.cpp +++ b/ginac/numeric.cpp @@ -6,10 +6,31 @@ * provide implementation of arithmetic operators and numerical evaluation * of special functions or implement the interface to the bignum package. */ +/* + * GiNaC Copyright (C) 1999 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + #include #include -#include "ginac.h" +#include "numeric.h" +#include "ex.h" +#include "config.h" +#include "debugmsg.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: @@ -19,6 +40,8 @@ #include #endif +namespace GiNaC { + // linker has no problems finding text symbols for numerator or denominator //#define SANE_LINKER @@ -30,7 +53,7 @@ // public /** default ctor. Numerically it initializes to an integer zero. */ -numeric::numeric() : basic(TINFO_NUMERIC) +numeric::numeric() : basic(TINFO_numeric) { debugmsg("numeric default constructor", LOGLEVEL_CONSTRUCT); value = new cl_N; @@ -82,7 +105,7 @@ void numeric::destroy(bool call_parent) // public -numeric::numeric(int i) : basic(TINFO_NUMERIC) +numeric::numeric(int i) : basic(TINFO_numeric) { debugmsg("numeric constructor from int",LOGLEVEL_CONSTRUCT); // Not the whole int-range is available if we don't cast to long @@ -94,7 +117,7 @@ numeric::numeric(int i) : basic(TINFO_NUMERIC) status_flags::hash_calculated); } -numeric::numeric(unsigned int i) : basic(TINFO_NUMERIC) +numeric::numeric(unsigned int i) : basic(TINFO_numeric) { debugmsg("numeric constructor from uint",LOGLEVEL_CONSTRUCT); // Not the whole uint-range is available if we don't cast to ulong @@ -106,7 +129,7 @@ numeric::numeric(unsigned int i) : basic(TINFO_NUMERIC) status_flags::hash_calculated); } -numeric::numeric(long i) : basic(TINFO_NUMERIC) +numeric::numeric(long i) : basic(TINFO_numeric) { debugmsg("numeric constructor from long",LOGLEVEL_CONSTRUCT); value = new cl_I(i); @@ -115,7 +138,7 @@ numeric::numeric(long i) : basic(TINFO_NUMERIC) status_flags::hash_calculated); } -numeric::numeric(unsigned long i) : basic(TINFO_NUMERIC) +numeric::numeric(unsigned long i) : basic(TINFO_numeric) { debugmsg("numeric constructor from ulong",LOGLEVEL_CONSTRUCT); value = new cl_I(i); @@ -127,7 +150,7 @@ numeric::numeric(unsigned long i) : basic(TINFO_NUMERIC) /** Ctor for rational numerics a/b. * * @exception overflow_error (division by zero) */ -numeric::numeric(long numer, long denom) : basic(TINFO_NUMERIC) +numeric::numeric(long numer, long denom) : basic(TINFO_numeric) { debugmsg("numeric constructor from long/long",LOGLEVEL_CONSTRUCT); if (!denom) @@ -139,7 +162,7 @@ numeric::numeric(long numer, long denom) : basic(TINFO_NUMERIC) status_flags::hash_calculated); } -numeric::numeric(double d) : basic(TINFO_NUMERIC) +numeric::numeric(double d) : basic(TINFO_numeric) { debugmsg("numeric constructor from double",LOGLEVEL_CONSTRUCT); // We really want to explicitly use the type cl_LF instead of the @@ -152,7 +175,7 @@ numeric::numeric(double d) : basic(TINFO_NUMERIC) status_flags::hash_calculated); } -numeric::numeric(char const *s) : basic(TINFO_NUMERIC) +numeric::numeric(char const *s) : basic(TINFO_numeric) { // MISSING: treatment of complex and ints and rationals. debugmsg("numeric constructor from string",LOGLEVEL_CONSTRUCT); if (strchr(s, '.')) @@ -166,7 +189,7 @@ numeric::numeric(char const *s) : basic(TINFO_NUMERIC) /** Ctor from CLN types. This is for the initiated user or internal use * only. */ -numeric::numeric(cl_N const & z) : basic(TINFO_NUMERIC) +numeric::numeric(cl_N const & z) : basic(TINFO_numeric) { debugmsg("numeric constructor from cl_N", LOGLEVEL_CONSTRUCT); value = new cl_N(z); @@ -201,7 +224,7 @@ void numeric::printraw(ostream & os) const void numeric::print(ostream & os, unsigned upper_precedence) const { debugmsg("numeric print", LOGLEVEL_PRINT); - if (is_real()) { + if (is_real()) { // case 1, real: x or -x if ((precedence<=upper_precedence) && (!is_pos_integer())) { os << "(" << *value << ")"; @@ -492,10 +515,35 @@ numeric const & numeric::operator=(char const * s) return operator=(numeric(s)); } +/** Return the complex half-plane (left or right) in which the number lies. + * 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) */ +int numeric::csgn(void) const +{ + if (is_zero()) + return 0; + if (!zerop(realpart(*value))) { + if (plusp(realpart(*value))) + return 1; + else + return -1; + } else { + if (plusp(imagpart(*value))) + return 1; + else + return -1; + } +} + /** This method establishes a canonical order on all numbers. For complex * numbers this is not possible in a mathematically consistent way but we need * to establish some order and it ought to be fast. So we simply define it - * similar to Maple's csgn. */ + * to be compatible with our method csgn. + * + * @return csgn(*this-other) + * @see numeric::csgn(void) */ int numeric::compare(numeric const & other) const { // Comparing two real numbers? @@ -831,7 +879,7 @@ const numeric some_numeric; type_info const & typeid_numeric=typeid(some_numeric); /** Imaginary unit. This is not a constant but a numeric since we are * natively handing complex numbers anyways. */ -const numeric I = (complex(cl_I(0),cl_I(1))); +const numeric I = numeric(complex(cl_I(0),cl_I(1))); ////////// // global functions @@ -884,7 +932,7 @@ numeric const & numHALF(void) * @return arbitrary precision numerical exp(x). */ numeric exp(numeric const & x) { - return exp(*x.value); // -> CLN + return ::exp(*x.value); // -> CLN } /** Natural logarithm. @@ -896,7 +944,7 @@ numeric log(numeric const & z) { if (z.is_zero()) throw (std::overflow_error("log(): logarithmic singularity")); - return log(*z.value); // -> CLN + return ::log(*z.value); // -> CLN } /** Numeric sine (trigonometric function). @@ -904,7 +952,7 @@ numeric log(numeric const & z) * @return arbitrary precision numerical sin(x). */ numeric sin(numeric const & x) { - return sin(*x.value); // -> CLN + return ::sin(*x.value); // -> CLN } /** Numeric cosine (trigonometric function). @@ -912,7 +960,7 @@ numeric sin(numeric const & x) * @return arbitrary precision numerical cos(x). */ numeric cos(numeric const & x) { - return cos(*x.value); // -> CLN + return ::cos(*x.value); // -> CLN } /** Numeric tangent (trigonometric function). @@ -920,7 +968,7 @@ numeric cos(numeric const & x) * @return arbitrary precision numerical tan(x). */ numeric tan(numeric const & x) { - return tan(*x.value); // -> CLN + return ::tan(*x.value); // -> CLN } /** Numeric inverse sine (trigonometric function). @@ -928,7 +976,7 @@ numeric tan(numeric const & x) * @return arbitrary precision numerical asin(x). */ numeric asin(numeric const & x) { - return asin(*x.value); // -> CLN + return ::asin(*x.value); // -> CLN } /** Numeric inverse cosine (trigonometric function). @@ -936,7 +984,7 @@ numeric asin(numeric const & x) * @return arbitrary precision numerical acos(x). */ numeric acos(numeric const & x) { - return acos(*x.value); // -> CLN + return ::acos(*x.value); // -> CLN } /** Arcustangents. @@ -950,7 +998,7 @@ numeric atan(numeric const & x) x.real().is_zero() && !abs(x.imag()).is_equal(numONE())) throw (std::overflow_error("atan(): logarithmic singularity")); - return atan(*x.value); // -> CLN + return ::atan(*x.value); // -> CLN } /** Arcustangents. @@ -961,7 +1009,7 @@ numeric atan(numeric const & x) numeric atan(numeric const & y, numeric const & x) { if (x.is_real() && y.is_real()) - return atan(realpart(*x.value), realpart(*y.value)); // -> CLN + return ::atan(realpart(*x.value), realpart(*y.value)); // -> CLN else throw (std::invalid_argument("numeric::atan(): complex argument")); } @@ -971,7 +1019,7 @@ numeric atan(numeric const & y, numeric const & x) * @return arbitrary precision numerical sinh(x). */ numeric sinh(numeric const & x) { - return sinh(*x.value); // -> CLN + return ::sinh(*x.value); // -> CLN } /** Numeric hyperbolic cosine (trigonometric function). @@ -979,7 +1027,7 @@ numeric sinh(numeric const & x) * @return arbitrary precision numerical cosh(x). */ numeric cosh(numeric const & x) { - return cosh(*x.value); // -> CLN + return ::cosh(*x.value); // -> CLN } /** Numeric hyperbolic tangent (trigonometric function). @@ -987,7 +1035,7 @@ numeric cosh(numeric const & x) * @return arbitrary precision numerical tanh(x). */ numeric tanh(numeric const & x) { - return tanh(*x.value); // -> CLN + return ::tanh(*x.value); // -> CLN } /** Numeric inverse hyperbolic sine (trigonometric function). @@ -995,7 +1043,7 @@ numeric tanh(numeric const & x) * @return arbitrary precision numerical asinh(x). */ numeric asinh(numeric const & x) { - return asinh(*x.value); // -> CLN + return ::asinh(*x.value); // -> CLN } /** Numeric inverse hyperbolic cosine (trigonometric function). @@ -1003,7 +1051,7 @@ numeric asinh(numeric const & x) * @return arbitrary precision numerical acosh(x). */ numeric acosh(numeric const & x) { - return acosh(*x.value); // -> CLN + return ::acosh(*x.value); // -> CLN } /** Numeric inverse hyperbolic tangent (trigonometric function). @@ -1011,14 +1059,22 @@ numeric acosh(numeric const & x) * @return arbitrary precision numerical atanh(x). */ numeric atanh(numeric const & x) { - return atanh(*x.value); // -> CLN + return ::atanh(*x.value); // -> CLN } /** The gamma function. - * stub stub stub stub stub stub! */ + * This is only a stub! */ numeric gamma(numeric const & x) { - clog << "gamma(): Nobody expects the Spanish inquisition" << endl; + clog << "gamma(): Does anybody know good way to calculate this numerically?" << endl; + return numeric(0); +} + +/** The psi function (aka polygamma function). + * This is only a stub! */ +numeric psi(numeric const & n, numeric const & x) +{ + clog << "psi(): Does anybody know good way to calculate this numerically?" << endl; return numeric(0); } @@ -1031,7 +1087,7 @@ numeric factorial(numeric const & nn) throw (std::range_error("numeric::factorial(): argument must be integer >= 0")); } - return numeric(factorial(nn.to_int())); // -> CLN + return numeric(::factorial(nn.to_int())); // -> CLN } /** The double factorial combinatorial function. (Scarcely used, but still @@ -1042,6 +1098,10 @@ numeric factorial(numeric const & nn) * @exception range_error (argument must be integer >= -1) */ numeric doublefactorial(numeric const & 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 @@ -1103,7 +1163,7 @@ numeric doublefactorial(numeric const & nn) numeric binomial(numeric const & n, numeric const & k) { if (n.is_nonneg_integer() && k.is_nonneg_integer()) { - return numeric(binomial(n.to_int(),k.to_int())); // -> CLN + return numeric(::binomial(n.to_int(),k.to_int())); // -> CLN } else { // should really be gamma(n+1)/(gamma(r+1)/gamma(n-r+1) return numeric(0); @@ -1114,7 +1174,7 @@ numeric binomial(numeric const & n, numeric const & k) /** Absolute value. */ numeric abs(numeric const & x) { - return abs(*x.value); // -> CLN + return ::abs(*x.value); // -> CLN } /** Modulus (in positive representation). @@ -1127,7 +1187,7 @@ numeric abs(numeric const & x) numeric mod(numeric const & a, numeric const & b) { if (a.is_integer() && b.is_integer()) { - return mod(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + return ::mod(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN } else { return numZERO(); // Throw? @@ -1142,7 +1202,7 @@ numeric smod(numeric const & a, numeric const & b) { if (a.is_integer() && b.is_integer()) { cl_I b2 = The(cl_I)(ceiling1(The(cl_I)(*b.value) / 2)) - 1; - return mod(The(cl_I)(*a.value) + b2, The(cl_I)(*b.value)) - b2; + return ::mod(The(cl_I)(*a.value) + b2, The(cl_I)(*b.value)) - b2; } else { return numZERO(); // Throw? } @@ -1157,7 +1217,7 @@ numeric smod(numeric const & a, numeric const & b) numeric irem(numeric const & a, numeric const & b) { if (a.is_integer() && b.is_integer()) { - return rem(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + return ::rem(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN } else { return numZERO(); // Throw? @@ -1225,7 +1285,7 @@ numeric iquo(numeric const & a, numeric const & b, numeric & r) * where imag(z)>0. */ numeric sqrt(numeric const & z) { - return sqrt(*z.value); // -> CLN + return ::sqrt(*z.value); // -> CLN } /** Integer numeric square root. */ @@ -1233,7 +1293,7 @@ numeric isqrt(numeric const & x) { if (x.is_integer()) { cl_I root; - isqrt(The(cl_I)(*x.value), &root); // -> CLN + ::isqrt(The(cl_I)(*x.value), &root); // -> CLN return root; } else return numZERO(); // Throw? @@ -1246,7 +1306,7 @@ numeric isqrt(numeric const & x) numeric gcd(numeric const & a, numeric const & b) { if (a.is_integer() && b.is_integer()) - return gcd(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + return ::gcd(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN else return numONE(); } @@ -1258,7 +1318,7 @@ numeric gcd(numeric const & a, numeric const & b) numeric lcm(numeric const & a, numeric const & b) { if (a.is_integer() && b.is_integer()) - return lcm(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN + return ::lcm(The(cl_I)(*a.value), The(cl_I)(*b.value)); // -> CLN else return *a.value * *b.value; } @@ -1324,3 +1384,5 @@ bool _numeric_digits::too_late = false; /** Accuracy in decimal digits. Only object of this type! Can be set using * assignment from C++ unsigned ints and evaluated like any built-in type. */ _numeric_digits Digits; + +} // namespace GiNaC