mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 08:47:28 +01:00
[poincare] Fix Round
This commit is contained in:
@@ -102,6 +102,7 @@ objs += $(addprefix poincare/src/,\
|
||||
product.o\
|
||||
rational.o\
|
||||
real_part.o\
|
||||
round.o\
|
||||
sequence.o\
|
||||
serialization_helper.o\
|
||||
simplification_helper.o\
|
||||
|
||||
@@ -158,6 +158,7 @@
|
||||
#include <poincare/decimal.h>
|
||||
#include <poincare/rational.h>
|
||||
#include <poincare/real_part.h>
|
||||
#include <poincare/round.h>
|
||||
#include <poincare/store.h>
|
||||
#include <poincare/sum.h>
|
||||
#include <poincare/symbol.h>
|
||||
|
||||
@@ -68,6 +68,7 @@ private:
|
||||
|
||||
class Power : public Expression {
|
||||
friend class PowerNode;
|
||||
friend class Round;
|
||||
public:
|
||||
Power(Expression base, Expression exponent) : Expression(TreePool::sharedPool()->createTreeNode<PowerNode>()) {
|
||||
replaceChildAtIndexInPlace(0, base);
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
|
||||
class RealPartNode : public ExpressionNode {
|
||||
public:
|
||||
// Allocation Failure
|
||||
|
||||
@@ -2,34 +2,56 @@
|
||||
#define POINCARE_ROUND_H
|
||||
|
||||
#include <poincare/layout_helper.h>
|
||||
#include <poincare/static_hierarchy.h>
|
||||
#include <poincare/expression.h>
|
||||
#include <poincare/evaluation.h>
|
||||
#include <poincare/serialization_helper.h>
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
class Round : public StaticHierarchy<2> {
|
||||
using StaticHierarchy<2>::StaticHierarchy;
|
||||
class RoundNode : public ExpressionNode {
|
||||
public:
|
||||
Type type() const override;
|
||||
private:
|
||||
/* Layout */
|
||||
LayoutRef createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const override {
|
||||
return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, name());
|
||||
// Allocation Failure
|
||||
static RoundNode * FailedAllocationStaticNode();
|
||||
RoundNode * failedAllocationStaticNode() override { return FailedAllocationStaticNode(); }
|
||||
|
||||
// TreeNode
|
||||
size_t size() const override { return sizeof(RoundNode); }
|
||||
int numberOfChildren() const override { return 2; }
|
||||
#if POINCARE_TREE_LOG
|
||||
virtual void logNodeName(std::ostream & stream) const override {
|
||||
stream << "Round";
|
||||
}
|
||||
#endif
|
||||
|
||||
// Properties
|
||||
Type type() const override { return Type::Round; }
|
||||
private:
|
||||
// Layout
|
||||
LayoutReference 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());
|
||||
}
|
||||
const char * name() const { return "round"; }
|
||||
/* Simplification */
|
||||
// Simplification
|
||||
Expression shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const override;
|
||||
/* Complex */
|
||||
// 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;
|
||||
};
|
||||
|
||||
class Round : public Expression {
|
||||
public:
|
||||
Round() : Expression(TreePool::sharedPool()->createTreeNode<RoundNode>()) {}
|
||||
Round(const RoundNode * n) : Expression(n) {}
|
||||
Round(Expression operand0, Expression operand1) : Round() {
|
||||
replaceChildAtIndexInPlace(0, operand0);
|
||||
replaceChildAtIndexInPlace(1, operand1);
|
||||
}
|
||||
|
||||
Expression shallowReduce(Context & context, Preferences::AngleUnit angleUnit) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -151,8 +151,7 @@ randint { poincare_expression_yylval.expression = new Randint(); return FUNCTION
|
||||
re { poincare_expression_yylval.expression = RealPart(); return FUNCTION; }
|
||||
rem { poincare_expression_yylval.expression = DivisionRemainder(); return FUNCTION; }
|
||||
root { poincare_expression_yylval.expression = NthRoot(); return FUNCTION; }
|
||||
/*round { poincare_expression_yylval.expression = new Round(); return FUNCTION; }
|
||||
*/
|
||||
round { poincare_expression_yylval.expression = Round(); return FUNCTION; }
|
||||
sin { poincare_expression_yylval.expression = Sine(); return FUNCTION; }
|
||||
sinh { poincare_expression_yylval.expression = HyperbolicSine(); return FUNCTION; }
|
||||
sum { poincare_expression_yylval.expression = Sum(); return FUNCTION; }
|
||||
|
||||
@@ -10,13 +10,31 @@ extern "C" {
|
||||
|
||||
namespace Poincare {
|
||||
|
||||
ExpressionNode::Type Round::type() const {
|
||||
return Type::Round;
|
||||
RoundNode * RoundNode::FailedAllocationStaticNode() {
|
||||
static AllocationFailureExpressionNode<RoundNode> failure;
|
||||
TreePool::sharedPool()->registerStaticNodeIfRequired(&failure);
|
||||
return &failure;
|
||||
}
|
||||
|
||||
Expression * Round::clone() const {
|
||||
Round * c = new Round(m_operands, true);
|
||||
return c;
|
||||
LayoutReference RoundNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
|
||||
return LayoutHelper::Prefix(Round(this), floatDisplayMode, numberOfSignificantDigits, name());
|
||||
}
|
||||
|
||||
Expression RoundNode::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const {
|
||||
return Round(this).shallowReduce(context, angleUnit);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Evaluation<T> RoundNode::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(f2) || f2 != std::round(f2)) {
|
||||
return Complex<T>::Undefined();
|
||||
}
|
||||
T err = std::pow(10, std::floor(f2));
|
||||
return Complex<T>(std::round(f1*err)/err);
|
||||
}
|
||||
|
||||
Expression Round::shallowReduce(Context& context, Preferences::AngleUnit angleUnit) const {
|
||||
@@ -25,46 +43,30 @@ Expression Round::shallowReduce(Context& context, Preferences::AngleUnit angleUn
|
||||
return e;
|
||||
}
|
||||
#if MATRIX_EXACT_REDUCING
|
||||
if (childAtIndex(0)->type() == Type::Matrix || childAtIndex(1)->type() == Type::Matrix) {
|
||||
return replaceWith(new Undefined(), true);
|
||||
if (childAtIndex(0).type() == ExpressionNode::Type::Matrix || childAtIndex(1).type() == ExpressionNode::Type::Matrix) {
|
||||
return Undefined();
|
||||
}
|
||||
#endif
|
||||
if (childAtIndex(0)->type() == Type::Rational && childAtIndex(1)->type() == Type::Rational) {
|
||||
Rational * r1 = static_cast<Rational *>(childAtIndex(0));
|
||||
Rational * r2 = static_cast<Rational *>(childAtIndex(1));
|
||||
if (!r2->denominator().isOne()) {
|
||||
return replaceWith(new Undefined(), true);
|
||||
if (childAtIndex(0).type() == ExpressionNode::Type::Rational && childAtIndex(1).type() == ExpressionNode::Type::Rational) {
|
||||
Rational r1 = static_cast<Rational>(childAtIndex(0));
|
||||
Rational r2 = static_cast<Rational>(childAtIndex(1));
|
||||
if (!r2.integerDenominator().isOne()) {
|
||||
return Undefined();
|
||||
}
|
||||
const Rational ten(10);
|
||||
if (Power::RationalExponentShouldNotBeReduced(&ten, r2)) {
|
||||
return this;
|
||||
if (Power::RationalExponentShouldNotBeReduced(ten, r2)) {
|
||||
return *this;
|
||||
}
|
||||
Rational err = Rational::Power(ten, r2->numerator());
|
||||
Rational mult = Rational::Multiplication(*r1, err);
|
||||
IntegerDivision d = Integer::Division(mult.numerator(), mult.denominator());
|
||||
Rational err = Rational::IntegerPower(ten, r2.signedIntegerNumerator());
|
||||
Rational mult = Rational::Multiplication(r1, err);
|
||||
IntegerDivision d = Integer::Division(mult.signedIntegerNumerator(), mult.integerDenominator());
|
||||
Integer rounding = d.quotient;
|
||||
if (Rational::NaturalOrder(Rational(d.remainder, mult.denominator()), Rational(1,2)) >= 0) {
|
||||
if (Rational::NaturalOrder(Rational(d.remainder, mult.integerDenominator()), Rational(1,2)) >= 0) {
|
||||
rounding = Integer::Addition(rounding, Integer(1));
|
||||
}
|
||||
Rational result = Rational::Multiplication(rounding, Rational::Power(Rational(1,10), r2->numerator()));
|
||||
return replaceWith(new Rational(result), true);
|
||||
return Rational::Multiplication(rounding, Rational::IntegerPower(Rational(1,10), r2.signedIntegerNumerator()));
|
||||
}
|
||||
return this; // TODO: implement for rationals!
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Complex<T> * Round::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();
|
||||
delete f1Input;
|
||||
delete f2Input;
|
||||
if (std::isnan(f2) || f2 != std::round(f2)) {
|
||||
return new Complex<T>(Complex<T>::Undefined());
|
||||
}
|
||||
T err = std::pow(10, std::floor(f2));
|
||||
return new Complex<T>(std::round(f1*err)/err);
|
||||
return *this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,9 +56,7 @@ QUIZ_CASE(poincare_parse_function) {
|
||||
assert_parsed_expression_type("rem(29, 10)", ExpressionNode::Type::DivisionRemainder);
|
||||
assert_parsed_expression_type("root(2,3)", ExpressionNode::Type::NthRoot);
|
||||
assert_parsed_expression_type("R(2)", ExpressionNode::Type::SquareRoot);
|
||||
#if 0
|
||||
assert_parsed_expression_type("round(2,3)", ExpressionNode::Type::Round);
|
||||
#endif
|
||||
assert_parsed_expression_type("sum(n, 4, 10)", ExpressionNode::Type::Sum);
|
||||
#if MATRICES_ARE_DEFINED
|
||||
assert_parsed_expression_type("trace([[1,2,3][4,5,6][7,8,9]])", ExpressionNode::Type::MatrixTrace);
|
||||
@@ -208,11 +206,9 @@ QUIZ_CASE(poincare_function_evaluate) {
|
||||
assert_parsed_expression_evaluates_to<double>("transpose([[1,2][4,5][7,8]])", "[[1,4,7][2,5,8]]");
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
assert_parsed_expression_evaluates_to<float>("round(2.3246,3)", "2.325");
|
||||
assert_parsed_expression_evaluates_to<double>("round(2.3245,3)", "2.325");
|
||||
|
||||
#endif
|
||||
assert_parsed_expression_evaluates_to<float>("6!", "720");
|
||||
assert_parsed_expression_evaluates_to<double>("6!", "720");
|
||||
|
||||
@@ -273,12 +269,12 @@ QUIZ_CASE(poincare_function_simplify) {
|
||||
assert_parsed_expression_simplify_to("root(4,3)", "root(4,3)");
|
||||
assert_parsed_expression_simplify_to("root(4,P)", "4^(1/P)");
|
||||
assert_parsed_expression_simplify_to("root(27,3)", "3");
|
||||
#if 0
|
||||
assert_parsed_expression_simplify_to("round(4.235,2)", "106/25");
|
||||
assert_parsed_expression_simplify_to("round(4.23,0)", "4");
|
||||
assert_parsed_expression_simplify_to("round(4.9,0)", "5");
|
||||
assert_parsed_expression_simplify_to("round(12.9,-1)", "10");
|
||||
assert_parsed_expression_simplify_to("round(12.9,-2)", "0");
|
||||
#if 0
|
||||
assert_parsed_expression_simplify_to("permute(99,4)", "90345024");
|
||||
assert_parsed_expression_simplify_to("permute(20,-10)", "undef");
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user