* of special functions or implement the interface to the bignum package. */
/*
- * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany
+ * GiNaC Copyright (C) 1999-2022 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
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "config.h"
-
-#include <vector>
-#include <stdexcept>
-#include <string>
-#include <sstream>
-#include <limits>
-
#include "numeric.h"
#include "ex.h"
#include "operators.h"
#include "archive.h"
-#include "tostring.h"
#include "utils.h"
+#include <limits>
+#include <sstream>
+#include <stdexcept>
+#include <string>
+#include <vector>
+
// CLN should pollute the global namespace as little as possible. Hence, we
// include most of it here and include only the part needed for properly
// declaring cln::cl_number in numeric.h. This can only be safely done in
numeric::numeric(int i)
{
// Not the whole int-range is available if we don't cast to long
- // first. This is due to the behaviour of the cl_I-ctor, which
+ // first. This is due to the behavior of the cl_I-ctor, which
// emphasizes efficiency. However, if the integer is small enough
// we save space and dereferences by using an immediate type.
// (C.f. <cln/object.h>)
numeric::numeric(unsigned int i)
{
// Not the whole uint-range is available if we don't cast to ulong
- // first. This is due to the behaviour of the cl_I-ctor, which
+ // first. This is due to the behavior of the cl_I-ctor, which
// emphasizes efficiency. However, if the integer is small enough
// we save space and dereferences by using an immediate type.
// (C.f. <cln/object.h>)
setflag(status_flags::evaluated | status_flags::expanded);
}
+numeric::numeric(long long i)
+{
+ value = cln::cl_I(i);
+ setflag(status_flags::evaluated | status_flags::expanded);
+}
+
+numeric::numeric(unsigned long long i)
+{
+ value = cln::cl_I(i);
+ setflag(status_flags::evaluated | status_flags::expanded);
+}
/** Constructor for rational numerics a/b.
*
// E to lower case
term = term.replace(term.find("E"),1,"e");
// append _<Digits> to term
- term += "_" + ToString((unsigned)Digits);
+ term += "_" + std::to_string((unsigned)Digits);
// construct float using cln::cl_F(const char *) ctor.
if (imaginary)
ctorval = ctorval + cln::complex(cln::cl_I(0),cln::cl_F(term.c_str()));
// Rational number
const cln::cl_I numer = cln::numerator(cln::the<cln::cl_RA>(x));
const cln::cl_I denom = cln::denominator(cln::the<cln::cl_RA>(x));
- if (cln::plusp(x) > 0) {
+ if (cln::plusp(x)) {
c.s << "(";
print_integer_csrc(c, numer);
} else {
/**
* @brief Check if CLN integer can be converted into int
*
- * @sa http://www.ginac.de/pipermail/cln-list/2006-October/000248.html
+ * @sa https://www.ginac.de/pipermail/cln-list/2006-October/000248.html
*/
template<>
inline bool coerce<int, cln::cl_I>(int& dst, const cln::cl_I& arg)
{
if (cln::instanceof(x, cln::cl_I_ring)) {
- int dst;
- // fixnum
- if (coerce(dst, cln::the<cln::cl_I>(x))) {
- // can be converted to native int
- if (dst < 0)
- c.s << "(-" << dst << ")";
- else
- c.s << dst;
- } else {
- // bignum
- c.s << "cln::cl_I(\"";
- print_real_number(c, x);
- c.s << "\")";
- }
+ int dst;
+ // fixnum
+ if (coerce(dst, cln::the<cln::cl_I>(x))) {
+ // can be converted to native int
+ if (dst < 0)
+ c.s << '(' << dst << ')';
+ else
+ c.s << dst;
+ } else {
+ // bignum
+ c.s << "cln::cl_I(\"";
+ print_real_number(c, x);
+ c.s << "\")";
+ }
} else if (cln::instanceof(x, cln::cl_RA_ring)) {
// Rational number
case info_flags::negative:
return is_negative();
case info_flags::nonnegative:
- return !is_negative();
+ return is_zero() || is_positive();
case info_flags::posint:
return is_pos_integer();
case info_flags::negint:
return is_odd();
case info_flags::prime:
return is_prime();
- case info_flags::algebraic:
- return !is_real();
}
return false;
}
/** Evaluation of numbers doesn't do anything at all. */
-ex numeric::eval(int level) const
+ex numeric::eval() const
{
- // Warning: if this is ever gonna do something, the ex ctors from all kinds
- // of numbers should be checking for status_flags::evaluated.
return this->hold();
}
* currently set. In case the object already was a floating point number the
* precision is trimmed to match the currently set default.
*
- * @param level ignored, only needed for overriding basic::evalf.
* @return an ex-handle to a numeric. */
-ex numeric::evalf(int level) const
+ex numeric::evalf() const
{
- // level can safely be discarded for numeric objects.
return numeric(cln::cl_float(1.0, cln::default_float_format) * value);
}
return other;
else if (&other==_num0_p)
return *this;
-
- return static_cast<const numeric &>((new numeric(value + other.value))->
- setflag(status_flags::dynallocated));
+
+ return dynallocate<numeric>(value + other.value);
}
// hack is supposed to keep the number of distinct numeric objects low.
if (&other==_num0_p || cln::zerop(other.value))
return *this;
-
- return static_cast<const numeric &>((new numeric(value - other.value))->
- setflag(status_flags::dynallocated));
+
+ return dynallocate<numeric>(value - other.value);
}
else if (&other==_num1_p)
return *this;
- return static_cast<const numeric &>((new numeric(value * other.value))->
- setflag(status_flags::dynallocated));
+ return dynallocate<numeric>(value * other.value);
}
return *this;
if (cln::zerop(cln::the<cln::cl_N>(other.value)))
throw std::overflow_error("division by zero");
- return static_cast<const numeric &>((new numeric(value / other.value))->
- setflag(status_flags::dynallocated));
+
+ return dynallocate<numeric>(value / other.value);
}
else
return *_num0_p;
}
- return static_cast<const numeric &>((new numeric(cln::expt(value, other.value)))->
- setflag(status_flags::dynallocated));
+
+ return dynallocate<numeric>(cln::expt(value, other.value));
}
if (cln::instanceof(r, cln::cl_RA_ring) && cln::instanceof(i, cln::cl_RA_ring)) {
const cln::cl_I s = cln::lcm(cln::denominator(r), cln::denominator(i));
return numeric(cln::complex(cln::numerator(r)*(cln::exquo(s,cln::denominator(r))),
- cln::numerator(i)*(cln::exquo(s,cln::denominator(i)))));
+ cln::numerator(i)*(cln::exquo(s,cln::denominator(i)))));
}
}
// at least one float encountered
return *_num0_p;
if (x.is_real() && y.is_real())
return numeric(cln::atan(cln::the<cln::cl_R>(x.to_cl_N()),
- cln::the<cln::cl_R>(y.to_cl_N())));
+ cln::the<cln::cl_R>(y.to_cl_N())));
// Compute -I*log((x+I*y)/sqrt(x^2+y^2))
// == -I*log((x+I*y)/sqrt((x+I*y)*(x-I*y)))
std::vector<cln::cl_N> *current_vector;
};
-std::vector<cln::cl_N>* lanczos_coeffs::coeffs = 0;
+std::vector<cln::cl_N>* lanczos_coeffs::coeffs = nullptr;
bool lanczos_coeffs::sufficiently_accurate(int digits)
{ if (digits<=20) {
{
cln::cl_N A = (*current_vector)[0];
int size = current_vector->size();
- for (int i=1; i<size; ++i)
- A = A + (*current_vector)[i]/(x+cln::cl_I(-1+i));
+ for (int i=1; i<size; ++i)
+ A = A + (*current_vector)[i]/(x+cln::cl_I(-1+i));
return A;
}
coeffs[3].swap(coeffs_120);
}
-static const cln::float_format_t guess_precision(const cln::cl_N& x)
+static 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))
- 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-cln::cl_N(1)/2)*log(temp)
- - temp
- + log(A);
- return result;
+ cln::cl_N result = log(cln::cl_I(2)*pi_val)/2
+ + (x-cln::cl_N(1)/2)*log(temp)
+ - temp
+ + log(A);
+ return result;
}
else
throw dunno();
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 - cln::cl_N(1)/2)
- * exp(-temp) * A;
- return result;
+ cln::cl_N result = sqrt(cln::cl_I(2)*pi_val)
+ * expt(temp, x - cln::cl_N(1)/2)
+ * exp(-temp) * A;
+ return result;
}
else
throw dunno();
results.reserve(n/2);
for (unsigned p=next_r; p<=n; p+=2) {
- cln::cl_I c = 1; // seed for binonmial coefficients
+ cln::cl_I c = 1; // seed for binomial coefficients
cln::cl_RA b = cln::cl_RA(p-1)/-2;
// The CLN manual says: "The conversion from `unsigned int' works only
// if the argument is < 2^29" (This is for 32 Bit machines. More
c = cln::exquo((c * (p+3-2*k)) * (p/2-k+1), cln::cl_I(2*k-1)*k);
b = b + c*results[k-1];
}
- }
+ }
results.push_back(-b/(p+1));
}
next_r = n+2;
// F(2n+2) = F(n+1)*(2*F(n) + F(n+1))
if (n.is_zero())
return *_num0_p;
- if (n.is_negative())
- if (n.is_even())
+ if (n.is_negative()) {
+ if (n.is_even()) {
return -fibonacci(-n);
- else
+ }
+ else {
return fibonacci(-n);
+ }
+ }
cln::cl_I u(0);
cln::cl_I v(1);
/** Modulus (in symmetric representation).
- * Equivalent to Maple's mods.
*
- * @return a mod b in the range [-iquo(abs(b)-1,2), iquo(abs(b),2)]. */
-const numeric smod(const numeric &a, const numeric &b)
-{
- if (a.is_integer() && b.is_integer()) {
- const cln::cl_I b2 = cln::ceiling1(cln::the<cln::cl_I>(b.to_cl_N()) >> 1) - 1;
- return numeric(cln::mod(cln::the<cln::cl_I>(a.to_cl_N()) + b2,
- cln::the<cln::cl_I>(b.to_cl_N())) - b2);
+ * @return a mod b in the range [-iquo(abs(b),2), iquo(abs(b),2)]. */
+const numeric smod(const numeric &a_, const numeric &b_)
+{
+ if (a_.is_integer() && b_.is_integer()) {
+ const cln::cl_I a = cln::the<cln::cl_I>(a_.to_cl_N());
+ const cln::cl_I b = cln::the<cln::cl_I>(b_.to_cl_N());
+ const cln::cl_I b2 = b >> 1;
+ const cln::cl_I m = cln::mod(a, b);
+ const cln::cl_I m_b = m - b;
+ const cln::cl_I ret = m > b2 ? m_b : m;
+ return numeric(ret);
} else
return *_num0_p;
}
cln::default_float_format = cln::float_format(prec);
// call registered callbacks
- std::vector<digits_changed_callback>::const_iterator it = callbacklist.begin(), end = callbacklist.end();
- for (; it != end; ++it) {
- (*it)(digitsdiff);
+ for (auto it : callbacklist) {
+ (it)(digitsdiff);
}
return *this;