[poincare] Fix LCM

This commit is contained in:
Émilie Feral
2018-08-27 17:38:07 +02:00
parent 1853e35d39
commit 5dcdaf3a6b
7 changed files with 96 additions and 65 deletions

View File

@@ -80,6 +80,7 @@ objs += $(addprefix poincare/src/,\
infinity.o\
integer.o\
layout_helper.o\
least_common_multiple.o\
logarithm.o\
opposite.o\
matrix.o\

View File

@@ -144,6 +144,7 @@
#include <poincare/infinity.h>
#include <poincare/integer.h>
#include <poincare/global_context.h>
#include <poincare/least_common_multiple.h>
#include <poincare/logarithm.h>
#include <poincare/naperian_logarithm.h>
#include <poincare/number.h>

View File

@@ -1,21 +1,29 @@
#ifndef POINCARE_LEAST_COMMON_MULTIPLE_H
#define POINCARE_LEAST_COMMON_MULTIPLE_H
#include <poincare/layout_helper.h>
#include <poincare/static_hierarchy.h>
#include <poincare/evaluation.h>
#include <poincare/serialization_helper.h>
#include <poincare/expression.h>
namespace Poincare {
class LeastCommonMultiple : public StaticHierarchy<2> {
using StaticHierarchy<2>::StaticHierarchy;
class LeastCommonMultipleNode : public ExpressionNode {
public:
Type type() const override;
static LeastCommonMultipleNode * FailedAllocationStaticNode();
LeastCommonMultipleNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); }
// TreeNode
size_t size() const override { return sizeof(LeastCommonMultipleNode); }
int numberOfChildren() const override { return 2; }
#if POINCARE_TREE_LOG
virtual void logNodeName(std::ostream & stream) const override {
stream << "LeastCommonMultiple";
}
#endif
// ExpressionNode
Type type() const override { return Type::LeastCommonMultiple; }
private:
/* Layout */
LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override {
return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, name());
}
LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override;
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override {
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name());
}
@@ -28,6 +36,19 @@ private:
template<typename T> Evaluation<T> templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const;
};
class LeastCommonMultiple : public Expression {
public:
LeastCommonMultiple() : Expression(TreePool::sharedPool()->createTreeNode<LeastCommonMultipleNode>()) {}
LeastCommonMultiple(const LeastCommonMultipleNode * n) : Expression(n) {}
LeastCommonMultiple(Expression child1, Expression child2) : LeastCommonMultiple() {
replaceChildAtIndexInPlace(0, child1);
replaceChildAtIndexInPlace(1, child2);
}
// Expression
Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const;
};
}
#endif

View File

