[poincare] Fix Factor

This commit is contained in:
Émilie Feral
2018-08-27 16:28:05 +02:00
parent c489af25e9
commit 9f5e953104
6 changed files with 80 additions and 65 deletions

View File

@@ -61,6 +61,7 @@ objs += $(addprefix poincare/src/,\
expression_lexer.o\
expression_node.o\
expression_parser.o\
factor.o\
factorial.o\
float.o\
floor.o\

View File

@@ -122,6 +122,7 @@
#include <poincare/division_remainder.h>
#include <poincare/empty_expression.h>
#include <poincare/equal.h>
#include <poincare/factor.h>
#include <poincare/factorial.h>
#include <poincare/floor.h>
#include <poincare/frac_part.h>

View File

@@ -2,38 +2,57 @@
#define POINCARE_FACTOR_H
#include <poincare/layout_helper.h>
#include <poincare/static_hierarchy.h>
#include <poincare/multiplication.h>
#include <poincare/serialization_helper.h>
#include <poincare/expression.h>
#include <poincare/rational.h>
#include <poincare/multiplication.h>
#include <cmath>
namespace Poincare {
class Factor : public StaticHierarchy<1> {
using StaticHierarchy<1>::StaticHierarchy;
class FactorNode : public ExpressionNode {
public:
Type type() const override;
// Allocation Failure
static FactorNode * FailedAllocationStaticNode();
FactorNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); }
// TreeNode
size_t size() const override { return sizeof(FactorNode); }
int numberOfChildren() const override { return 1; }
#if POINCARE_TREE_LOG
virtual void logNodeName(std::ostream & stream) const override {
stream << "Factor";
}
#endif
Type type() const override { return Type::Factor; }
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;
/* Serialization */
int serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override {
return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, name());
}
const char * name() const { return "factor"; }
/* Simplification */
Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) override;
Expression * createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit);
Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const override;
/* Evaluation */
Evaluation<float> approximate(SinglePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<float>(context, angleUnit); }
Evaluation<double> approximate(DoublePrecision p, Context& context, Preferences::AngleUnit angleUnit) const override { return templatedApproximate<double>(context, angleUnit); }
template<typename T> Evaluation<T> templatedApproximate(Context& context, Preferences::AngleUnit angleUnit) const {
return childAtIndex(0)->privateApproximate(T(), context, angleUnit);
return childAtIndex(0)->approximate(T(), context, angleUnit);
}
};
class Factor : public Expression {
public:
Factor() : Expression(TreePool::sharedPool()->createTreeNode<FactorNode>()) {}
Factor(const FactorNode * n) : Expression(n) {}
Factor(Expression operand) : Factor() {
replaceChildAtIndexInPlace(0, operand);
}
Expression shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const;
Multiplication createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit) const;
};
}
#endif

View File

@@ -130,8 +130,7 @@ conj { poincare_expression_yylval.expression = Conjugate(); return FUNCTION; }
det { poincare_expression_yylval.expression = Determinant(); return FUNCTION; }
cos { poincare_expression_yylval.expression = Cosine(); return FUNCTION; }
cosh { poincare_expression_yylval.expression = HyperbolicCosine(); return FUNCTION; }
/*factor { poincare_expression_yylval.expression = new Factor(); return FUNCTION; }
*/
factor { poincare_expression_yylval.expression = new Factor(); return FUNCTION; }
floor { poincare_expression_yylval.expression = Floor(); return FUNCTION; }
frac { poincare_expression_yylval.expression = FracPart(); return FUNCTION; }
gcd { poincare_expression_yylval.expression = GreatCommonDivisor(); return FUNCTION; }

View File

