diff --git a/apps/calculation/additional_outputs/integer_list_controller.cpp b/apps/calculation/additional_outputs/integer_list_controller.cpp index 634c24f3a..d7ebd0194 100644 --- a/apps/calculation/additional_outputs/integer_list_controller.cpp +++ b/apps/calculation/additional_outputs/integer_list_controller.cpp @@ -1,6 +1,8 @@ #include "integer_list_controller.h" #include +#include #include +#include #include #include #include "../app.h" @@ -26,10 +28,30 @@ Integer::Base baseAtIndex(int index) { void IntegerListController::setExpression(Poincare::Expression e) { ExpressionsListController::setExpression(e); static_assert(k_maxNumberOfRows >= k_indexOfFactorExpression + 1, "k_maxNumberOfRows must be greater than k_indexOfFactorExpression"); - assert(!m_expression.isUninitialized() && m_expression.type() == ExpressionNode::Type::BasedInteger); - Integer integer = static_cast(m_expression).integer(); - for (int index = 0; index < k_indexOfFactorExpression; ++index) { - m_layouts[index] = integer.createLayout(baseAtIndex(index)); + assert(!m_expression.isUninitialized() && m_expression.type() == ExpressionNode::Type::BasedInteger || (m_expression.type() == ExpressionNode::Type::Opposite && m_expression.childAtIndex(0).type() == ExpressionNode::Type::BasedInteger)); + assert(!m_expression.isUninitialized()); + + if (m_expression.type() == ExpressionNode::Type::BasedInteger) { + Integer integer = static_cast(m_expression).integer(); + for (int index = 0; index < k_indexOfFactorExpression; ++index) { + m_layouts[index] = integer.createLayout(baseAtIndex(index)); + } + } + else + { + Opposite b = static_cast(m_expression); + Expression e = b.childAtIndex(0); + Integer childInt = static_cast(e).integer(); + childInt.setNegative(true); + Integer num_bits = Integer::CeilingLog2(childInt); + Integer integer = Integer::TwosComplementToBits(childInt, num_bits); + for (int index = 0; index < k_indexOfFactorExpression; ++index) { + if(baseAtIndex(index) == Integer::Base::Decimal) { + m_layouts[index] = childInt.createLayout(baseAtIndex(index)); + } else { + m_layouts[index] = integer.createLayout(baseAtIndex(index)); + } + } } // Computing factorExpression Expression factor = Factor::Builder(m_expression.clone()); diff --git a/apps/math_toolbox.cpp b/apps/math_toolbox.cpp index 9e25b96e1..c944f0be1 100644 --- a/apps/math_toolbox.cpp +++ b/apps/math_toolbox.cpp @@ -109,7 +109,8 @@ const ToolboxMessageTree logicChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::LogicalBitClearCommandWithArg, I18n::Message::LogicalBitClear), ToolboxMessageTree::Leaf(I18n::Message::LogicalBitFlipCommandWithArg, I18n::Message::LogicalBitFlip), ToolboxMessageTree::Leaf(I18n::Message::LogicalBitsClearCommandWithArg, I18n::Message::LogicalBitsClear), - ToolboxMessageTree::Leaf(I18n::Message::TwosComplementToBitsCommandWithArg, I18n::Message::TwosComplementToBits) + ToolboxMessageTree::Leaf(I18n::Message::TwosComplementToBitsCommandWithArg, I18n::Message::TwosComplementToBits), + ToolboxMessageTree::Leaf(I18n::Message::CeilingLog2CommandWithArg, I18n::Message::CeilingLog2) }; #if LIST_ARE_DEFINED diff --git a/apps/shared.universal.i18n b/apps/shared.universal.i18n index 90eaea59e..5eb42a2c8 100644 --- a/apps/shared.universal.i18n +++ b/apps/shared.universal.i18n @@ -511,3 +511,4 @@ LogicalRotateRightExplicitCommandWithArg = "ror(a,r,n)" LogicalXor = "a XOR b" LogicalXorCommandWithArg = "xor(a,r)" TwosComplementToBitsCommandWithArg = "tc(a,n)" +CeilingLog2CommandWithArg = "clog2(a)" diff --git a/apps/toolbox.de.i18n b/apps/toolbox.de.i18n index 22b999cf2..c8d8dc5ae 100644 --- a/apps/toolbox.de.i18n +++ b/apps/toolbox.de.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Bitverschiebung rechts von a um s" LogicalRotateLeft = "Rotieren von a um r Bit n. links" LogicalRotateRight= "Rotieren von a um r Bit n. rechts" TwosComplementToBits = "Äquivalent im Zweierkomplement" +CeilingLog2 = "Anzahl der Bits, die zum Speichern von a benötigt werden" ExplicitNumberOfBits = "Explizite Bitbreite" diff --git a/apps/toolbox.en.i18n b/apps/toolbox.en.i18n index 2121c57d1..4e093158a 100644 --- a/apps/toolbox.en.i18n +++ b/apps/toolbox.en.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Logical shift right [a >> s]" LogicalRotateLeft = "Rotate r bits of a to the left" LogicalRotateRight= "Rotate r bits of a to the right" TwosComplementToBits = "Two's complement equivalent" +CeilingLog2 = "Number of bits needed to store a" ExplicitNumberOfBits = "Explicit number of bits" diff --git a/apps/toolbox.es.i18n b/apps/toolbox.es.i18n index 8c78f849d..483bee019 100644 --- a/apps/toolbox.es.i18n +++ b/apps/toolbox.es.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Desplazamiento lógico derecha" LogicalRotateLeft = "Gire r bits de a hacia izquierda" LogicalRotateRight= "Gire r bits de a hacia derecha" TwosComplementToBits = "Equivalente en complemento a dos" +CeilingLog2 = "Número de bits necesarios para almacenar a" ExplicitNumberOfBits = "Número explícito de bits" diff --git a/apps/toolbox.fr.i18n b/apps/toolbox.fr.i18n index 0a92022c4..92b0c2a4c 100644 --- a/apps/toolbox.fr.i18n +++ b/apps/toolbox.fr.i18n @@ -526,4 +526,5 @@ LogicalShiftRight = "Décalage logique droite [a >> s]" LogicalRotateLeft = "Rotation gauche de a par r bits" LogicalRotateRight= "Rotation droite de a par r bits" TwosComplementToBits = "Equivalent en complément à deux" +CeilingLog2 = "Nombre de bits nécessaires pour stocker a" ExplicitNumberOfBits = "Nombre indiqué de bits" diff --git a/apps/toolbox.hu.i18n b/apps/toolbox.hu.i18n index 56a8db33f..45a437bfd 100644 --- a/apps/toolbox.hu.i18n +++ b/apps/toolbox.hu.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Logikai eltolás jobbra [a >> s]" LogicalRotateLeft = "Forog r bitek nak a balra" LogicalRotateRight= "Forog r bitek nak a jobbra" TwosComplementToBits = "Kettő komplementere egyenértékű" +CeilingLog2 = "Az a tárolásához szükséges bitek száma" ExplicitNumberOfBits = "Explicit bitszám" diff --git a/apps/toolbox.it.i18n b/apps/toolbox.it.i18n index 5d34053d2..8428d633c 100644 --- a/apps/toolbox.it.i18n +++ b/apps/toolbox.it.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Spostamento logico a destra" LogicalRotateLeft = "Ruota r bit di a verso sinistra" LogicalRotateRight= "Ruota r bit di a verso destra" TwosComplementToBits = "Equivalente in complemento di due" +CeilingLog2 = "Numero di bit necessari per memorizzare a" ExplicitNumberOfBits = "Numero esplicito di bit" diff --git a/apps/toolbox.nl.i18n b/apps/toolbox.nl.i18n index 4f266d7bb..64156d405 100644 --- a/apps/toolbox.nl.i18n +++ b/apps/toolbox.nl.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Logische verschuiving naar rechts" LogicalRotateLeft = "Draai r stukjes a naar links" LogicalRotateRight= "Draai r stukjes a naar rechts" TwosComplementToBits = "Tweeën vullen equivalent aan" +CeilingLog2 = "Aantal bits dat nodig is om a op te slaan" ExplicitNumberOfBits = "Expliciet aantal bits" diff --git a/apps/toolbox.pt.i18n b/apps/toolbox.pt.i18n index 9ec6b3d2c..e36156edc 100644 --- a/apps/toolbox.pt.i18n +++ b/apps/toolbox.pt.i18n @@ -522,4 +522,5 @@ LogicalShiftRight = "Mudar lógica para a direita" LogicalRotateLeft = "Girar r bits de a para a esquerda" LogicalRotateRight= "Girar r bits de a para a direita" TwosComplementToBits = "Complementar de dois equivalente" +CeilingLog2 = "Número de bits necessários para armazenar a" ExplicitNumberOfBits = "Número explícito de bits" diff --git a/poincare/include/poincare/binary_operation.h b/poincare/include/poincare/binary_operation.h index 7d72431f1..9cbe8a2b1 100644 --- a/poincare/include/poincare/binary_operation.h +++ b/poincare/include/poincare/binary_operation.h @@ -220,6 +220,14 @@ namespace Poincare Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); }; + class CeilingLog2 final : public Expression { + public: + CeilingLog2(const BinaryOperationNode<32> *n) : Expression(n) {} + static CeilingLog2 Builder(Expression child1) { return TreeHandle::FixedArityBuilder >({child1}); } + static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("clog2", 1, &UntypedBuilderOneChild); + Expression shallowReduce(ExpressionNode::ReductionContext reductionContext); + }; + } // namespace Poincare #endif diff --git a/poincare/include/poincare/expression.h b/poincare/include/poincare/expression.h index 7ec43fbef..fb8887982 100644 --- a/poincare/include/poincare/expression.h +++ b/poincare/include/poincare/expression.h @@ -36,6 +36,7 @@ class Expression : public TreeHandle { friend class BitsClearExplicit; friend class BitSet; friend class Ceiling; + friend class CeilingLog2; friend class CommonLogarithm; template friend class ComplexNode; diff --git a/poincare/include/poincare/expression_node.h b/poincare/include/poincare/expression_node.h index 9f3b35bdd..fe9be018f 100644 --- a/poincare/include/poincare/expression_node.h +++ b/poincare/include/poincare/expression_node.h @@ -65,6 +65,7 @@ public: BinomialCoefficient, BinomPDF, Ceiling, + CeilingLog2, ComplexArgument, Conjugate, Derivative, diff --git a/poincare/include/poincare/integer.h b/poincare/include/poincare/integer.h index a31aa27f8..2e6b7500d 100644 --- a/poincare/include/poincare/integer.h +++ b/poincare/include/poincare/integer.h @@ -169,6 +169,7 @@ public: static Integer LogicalBitFlip(const Integer &a, const Integer &bit); static Integer Truncate(const Integer &a, const Integer &num_bits); static Integer TwosComplementToBits(const Integer &a, const Integer &num_bits); + static Integer CeilingLog2(const Integer &a); // Derived expression builder static Expression CreateMixedFraction(const Integer & num, const Integer & denom); diff --git a/poincare/src/binary_operation.cpp b/poincare/src/binary_operation.cpp index cbcce235e..f85683bb3 100644 --- a/poincare/src/binary_operation.cpp +++ b/poincare/src/binary_operation.cpp @@ -30,6 +30,7 @@ namespace Poincare { constexpr Expression::FunctionHelper RotateRight::s_functionHelper; constexpr Expression::FunctionHelper RotateRightExplicit::s_functionHelper; constexpr Expression::FunctionHelper TwosComplement::s_functionHelper; + constexpr Expression::FunctionHelper CeilingLog2::s_functionHelper; template<> int BinaryOperationNode<1>::numberOfChildren() const { return And::s_functionHelper.numberOfChildren(); } template<> int BinaryOperationNode<5>::numberOfChildren() const { return Or::s_functionHelper.numberOfChildren(); } @@ -53,6 +54,7 @@ namespace Poincare { template<> int BinaryOperationNode<29>::numberOfChildren() const { return RotateRight::s_functionHelper.numberOfChildren(); } template<> int BinaryOperationNode<30>::numberOfChildren() const { return RotateRightExplicit::s_functionHelper.numberOfChildren(); } template<> int BinaryOperationNode<31>::numberOfChildren() const { return TwosComplement::s_functionHelper.numberOfChildren(); } + template<> int BinaryOperationNode<32>::numberOfChildren() const { return CeilingLog2::s_functionHelper.numberOfChildren(); } template<> Layout BinaryOperationNode<1>::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { @@ -164,10 +166,15 @@ namespace Poincare { return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, TwosComplement::s_functionHelper.name()); } + template<> + Layout BinaryOperationNode<32>::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { + return LayoutHelper::Prefix(this, floatDisplayMode, numberOfSignificantDigits, CeilingLog2::s_functionHelper.name()); + } template int BinaryOperationNode::serialize(char *buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const { return SerializationHelper::Prefix(this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits, + T == 32 ? CeilingLog2::s_functionHelper.name() : T == 31 ? TwosComplement::s_functionHelper.name() : T == 30 ? RotateRightExplicit::s_functionHelper.name() : T == 29 ? RotateRight::s_functionHelper.name() : @@ -303,6 +310,11 @@ namespace Poincare { return TwosComplement(this).shallowReduce(reductionContext); } + template<> + Expression BinaryOperationNode<32>::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + return CeilingLog2(this).shallowReduce(reductionContext); + } + // Check to make sure the the expression is a positive integer Integer getValidInteger(Expression a) { if (a.type() != ExpressionNode::Type::Rational) { @@ -327,11 +339,11 @@ namespace Poincare { Integer cq; Integer x; - if(aq.isNegative() && t != ExpressionNode::Type::TwosComplement) { + if(aq.isNegative() && t != ExpressionNode::Type::TwosComplement && t != ExpressionNode::Type::CeilingLog2) { return Undefined::Builder(); } - if(t != ExpressionNode::Type::Not) { + if(t != ExpressionNode::Type::Not && t != ExpressionNode::Type::CeilingLog2) { bq = getValidInteger(e.childAtIndex(1)); if(bq.isNegative()) { return Undefined::Builder(); @@ -434,6 +446,9 @@ namespace Poincare { case ExpressionNode::Type::TwosComplement: x = Integer::TwosComplementToBits(aq, bq); break; + case ExpressionNode::Type::CeilingLog2: + x = Integer::CeilingLog2(aq); + break; default: break; } @@ -530,6 +545,10 @@ namespace Poincare { return BinaryOperation::shallowReduceDirect(*this, ExpressionNode::Type::TwosComplement, reductionContext); } + Expression CeilingLog2::shallowReduce(ExpressionNode::ReductionContext reductionContext) { + return BinaryOperation::shallowReduceDirect(*this, ExpressionNode::Type::CeilingLog2, reductionContext); + } + template int BinaryOperationNode<1>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; template int BinaryOperationNode<2>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; template int BinaryOperationNode<3>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; @@ -561,5 +580,6 @@ template int BinaryOperationNode<28>::serialize(char * buffer, int bufferSize, P template int BinaryOperationNode<29>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; template int BinaryOperationNode<30>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; template int BinaryOperationNode<31>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; +template int BinaryOperationNode<32>::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const; } // namespace Poincare \ No newline at end of file diff --git a/poincare/src/expression.cpp b/poincare/src/expression.cpp index 4c066e6c1..10c117bbc 100644 --- a/poincare/src/expression.cpp +++ b/poincare/src/expression.cpp @@ -272,7 +272,7 @@ bool Expression::isDefinedCosineOrSine(Context * context, Preferences::ComplexFo } bool Expression::isBasedIntegerCappedBy(const char * stringInteger) const { - return type() == ExpressionNode::Type::BasedInteger && (Integer::NaturalOrder(convert().integer(), Integer(stringInteger)) < 0); + return type() == ExpressionNode::Type::BasedInteger || (type() == ExpressionNode::Type::Opposite && childAtIndex(0).type() == ExpressionNode::Type::BasedInteger); // && (Integer::NaturalOrder(convert().integer(), Integer(stringInteger)) < 0); } bool Expression::isDivisionOfIntegers() const { diff --git a/poincare/src/integer.cpp b/poincare/src/integer.cpp index c780bce0a..c4fadbc4f 100644 --- a/poincare/src/integer.cpp +++ b/poincare/src/integer.cpp @@ -521,7 +521,7 @@ Integer Integer::LogicalShift(const Integer &a, const Integer &shift, const Inte return uint_final; } - // Sift Left + // Shift Left while (points > 0) { uint8_t power = (points >= 31) ? 31 : points; @@ -832,6 +832,29 @@ Integer Integer::TwosComplementToBits(const Integer &a, const Integer &num_bits) return a; } +Integer Integer::CeilingLog2(const Integer &a) +{ + if (a.isZero()) + { + return Integer(0); + } + uint8_t bits = 0; + Integer buffer; + if(a.isNegative()) { + Integer x2 = Integer::Multiplication(a,2); + x2.setNegative(false); + buffer = Integer::Subtraction(x2, Integer(1)); + } else { + buffer = a; + } + while(!buffer.isZero()) { + bits++; + buffer = Integer::LogicalShift(buffer,Integer(-1)); + } + Integer num_bits_in_a = Integer(bits); + return num_bits_in_a; +} + Integer Integer::addition(const Integer & a, const Integer & b, bool inverseBNegative, bool oneDigitOverflow) { bool bNegative = (inverseBNegative ? !b.m_negative : b.m_negative); if (a.m_negative == bNegative) { diff --git a/poincare/src/parsing/parser.h b/poincare/src/parsing/parser.h index 09e7b3964..e4d50609c 100644 --- a/poincare/src/parsing/parser.h +++ b/poincare/src/parsing/parser.h @@ -114,6 +114,7 @@ private: &BitGet::s_functionHelper, &BitSet::s_functionHelper, &Ceiling::s_functionHelper, + &CeilingLog2::s_functionHelper, &ConfidenceInterval::s_functionHelper, &Conjugate::s_functionHelper, &Cosine::s_functionHelper, diff --git a/poincare/src/tree_handle.cpp b/poincare/src/tree_handle.cpp index 9d9e010fc..06bafb197 100644 --- a/poincare/src/tree_handle.cpp +++ b/poincare/src/tree_handle.cpp @@ -295,6 +295,7 @@ template BinomialCoefficient TreeHandle::FixedArityBuilder(const Tuple &); template BinomPDF TreeHandle::FixedArityBuilder(const Tuple &); template Ceiling TreeHandle::FixedArityBuilder(const Tuple &); +template CeilingLog2 TreeHandle::FixedArityBuilder >(const Tuple &); template CeilingLayout TreeHandle::FixedArityBuilder(const Tuple &); template CommonLogarithm TreeHandle::FixedArityBuilder >(const Tuple &); template ComplexArgument TreeHandle::FixedArityBuilder(const Tuple &);