@@ -137,8 +137,8 @@ gcd { poincare_expression_yylval.expression = GreatCommonDivisor(); return FUNCT
im { poincare_expression_yylval.expression = ImaginaryPart(); return FUNCTION; }
/*int { poincare_expression_yylval.expression = new Integral(); return FUNCTION; }
inverse { poincare_expression_yylval.expression = new MatrixInverse(); return FUNCTION; }
lcm { poincare_expression_yylval.expression = new LeastCommonMultiple(); return FUNCTION; }
*/
lcm { poincare_expression_yylval.expression = LeastCommonMultiple(); return FUNCTION; }
ln { poincare_expression_yylval.expression = NaperianLogarithm(); return FUNCTION; }
log { return LOGFUNCTION; }
/*permute { poincare_expression_yylval.expression = new PermuteCoefficient(); return FUNCTION; }

View File

@@ -2,6 +2,7 @@
#include <poincare/rational.h>
#include <poincare/undefined.h>
#include <poincare/arithmetic.h>
#include <poincare/layout_helper.h>
extern "C" {
#include <assert.h>
@@ -10,64 +11,31 @@ extern "C" {
namespace Poincare {
ExpressionNode::Type LeastCommonMultiple::type() const {
return Type::LeastCommonMultiple;
LeastCommonMultipleNode * LeastCommonMultipleNode::FailedAllocationStaticNode() {
static AllocationFailureExpressionNode<LeastCommonMultipleNode> failure;
TreePool::sharedPool()->registerStaticNodeIfRequired(&failure);
return &failure;
}
Expression * LeastCommonMultiple::clone() const {
LeastCommonMultiple * a = new LeastCommonMultiple(m_operands, true);
return a;
LayoutReference LeastCommonMultipleNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return LayoutHelper::Prefix(LeastCommonMultiple(this), floatDisplayMode, numberOfSignificantDigits, name());
}
Expression LeastCommonMultiple::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const {
Expression e = Expression::defaultShallowReduce(context, angleUnit);
if (e.isUndefinedOrAllocationFailure()) {
return e;
}
Expression * op0 = childAtIndex(0);
Expression * op1 = childAtIndex(1);
#if MATRIX_EXACT_REDUCING
if (op0->type() == Type::Matrix || op1->type() == Type::Matrix) {
return replaceWith(new Undefined(), true);
}
#endif
if (op0->type() == Type::Rational) {
Rational * r0 = static_cast<Rational *>(op0);
if (!r0->denominator().isOne()) {
return replaceWith(new Undefined(), true);
}
}
if (op1->type() == Type::Rational) {
Rational * r1 = static_cast<Rational *>(op1);
if (!r1->denominator().isOne()) {
return replaceWith(new Undefined(), true);
}
}
if (op0->type() != Type::Rational || op1->type() != Type::Rational) {
return this;
}
Rational * r0 = static_cast<Rational *>(op0);
Rational * r1 = static_cast<Rational *>(op1);
Integer a = r0->numerator();
Integer b = r1->numerator();
Integer lcm = Arithmetic::LCM(&a, &b);
return replaceWith(new Rational(lcm), true);
Expression LeastCommonMultipleNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const {
return LeastCommonMultiple(this).shallowReduce(context, angleUnit);
}
template<typename T>
Complex<T> * LeastCommonMultiple::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
Evaluation<T> * f1Input = childAtIndex(0)->privateApproximate(T(), context, angleUnit);
Evaluation<T> * f2Input = childAtIndex(1)->privateApproximate(T(), context, angleUnit);
T f1 = f1Input->toScalar();
T f2 = f2Input->toScalar();
delete f1Input;
delete f2Input;
Evaluation<T> LeastCommonMultipleNode::templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
Evaluation<T> f1Input = childAtIndex(0)->approximate(T(), context, angleUnit);
Evaluation<T> f2Input = childAtIndex(1)->approximate(T(), context, angleUnit);
T f1 = f1Input.toScalar();
T f2 = f2Input.toScalar();
if (std::isnan(f1) || std::isnan(f2) || f1 != (int)f1 || f2 != (int)f2) {
return new Complex<T>(Complex<T>::Undefined());
return Complex<T>::Undefined();
}
if (f1 == 0.0f || f2 == 0.0f) {
return new Complex<T>(0);
return Complex<T>(0.0);
}
int a = (int)f2;
int b = (int)f1;
@@ -82,7 +50,43 @@ Complex<T> * LeastCommonMultiple::templatedApproximate(Context& context, Prefere
a = b;
b = r;
}
return new Complex<T>(product/a);
return Complex<T>(product/a);
}
Expression LeastCommonMultiple::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const {
Expression e = Expression::defaultShallowReduce(context, angleUnit);
if (e.isUndefinedOrAllocationFailure()) {
return e;
}
Expression op0 = childAtIndex(0);
Expression op1 = childAtIndex(1);
#if MATRIX_EXACT_REDUCING
if (op0.type() == Type::Matrix || op1.type() == Type::Matrix) {
return Undefined();
}
#endif
if (op0.type() == ExpressionNode::Type::Rational) {
Rational r0 = static_cast<Rational&>(op0);
if (!r0.integerDenominator().isOne()) {
return Undefined();
}
}
if (op1.type() == ExpressionNode::Type::Rational) {
Rational r1 = static_cast<Rational&>(op1);
if (!r1.integerDenominator().isOne()) {
return Undefined();
}
}
if (op0.type() != ExpressionNode::Type::Rational || op1.type() != ExpressionNode::Type::Rational) {
return *this;
}
Rational r0 = static_cast<Rational&>(op0);
Rational r1 = static_cast<Rational&>(op1);
Integer a = r0.signedIntegerNumerator();
Integer b = r1.signedIntegerNumerator();
Integer lcm = Arithmetic::LCM(a, b);
return Rational(lcm);
}
}

View File

@@ -34,12 +34,12 @@ QUIZ_CASE(poincare_parse_function) {
assert_parsed_expression_type("frac(2.3)", ExpressionNode::Type::FracPart);
assert_parsed_expression_type("gcd(2,3)", ExpressionNode::Type::GreatCommonDivisor);
assert_parsed_expression_type("im(2+I)", ExpressionNode::Type::ImaginaryPart);
assert_parsed_expression_type("lcm(2,3)", ExpressionNode::Type::LeastCommonMultiple);
#if 0
assert_parsed_expression_type("int(x, 2, 3)", ExpressionNode::Type::Integral);
#if MATRICES_ARE_DEFINED
assert_parsed_expression_type("inverse([[1,2,3][4,5,6][7,8,9]])", ExpressionNode::Type::MatrixInverse);
#endif
assert_parsed_expression_type("lcm(2,3)", ExpressionNode::Type::LeastCommonMultiple);
assert_parsed_expression_type("ln(2)", ExpressionNode::Type::NaperianLogarithm);
assert_parsed_expression_type("log(2)", ExpressionNode::Type::Logarithm);
assert_parsed_expression_type("permute(10, 4)", ExpressionNode::Type::PermuteCoefficient);
@@ -109,14 +109,14 @@ QUIZ_CASE(poincare_function_evaluate) {
assert_parsed_expression_evaluates_to<float>("im(2+3I)", "3");
assert_parsed_expression_evaluates_to<double>("im(2+3I)", "3");
assert_parsed_expression_evaluates_to<float>("lcm(234,394)", "46098");
assert_parsed_expression_evaluates_to<double>("lcm(234,394)", "46098");
#if 0
assert_parsed_expression_evaluates_to<float>("int(x, 1, 2)", "1.5");
assert_parsed_expression_evaluates_to<double>("int(x, 1, 2)", "1.5");
assert_parsed_expression_evaluates_to<float>("lcm(234,394)", "46098");
assert_parsed_expression_evaluates_to<double>("lcm(234,394)", "46098");
assert_parsed_expression_evaluates_to<float>("ln(2)", "0.6931472");
assert_parsed_expression_evaluates_to<double>("ln(2)", "6.9314718055995E-1");
@@ -275,9 +275,9 @@ QUIZ_CASE(poincare_function_simplify) {
assert_parsed_expression_simplify_to("frac(-1.3)", "7/10");
assert_parsed_expression_simplify_to("gcd(123,278)", "1");
assert_parsed_expression_simplify_to("gcd(11,121)", "11");
#if 0
assert_parsed_expression_simplify_to("lcm(123,278)", "34194");
assert_parsed_expression_simplify_to("lcm(11,121)", "121");
#if 0
assert_parsed_expression_simplify_to("R(4)", "2");
assert_parsed_expression_simplify_to("root(4,3)", "root(4,3)");
assert_parsed_expression_simplify_to("root(4,P)", "4^(1/P)");

View File

@@ -10,8 +10,12 @@ static inline int pool_size() {
}
#if POINCARE_TREE_LOG
static inline void log_pool() {
Poincare::TreePool::sharedPool()->flatLog(std::cout);
Poincare::TreePool::sharedPool()->treeLog(std::cout);
}
static void log_pool_tree() {
Poincare::TreePool::sharedPool()->treeLog(std::cout);
}
#endif
static void assert_pool_size(int i) {