[poincare] Add watthour representation to classic unit conversion

This commit is contained in:
Émilie Feral
2020-04-23 09:59:27 +02:00
parent cc114900fa
commit 4d7b9aa2a9
6 changed files with 42 additions and 0 deletions

View File

@@ -121,6 +121,7 @@ public:
bool isThree() const { return (numberOfDigits() == 1 && digit(0) == 3 && !m_negative); };
bool isTen() const { return (numberOfDigits() == 1 && digit(0) == 10 && !m_negative); };
bool isMinusOne() const { return (numberOfDigits() == 1 && digit(0) == 1 && m_negative); };
bool isMinusTwo() const { return (numberOfDigits() == 1 && digit(0) == 2 && m_negative); };
bool isZero() const { return (numberOfDigits() == 0); };
bool isEven() const { return ((digit(0) & 1) == 0); }

View File

@@ -45,8 +45,10 @@ public:
// Basic test
bool isZero() const { return unsignedNumerator().isZero(); }
bool isOne() const { return signedNumerator().isOne() && isInteger(); }
bool isTwo() const { return signedNumerator().isTwo() && isInteger(); }
bool isThree() const { return signedNumerator().isThree() && isInteger(); }
bool isMinusOne() const { return signedNumerator().isMinusOne() && isInteger(); }
bool isMinusTwo() const { return signedNumerator().isMinusTwo() && isInteger(); }
bool isHalf() const { return signedNumerator().isOne() && denominator().isTwo(); }
bool isMinusHalf() const { return signedNumerator().isMinusOne() && denominator().isTwo(); }
bool isTen() const { return signedNumerator().isTen() && isInteger(); }
@@ -90,8 +92,10 @@ public:
bool isNegative() const { return node()->isNegative(); }
bool isZero() const { return node()->isZero(); }
bool isOne() const { return node()->isOne(); }
bool isTwo() const { return node()->isTwo(); }
bool isThree() const { return node()->isThree(); }
bool isMinusOne() const { return node()->isMinusOne(); }
bool isMinusTwo() const { return node()->isMinusTwo(); }
bool isHalf() const { return node()->isHalf(); }
bool isMinusHalf() const { return node()->isMinusHalf(); }
bool isTen() const { return node()->isTen(); }

View File

