mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
[poincare] Exact undef results with GCD and LCM
Change-Id: Iba39cd6140d8ef5b3fd24e0f53c9e28fbd57d438
This commit is contained in:
committed by
Émilie Feral
parent
a89878a24d
commit
073893ae48
@@ -42,7 +42,7 @@ public:
|
||||
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("gcd", -2, &UntypedBuilderMultipleChildren<GreatCommonDivisor>);
|
||||
|
||||
// Expression
|
||||
Expression shallowReduce(Context * context);
|
||||
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
|
||||
Expression shallowBeautify(Context * context);
|
||||
};
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
static constexpr Expression::FunctionHelper s_functionHelper = Expression::FunctionHelper("lcm", -2, &UntypedBuilderMultipleChildren<LeastCommonMultiple>);
|
||||
|
||||
// Expression
|
||||
Expression shallowReduce(Context * context);
|
||||
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
|
||||
Expression shallowBeautify(Context * context);
|
||||
};
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ protected:
|
||||
node()->sortChildrenInPlace(order, context, canSwapMatrices, canBeInterrupted);
|
||||
}
|
||||
NAryExpressionNode * node() const { return static_cast<NAryExpressionNode *>(Expression::node()); }
|
||||
Expression checkChildrenAreRationalIntegers(Context * context);
|
||||
Expression checkChildrenAreRationalIntegersAndUpdate(ExpressionNode::ReductionContext reductionContext);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -289,12 +289,13 @@ bool Expression::hasDefinedComplexApproximation(Context * context, Preferences::
|
||||
}
|
||||
/* We return true when both real and imaginary approximation are defined and
|
||||
* imaginary part is not null. */
|
||||
Expression imag = ImaginaryPart::Builder(*this);
|
||||
Expression e = clone();
|
||||
Expression imag = ImaginaryPart::Builder(e);
|
||||
float b = imag.approximateToScalar<float>(context, complexFormat, angleUnit);
|
||||
if (b == 0.0f || std::isinf(b) || std::isnan(b)) {
|
||||
return false;
|
||||
}
|
||||
Expression real = RealPart::Builder(*this);
|
||||
Expression real = RealPart::Builder(e);
|
||||
float a = real.approximateToScalar<float>(context, complexFormat, angleUnit);
|
||||
if (std::isinf(a) || std::isnan(a)) {
|
||||
return false;
|
||||
|
||||
@@ -16,7 +16,7 @@ int GreatCommonDivisorNode::serialize(char * buffer, int bufferSize, Preferences
|
||||
}
|
||||
|
||||
Expression GreatCommonDivisorNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return GreatCommonDivisor(this).shallowReduce(reductionContext.context());
|
||||
return GreatCommonDivisor(this).shallowReduce(reductionContext);
|
||||
}
|
||||
|
||||
Expression GreatCommonDivisorNode::shallowBeautify(ReductionContext reductionContext) {
|
||||
@@ -36,7 +36,7 @@ Expression GreatCommonDivisor::shallowBeautify(Context * context) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expression GreatCommonDivisor::shallowReduce(Context * context) {
|
||||
Expression GreatCommonDivisor::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
{
|
||||
Expression e = Expression::defaultShallowReduce();
|
||||
e = e.defaultHandleUnitsInChildren();
|
||||
@@ -51,7 +51,7 @@ Expression GreatCommonDivisor::shallowReduce(Context * context) {
|
||||
|
||||
// Step 1: check that all children are compatible
|
||||
{
|
||||
Expression checkChildren = checkChildrenAreRationalIntegers(context);
|
||||
Expression checkChildren = checkChildrenAreRationalIntegersAndUpdate(reductionContext);
|
||||
if (!checkChildren.isUninitialized()) {
|
||||
return checkChildren;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ int LeastCommonMultipleNode::serialize(char * buffer, int bufferSize, Preference
|
||||
}
|
||||
|
||||
Expression LeastCommonMultipleNode::shallowReduce(ReductionContext reductionContext) {
|
||||
return LeastCommonMultiple(this).shallowReduce(reductionContext.context());
|
||||
return LeastCommonMultiple(this).shallowReduce(reductionContext);
|
||||
}
|
||||
|
||||
Expression LeastCommonMultipleNode::shallowBeautify(ReductionContext reductionContext) {
|
||||
@@ -36,7 +36,7 @@ Expression LeastCommonMultiple::shallowBeautify(Context * context) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Expression LeastCommonMultiple::shallowReduce(Context * context) {
|
||||
Expression LeastCommonMultiple::shallowReduce(ExpressionNode::ReductionContext reductionContext) {
|
||||
{
|
||||
Expression e = Expression::defaultShallowReduce();
|
||||
e = e.defaultHandleUnitsInChildren();
|
||||
@@ -51,7 +51,7 @@ Expression LeastCommonMultiple::shallowReduce(Context * context) {
|
||||
|
||||
// Step 1: check that all children are compatible
|
||||
{
|
||||
Expression checkChildren = checkChildrenAreRationalIntegers(context);
|
||||
Expression checkChildren = checkChildrenAreRationalIntegersAndUpdate(reductionContext);
|
||||
if (!checkChildren.isUninitialized()) {
|
||||
return checkChildren;
|
||||
}
|
||||
|
||||
@@ -74,13 +74,26 @@ int NAryExpression::allChildrenAreReal(Context * context) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
Expression NAryExpression::checkChildrenAreRationalIntegers(Context * context) {
|
||||
Expression NAryExpression::checkChildrenAreRationalIntegersAndUpdate(ExpressionNode::ReductionContext reductionContext) {
|
||||
for (int i = 0; i < numberOfChildren(); ++i) {
|
||||
Expression c = childAtIndex(i);
|
||||
if (c.deepIsMatrix(context)) {
|
||||
if (c.deepIsMatrix(reductionContext.context())) {
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
if (c.type() != ExpressionNode::Type::Rational) {
|
||||
/* Replace expression with undefined if child can be approximated to a
|
||||
* complex or finite non-integer number. Otherwise, rely on template
|
||||
* approximations. hasDefinedComplexApproximation is given Cartesian
|
||||
* complex format to force imaginary part approximation. */
|
||||
if (!c.isReal(reductionContext.context()) && c.hasDefinedComplexApproximation(reductionContext.context(), Preferences::ComplexFormat::Cartesian, reductionContext.angleUnit())) {
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
// If c was complex but with a null imaginary part, real part is checked.
|
||||
float app = c.approximateToScalar<float>(reductionContext.context(), reductionContext.complexFormat(), reductionContext.angleUnit());
|
||||
if (std::isfinite(app) && app != std::round(app)) {
|
||||
return replaceWithUndefinedInPlace();
|
||||
}
|
||||
// Note : Child could be replaced with the approximation (if finite) here.
|
||||
return *this;
|
||||
}
|
||||
if (!static_cast<Rational &>(c).isInteger()) {
|
||||
|
||||
Reference in New Issue
Block a user