#include #include "helper.h" using namespace Poincare; enum class PointOfInterestType { Maximum, Minimum, Root, Intersection, }; bool doubles_are_approximately_equal(double d1, double d2) { bool d2IsNaN = std::isnan(d2); if (std::isnan(d1)) { return d2IsNaN; } if (d2IsNaN) { return false; } return std::abs(d1-d2) < 0.00001; } void assert_points_of_interest_are( PointOfInterestType type, int numberOfPointsOfInterest, Coordinate2D * pointsOfInterest, const char * expression1, const char * expression2, const char * symbol, double start, double step, double max, Preferences::ComplexFormat complexFormat = Preferences::ComplexFormat::Real, Preferences::AngleUnit angleUnit = Preferences::AngleUnit::Degree) { Shared::GlobalContext context; Poincare::Expression e1 = parse_expression(expression1, &context, false); Poincare::Expression e2; if (expression2) { assert(type == PointOfInterestType::Intersection); e2 = parse_expression(expression2, &context, false); } for (int i = 0; i < numberOfPointsOfInterest; i++) { quiz_assert_log_if_failure(!std::isnan(start), e1); Coordinate2D nextPointOfInterest; if (type == PointOfInterestType::Maximum) { nextPointOfInterest = e1.nextMaximum(symbol, start, step, max, &context, complexFormat, angleUnit); } else if (type == PointOfInterestType::Minimum) { nextPointOfInterest = e1.nextMinimum(symbol, start, step, max, &context, complexFormat, angleUnit); } else if (type == PointOfInterestType::Root) { nextPointOfInterest = Coordinate2D(e1.nextRoot(symbol, start, step, max, &context, complexFormat, angleUnit), 0.0); } else if (type == PointOfInterestType::Intersection) { nextPointOfInterest = e1.nextIntersection(symbol, start, step, max, &context, complexFormat, angleUnit, e2); } quiz_assert_log_if_failure( doubles_are_approximately_equal(pointsOfInterest[i].x1(), nextPointOfInterest.x1()) && doubles_are_approximately_equal(pointsOfInterest[i].x2(), nextPointOfInterest.x2()), e1); start = nextPointOfInterest.x1() + step; } } QUIZ_CASE(poincare_function_extremum) { { { constexpr int numberOfMaxima = 3; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0), Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", nullptr, "a", -1.0, 0.1, 500.0); } { constexpr int numberOfMaxima = 3; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(360.0, 1.0), Coordinate2D(0.0, 1.0), Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "cos(a)", nullptr, "a", 500.0, -0.1, -1.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", nullptr, "a", 0.0, 0.1, 300.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(180.0, -1.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "cos(a)", nullptr, "a", 300.0, -0.1, 0.0); } } { { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "a^2", nullptr, "a", 100.0, -0.1, -1.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(0.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "a^2", nullptr, "a", 100.0, -0.1, -1.0); } } { { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 3.0)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "3", nullptr, "a", 100.0, -0.1, -1.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 3.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "3", nullptr, "a", 100.0, -0.1, -1.0); } } { { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMaxima = 1; Coordinate2D maxima[numberOfMaxima] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Maximum, numberOfMaxima, maxima, "0", nullptr, "a", 100.0, -0.1, -1.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfMinima = 1; Coordinate2D minima[numberOfMinima] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Minimum, numberOfMinima, minima, "0", nullptr, "a", 100.0, -0.1, -1.0); } } } QUIZ_CASE(poincare_function_root) { { constexpr int numberOfRoots = 3; Coordinate2D roots[numberOfRoots] = { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", nullptr, "a", 0.0, 0.1, 500.0); } { constexpr int numberOfRoots = 3; Coordinate2D roots[numberOfRoots] = { Coordinate2D(450.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(90.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "cos(a)", nullptr, "a", 500.0, -0.1, 0.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(0.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2", nullptr, "a", 100.0, -0.1, -1.0); } { constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-2.0, 0.0), Coordinate2D(2.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", nullptr, "a", -5.0, 0.1, 100.0); } { constexpr int numberOfRoots = 2; Coordinate2D roots[numberOfRoots] = { Coordinate2D(2.0, 0.0), Coordinate2D(-2.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "a^2-4", nullptr, "a", 100.0, -0.1, -5.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "3", nullptr, "a", 100.0, -0.1, -1.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(-0.9, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", nullptr, "a", -1.0, 0.1, 100.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(99.9, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "0", nullptr, "a", 100.0, -0.1, -1.0); } { constexpr int numberOfRoots = 1; Coordinate2D roots[numberOfRoots] = { Coordinate2D(NAN, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Root, numberOfRoots, roots, "ℯ^x", nullptr, "a", -1000.0, 0.1, -800); } } QUIZ_CASE(poincare_function_intersection) { { constexpr int numberOfIntersections = 1; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "2", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 1; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(NAN, NAN)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "2", "a", 500.0, -0.1, -1.0); } { constexpr int numberOfIntersections = 2; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(0.0, 1.0), Coordinate2D(360.0, 1.0)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "1", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 2; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(360.0, 1.0), Coordinate2D(0.0, 1.0)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "1", "a", 500.0, -0.1, -1.0); } { constexpr int numberOfIntersections = 3; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(90.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(450.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "0", "a", -1.0, 0.1, 500.0); } { constexpr int numberOfIntersections = 3; Coordinate2D intersections[numberOfIntersections] = { Coordinate2D(450.0, 0.0), Coordinate2D(270.0, 0.0), Coordinate2D(90.0, 0.0)}; assert_points_of_interest_are(PointOfInterestType::Intersection, numberOfIntersections, intersections, "cos(a)", "0", "a", 500.0, -0.1, -1.0); } }