#include "cartesian_function.h" #include #include using namespace Poincare; namespace Graph { CartesianFunction::CartesianFunction(const char * text, KDColor color) : Shared::Function(text, color), m_displayDerivative(false) { } bool CartesianFunction::displayDerivative() { return m_displayDerivative; } void CartesianFunction::setDisplayDerivative(bool display) { m_displayDerivative = display; } double CartesianFunction::approximateDerivative(double x, Poincare::Context * context) const { Poincare::Complex abscissa = Poincare::Complex::Float(x); Poincare::Expression * args[2] = {expression(context), &abscissa}; Poincare::Derivative derivative(args, true); /* TODO: when we will simplify derivative, we might want to simplify the * derivative here. However, we might want to do it once for all x (to avoid * lagging in the derivative table. */ return derivative.approximateToScalar(*context); } double CartesianFunction::sumBetweenBounds(double start, double end, Poincare::Context * context) const { Poincare::Complex x = Poincare::Complex::Float(start); Poincare::Complex y = Poincare::Complex::Float(end); Poincare::Expression * args[3] = {expression(context), &x, &y}; Poincare::Integral integral(args, true); /* TODO: when we will simplify integral, we might want to simplify the * integral here. However, we might want to do it once for all x (to avoid * lagging in the derivative table. */ return integral.approximateToScalar(*context); } CartesianFunction::Point CartesianFunction::mininimumBetweenBounds(double start, double end, Poincare::Context * context) const { Point p = brentAlgorithm(start, end, context); if (evaluateAtAbscissa(p.abscissa-k_sqrtEps, context) < p.value || evaluateAtAbscissa(p.abscissa+k_sqrtEps, context) < p.value || std::isnan(p.value)) { p.abscissa = NAN; p.value = NAN; } return p; } char CartesianFunction::symbol() const { return 'x'; } CartesianFunction::Point CartesianFunction::brentAlgorithm(double ax, double bx, Context * context) const { double e = 0.0; double a = ax; double b = bx; double x = a+k_goldenRatio*(b-a); double v = x; double w = x; double fx = evaluateAtAbscissa(x, context); double fw = fx; double fv = fw; double d = NAN; double u, fu; for (int i = 0; i < 100; i++) { double m = 0.5*(a+b); double tol1 = k_sqrtEps*std::fabs(x)+1E-10; double tol2 = 2.0*tol1; if (std::fabs(x-m) <= tol2-0.5*(b-a)) { Point result = {.abscissa = x, .value = fx}; return result; } double p = 0; double q = 0; double r = 0; if (std::fabs(e) > tol1) { r = (x-w)*(fx-fv); q = (x-v)*(fx-fw); p = (x-v)*q -(x-w)*r; q = 2.0*(q-r); if (q>0.0) { p = -p; } else { q = -q; } r = e; e = d; } if (std::fabs(p) < std::fabs(0.5*q*r) && p= tol1 ? d : (d>0 ? tol1 : -tol1)); fu = evaluateAtAbscissa(u, context); if (fu <= fx) { if (u