Files
Upsilon/poincare/src/factorial.cpp
Émilie Feral 9fbec16db4 [poincare] Merge MultiplicationImplicit and MultiplicationExplicit (they
were required if we wanted to parse into two distincts expression 2π and
2*π but don't)
2019-08-08 17:22:05 +02:00

131 lines
4.2 KiB
C++

#include <poincare/factorial.h>
#include <poincare/code_point_layout.h>
#include <poincare/constant.h>
#include <poincare/horizontal_layout.h>
#include <poincare/parenthesis.h>
#include <poincare/rational.h>
#include <poincare/serialization_helper.h>
#include <poincare/symbol.h>
#include <poincare/undefined.h>
#include <cmath>
namespace Poincare {
// Property
Expression FactorialNode::setSign(Sign s, ReductionContext reductionContext) {
assert(s == Sign::Positive);
return Factorial(this);
}
bool FactorialNode::childNeedsUserParentheses(const Expression & child) const {
if (child.isNumber() && static_cast<const Number &>(child).sign() == Sign::Negative) {
return true;
}
Type types[] = {Type::Subtraction, Type::Opposite, Type::Multiplication, Type::Addition};
return child.isOfType(types, 4);
}
// Layout
bool FactorialNode::childNeedsSystemParenthesesAtSerialization(const TreeNode * child) const {
/* 2
* --- ! ---> [2/3]!
* 3
*/
if (static_cast<const ExpressionNode *>(child)->type() == Type::Rational && !static_cast<const RationalNode *>(child)->isInteger()) {
return true;
}
Type types[] = {Type::Division, Type::Power};
return static_cast<const ExpressionNode *>(child)->isOfType(types, 2);
}
// Simplification
Expression FactorialNode::shallowReduce(ReductionContext reductionContext) {
return Factorial(this).shallowReduce(reductionContext);
}
template<typename T>
Complex<T> FactorialNode::computeOnComplex(const std::complex<T> c, Preferences::ComplexFormat, Preferences::AngleUnit angleUnit) {
T n = c.real();
if (c.imag() != 0 || std::isnan(n) || n != (int)n || n < 0) {
return Complex<T>::Undefined();
}
T result = 1;
for (int i = 1; i <= (int)n; i++) {
result *= (T)i;
if (std::isinf(result)) {
return Complex<T>::Builder(result);
}
}
return Complex<T>::Builder(std::round(result));
}
Layout FactorialNode::createLayout(Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
HorizontalLayout result = HorizontalLayout::Builder();
result.addOrMergeChildAtIndex(childAtIndex(0)->createLayout(floatDisplayMode, numberOfSignificantDigits), 0, false);
int childrenCount = result.numberOfChildren();
result.addChildAtIndex(CodePointLayout::Builder('!'), childrenCount, childrenCount, nullptr);
return result;
}
int FactorialNode::serialize(char * buffer, int bufferSize, Preferences::PrintFloatMode floatDisplayMode, int numberOfSignificantDigits) const {
int numberOfChar = SerializationHelper::SerializeChild(childAtIndex(0), this, buffer, bufferSize, floatDisplayMode, numberOfSignificantDigits);
if ((numberOfChar < 0) || (numberOfChar >= bufferSize-1)) {
return numberOfChar;
}
numberOfChar += SerializationHelper::CodePoint(&buffer[numberOfChar], bufferSize-numberOfChar, '!');
buffer[numberOfChar] = 0;
return numberOfChar;
}
Expression Factorial::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
{
Expression e = Expression::defaultShallowReduce();
if (e.isUndefined()) {
return e;
}
}
Expression c = childAtIndex(0);
if (c.type() == ExpressionNode::Type::Matrix) {
return mapOnMatrixFirstChild(reductionContext);
}
if (c.type() == ExpressionNode::Type::Rational) {
Rational r = c.convert<Rational>();
if (!r.isInteger() || r.sign() == ExpressionNode::Sign::Negative) {
return replaceWithUndefinedInPlace();
}
if (Integer(k_maxOperandValue).isLowerThan(r.unsignedIntegerNumerator())) {
return *this;
}
Rational fact = Rational::Builder(Integer::Factorial(r.unsignedIntegerNumerator()));
assert(!fact.numeratorOrDenominatorIsInfinity()); // because fact < k_maxOperandValue!
replaceWithInPlace(fact);
return fact;
}
if (c.type() == ExpressionNode::Type::Constant) {
// e! = undef, i! = undef, pi! = undef
return replaceWithUndefinedInPlace();
}
return *this;
}
#if 0
int Factorial::simplificationOrderGreaterType(const Expression * e) const {
if (SimplificationOrder(childAtIndex(0),e) == 0) {
return 1;
}
return SimplificationOrder(childAtIndex(0), e);
}
int Factorial::simplificationOrderSameType(const Expression * e) const {
return SimplificationOrder(childAtIndex(0), e->childAtIndex(0));
}
#endif
}