mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-03-29 11:39:58 +02:00
[poincare] Fix Factor
This commit is contained in:
@@ -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\
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user