@@ -415,10 +415,13 @@ public:
NegativePrefixes),
};
// TODO: find a better way to find defines these pointers
static_assert(sizeof(TimeRepresentatives)/sizeof(Representative) == 7, "The Unit::SecondRepresentative, Unit::HourRepresentative might require to be fixed if the TimeRepresentatives table was changed.");
static const Representative constexpr * SecondRepresentative = &TimeRepresentatives[0];
static const Representative constexpr * HourRepresentative = &TimeRepresentatives[2];
static const Representative constexpr * MeterRepresentative = &DistanceRepresentatives[0];
static const Representative constexpr * KilogramRepresentative = &MassRepresentatives[0];
static const Representative constexpr * LiterRepresentative = &VolumeRepresentatives[0];
static const Representative constexpr * WattRepresentative = &PowerRepresentatives[0];
static constexpr const Dimension DimensionTable[] = {
/* The current table is sorted from most to least simple units.
* The order determines the behavior of simplification.
@@ -724,8 +727,11 @@ public:
),
};
// TODO: find a better way to find defines these pointers
static_assert(sizeof(DimensionTable)/sizeof(Dimension) == 23, "The Unit::TimeDimension, Unit::DistanceDimension and so on might require to be fixed if the Dimension table was changed.");
static const Dimension constexpr * TimeDimension = &DimensionTable[0] ;
static const Dimension constexpr * DistanceDimension = &DimensionTable[1];
static const Dimension constexpr * MassDimension = &DimensionTable[2];
static const Dimension constexpr * PowerDimension = &DimensionTable[11];
static const Dimension constexpr * VolumeDimension = &DimensionTable[sizeof(DimensionTable)/sizeof(Dimension)-1];
static constexpr const Unit::Dimension * DimensionTableUpperBound =
@@ -738,11 +744,14 @@ public:
static Unit Kilometer() { return Builder(DistanceDimension, MeterRepresentative, &KiloPrefix); }
static Unit Hour() { return Builder(TimeDimension, HourRepresentative, &EmptyPrefix); }
static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); }
static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); }
static bool IsISSpeed(Expression & e);
static bool IsISVolume(Expression & e);
static bool IsISEnergy(Expression & e);
bool isMeter() const;
bool isSecond() const;
bool isKilogram() const;
// Simplification
Expression shallowReduce(ExpressionNode::ReductionContext reductionContext);
@@ -750,6 +759,7 @@ public:
static constexpr double MeterPerSecondToKilometerPerHourFactor = 60.0*60.0/1000.0;
static constexpr double CubicMeterToLiterFactor = 10.0*10.0*10.0;
static constexpr double JouleToWatthourFactor = 1.0/3600.0;
private:
UnitNode * node() const { return static_cast<UnitNode *>(Expression::node()); }
Expression removeUnit(Expression * unit);

View File

@@ -480,6 +480,15 @@ Expression Multiplication::shallowBeautify(ExpressionNode::ReductionContext redu
units = Unit::Liter();
static_cast<Unit&>(units).chooseBestMultipleForValue(value, 1, reductionContext);
}
if (Unit::IsISEnergy(units)) {
value *= Unit::JouleToWatthourFactor;
Unit w = Unit::Watt();
units = Multiplication::Builder(
w,
Unit::Hour()
);
w.chooseBestMultipleForValue(value, 1, reductionContext);
}
// TODO: what to do if no classic conversion?
}
if (result.isUninitialized()) {

View File

@@ -361,6 +361,11 @@ bool Unit::isMeter() const {
return node()->dimension() == DistanceDimension && node()->representative() == MeterRepresentative && node()->prefix() == &EmptyPrefix;
}
bool Unit::isKilogram() const {
return node()->dimension() == MassDimension && node()->representative() == KilogramRepresentative && node()->prefix() == &KiloPrefix;
}
bool Unit::IsISSpeed(Expression & e) {
// Form m*s^-1
return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 2 &&
@@ -377,6 +382,18 @@ bool Unit::IsISVolume(Expression & e) {
e.childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).convert<const Rational>().isThree();
}
bool Unit::IsISEnergy(Expression & e) {
// Form _kg*_m^2*_s^-2
return e.type() == ExpressionNode::Type::Multiplication && e.numberOfChildren() == 3 &&
e.childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(0).convert<Unit>().isKilogram() &&
e.childAtIndex(1).type() == ExpressionNode::Type::Power &&
e.childAtIndex(1).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert<Unit>().isMeter();
e.childAtIndex(1).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert<const Rational>().isTwo() &&
e.childAtIndex(2).type() == ExpressionNode::Type::Power &&
e.childAtIndex(2).childAtIndex(0).type() == ExpressionNode::Type::Unit && e.childAtIndex(1).childAtIndex(0).convert<Unit>().isSecond();
e.childAtIndex(2).childAtIndex(1).type() == ExpressionNode::Type::Rational && e.childAtIndex(1).childAtIndex(1).convert<const Rational>().isMinusTwo();
}
template Evaluation<float> UnitNode::templatedApproximate<float>(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;
template Evaluation<double> UnitNode::templatedApproximate<double>(Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) const;

View File

@@ -1287,6 +1287,7 @@ QUIZ_CASE(poincare_simplification_unit_conversion) {
assert_parsed_expression_simplify_to("10_m/_h", "0.01×_km×_h^\x12-1\x13", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion);
assert_parsed_expression_simplify_to("0.2_m^3", "200×_L", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion);
assert_parsed_expression_simplify_to("0.000012_m^3", "1.2×_cL", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion);
assert_parsed_expression_simplify_to("3600_J", "1×_W×_h", User, Degree, Cartesian, ReplaceAllDefinedSymbolsWithDefinition, ClassicUnitConversion);
}
QUIZ_CASE(poincare_simplification_user_function) {