@@ -13,74 +13,69 @@ extern "C" {
namespace Poincare {
ExpressionNode::Type Factor::type() const {
return Type::Factor;
FactorNode * FactorNode::FailedAllocationStaticNode() {
static AllocationFailureExpressionNode<FactorNode> failure;
TreePool::sharedPool()->registerStaticNodeIfRequired(&failure);
return &failure;
}
Expression * Factor::clone() const {
Factor * b = new Factor(m_operands, true);
return b;
LayoutRef FactorNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
return LayoutHelper::Prefix(Factor(this), floatDisplayMode, numberOfSignificantDigits, name());
}
Expression Factor::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) {
Expression * op = childAtIndex(0);
if (op->type() != Type::Rational) {
return new Undefined();
Expression FactorNode::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const {
return Factor(this).shallowBeautify(context, angleUnit);
}
Expression Factor::shallowBeautify(Context& context, Preferences::AngleUnit angleUnit) const {
Expression op = childAtIndex(0);
if (op.type() != ExpressionNode::Type::Rational) {
return Undefined();
}
Rational * r = static_cast<Rational *>(op);
if (r->isZero()) {
return replaceWith(r, true);
Rational r = static_cast<Rational &>(op);
if (r.isZero()) {
return r;
}
Expression * numeratorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r->numerator(), context, angleUnit);
Expression * result = numeratorDecomp;
if (result->type() == Type::Undefined) {
return replaceWith(result, true);
Multiplication numeratorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.unsignedIntegerNumerator(), context, angleUnit);
if (numeratorDecomp.numberOfChildren() == 0) {
return Undefined();
}
assert(numeratorDecomp->type() == Type::Multiplication);
if (!r->denominator().isOne()) {
Expression * denominatorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r->denominator(), context, angleUnit);
if (denominatorDecomp->type() == Type::Undefined) {
delete result;
return replaceWith(denominatorDecomp, true);
Expression result = numeratorDecomp.squashUnaryHierarchy();
if (!r.integerDenominator().isOne()) {
Multiplication denominatorDecomp = createMultiplicationOfIntegerPrimeDecomposition(r.integerDenominator(), context, angleUnit);
if (denominatorDecomp.numberOfChildren() == 0) {
return Undefined();
}
assert(denominatorDecomp->type() == Type::Multiplication);
result = new Division(numeratorDecomp, denominatorDecomp, false);
static_cast<Multiplication *>(denominatorDecomp)->squashUnaryHierarchy();
result = Division(numeratorDecomp, denominatorDecomp.squashUnaryHierarchy());
}
if (r->sign() == Sign::Negative) {
result = new Opposite(result, false);
if (r.sign() == ExpressionNode::Sign::Negative) {
result = Opposite(result);
}
replaceWith(result, true);
if (result == numeratorDecomp) {
return static_cast<Multiplication *>(numeratorDecomp)->squashUnaryHierarchy();
}
static_cast<Multiplication *>(numeratorDecomp)->squashUnaryHierarchy();
return result;
}
Expression * Factor::createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit) {
Multiplication Factor::createMultiplicationOfIntegerPrimeDecomposition(Integer i, Context & context, Preferences::AngleUnit angleUnit) const {
assert(!i.isZero());
i.setNegative(false);
Multiplication * m = new Multiplication();
assert(!i.isNegative());
Multiplication m;
if (i.isOne()) {
m->addOperand(new Rational(i));
m.addChildAtIndexInPlace(Rational(i), 0, 0);
return m;
}
Integer factors[Arithmetic::k_maxNumberOfPrimeFactors];
Integer coefficients[Arithmetic::k_maxNumberOfPrimeFactors];
Arithmetic::PrimeFactorization(&i, factors, coefficients, Arithmetic::k_maxNumberOfPrimeFactors);
Arithmetic::PrimeFactorization(i, factors, coefficients, Arithmetic::k_maxNumberOfPrimeFactors);
int index = 0;
if (coefficients[0].isMinusOne()) {
delete m;
return new Undefined();
// Exception: the decomposition failed
return m;
}
while (!coefficients[index].isZero() && index < Arithmetic::k_maxNumberOfPrimeFactors) {
Expression * factor = new Rational(factors[index]);
Expression factor = Rational(factors[index]);
if (!coefficients[index].isOne()) {
Expression * exponent = new Rational(coefficients[index]);
factor = new Power(factor, exponent, false);
factor = Power(factor, Rational(coefficients[index]));
}
m->addOperand(factor);
m.addChildAtIndexInPlace(factor, m.numberOfChildren(), m.numberOfChildren());
index++;
}
return m;

View File

@@ -29,9 +29,7 @@ QUIZ_CASE(poincare_parse_function) {
#endif
assert_parsed_expression_type("confidence(0.1, 100)", ExpressionNode::Type::ConfidenceInterval);
assert_parsed_expression_type("conj(2)", ExpressionNode::Type::Conjugate);
#if 0
assert_parsed_expression_type("factor(23/42)", ExpressionNode::Type::Factor);
#endif
assert_parsed_expression_type("floor(2.3)", ExpressionNode::Type::Floor);
assert_parsed_expression_type("frac(2.3)", ExpressionNode::Type::FracPart);
assert_parsed_expression_type("gcd(2,3)", ExpressionNode::Type::GreatCommonDivisor);
@@ -173,6 +171,9 @@ QUIZ_CASE(poincare_function_evaluate) {
assert_parsed_expression_evaluates_to<float>("conj(3+2*I)", "3-2*I");
assert_parsed_expression_evaluates_to<double>("conj(3+2*I)", "3-2*I");
assert_parsed_expression_evaluates_to<float>("factor(-23/4)", "-5.75");
assert_parsed_expression_evaluates_to<double>("factor(-123/24)", "-5.125");
#if 0
#if MATRICES_ARE_DEFINED
@@ -230,9 +231,6 @@ QUIZ_CASE(poincare_function_evaluate) {
assert_parsed_expression_evaluates_to<float>("root(-1,3)", "0.5+0.8660254*I");
assert_parsed_expression_evaluates_to<double>("root(-1,3)", "0.5+8.6602540378444E-1*I");
assert_parsed_expression_evaluates_to<float>("factor(-23/4)", "-5.75");
assert_parsed_expression_evaluates_to<double>("factor(-123/24)", "-5.125");
assert_parsed_expression_evaluates_to<float>("int(int(x*x,0,x),0,4)", "21.33333");
assert_parsed_expression_evaluates_to<double>("int(int(x*x,0,x),0,4)", "21.333333333333");
@@ -258,6 +256,10 @@ QUIZ_CASE(poincare_function_simplify) {
assert_parsed_expression_simplify_to("binomial(20,10)", "184756");
assert_parsed_expression_simplify_to("ceil(-1.3)", "-1");
assert_parsed_expression_simplify_to("conj(1/2)", "1/2");
assert_parsed_expression_simplify_to("factor(-10008/6895)", "-(2^3*3^2*139)/(5*7*197)");
assert_parsed_expression_simplify_to("factor(1008/6895)", "(2^4*3^2)/(5*197)");
assert_parsed_expression_simplify_to("factor(10007)", "10007");
assert_parsed_expression_simplify_to("factor(10007^2)", "undef");
assert_parsed_expression_simplify_to("quo(19,3)", "6");
assert_parsed_expression_simplify_to("quo(19,0)", "inf");
assert_parsed_expression_simplify_to("quo(-19,3)", "-7");
@@ -265,12 +267,10 @@ QUIZ_CASE(poincare_function_simplify) {
assert_parsed_expression_simplify_to("rem(-19,3)", "2");
assert_parsed_expression_simplify_to("rem(19,0)", "inf");
assert_parsed_expression_simplify_to("99!", "933262154439441526816992388562667004907159682643816214685929638952175999932299156089414639761565182862536979208272237582511852109168640000000000000000000000");
#if 0
assert_parsed_expression_simplify_to("factor(-10008/6895)", "-(2^3*3^2*139)/(5*7*197)");
assert_parsed_expression_simplify_to("factor(1008/6895)", "(2^4*3^2)/(5*197)");
assert_parsed_expression_simplify_to("factor(10007)", "10007");
assert_parsed_expression_simplify_to("factor(10007^2)", "undef");
#endif
assert_parsed_expression_simplify_to("floor(-1.3)", "-2");
assert_parsed_expression_simplify_to("frac(-1.3)", "7/10");
assert_parsed_expression_simplify_to("gcd(123,278)", "1");