diff --git a/apps/calculation/calculation.cpp b/apps/calculation/calculation.cpp index 682a27d66..3c0372c8c 100644 --- a/apps/calculation/calculation.cpp +++ b/apps/calculation/calculation.cpp @@ -257,10 +257,10 @@ Calculation::AdditionalInformationType Calculation::additionalInformationType(Co /* FIXME : When this method is accessed via leaving the additional outputs, * ie via a press on BACK, the reduction is interrupted, and removeUnit * goes badly.*/ - PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined); + PoincareHelpers::Reduce(&o, App::app()->localContext(), ExpressionNode::ReductionTarget::User, ExpressionNode::SymbolicComputation::ReplaceAllSymbolsWithDefinitionsOrUndefined, ExpressionNode::UnitConversion::None); o = o.removeUnit(&unit); double value = PoincareHelpers::ApproximateToScalar(o, App::app()->localContext()); - return (Unit::ShouldDisplayAdditionalOutputs(value, unit)) ? AdditionalInformationType::Unit : AdditionalInformationType::None; + return (Unit::ShouldDisplayAdditionalOutputs(value, unit, GlobalPreferences::sharedGlobalPreferences()->unitFormat())) ? AdditionalInformationType::Unit : AdditionalInformationType::None; } if (o.isBasedIntegerCappedBy(k_maximalIntegerWithAdditionalInformation)) { return AdditionalInformationType::Integer; diff --git a/poincare/include/poincare/unit.h b/poincare/include/poincare/unit.h index bef0ddabb..456ff4700 100644 --- a/poincare/include/poincare/unit.h +++ b/poincare/include/poincare/unit.h @@ -110,7 +110,7 @@ public: virtual const Prefix * basePrefix() const { return Prefix::EmptyPrefix(); } virtual bool isBaseUnit() const { return false; } virtual const Representative * standardRepresentative(double value, double exponent, ExpressionNode::ReductionContext reductionContext, const Prefix * * prefix) const { return DefaultFindBestRepresentative(value, exponent, representativesOfSameDimension(), numberOfRepresentatives(), prefix); } - virtual bool hasAdditionalExpressions(double value) const { return true; } + virtual bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const { return true; } virtual int setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const { return 0; } const char * rootSymbol() const { return m_rootSymbol; } double ratio() const { return m_ratio; } @@ -142,7 +142,7 @@ public: int numberOfRepresentatives() const override { return 7; } const Representative * representativesOfSameDimension() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } - bool hasAdditionalExpressions(double value) const override { return m_ratio * value >= representativesOfSameDimension()[1].ratio(); } + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return m_ratio * value >= representativesOfSameDimension()[1].ratio(); } int setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const override; private: using Representative::Representative; @@ -157,6 +157,7 @@ public: const Representative * representativesOfSameDimension() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } const Representative * standardRepresentative(double value, double exponent, ExpressionNode::ReductionContext reductionContext, const Prefix * * prefix) const override; + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return unitFormat == Preferences::UnitFormat::Imperial; } int setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const override; private: using Representative::Representative; @@ -172,6 +173,7 @@ public: const Prefix * basePrefix() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } const Representative * standardRepresentative(double value, double exponent, ExpressionNode::ReductionContext reductionContext, const Prefix * * prefix) const override; + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return unitFormat == Preferences::UnitFormat::Imperial; } int setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const override; private: using Representative::Representative; @@ -185,7 +187,7 @@ public: int numberOfRepresentatives() const override { return 1; } const Representative * representativesOfSameDimension() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } - bool hasAdditionalExpressions(double value) const override { return false; } + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return false; } private: using Representative::Representative; }; @@ -198,7 +200,7 @@ public: int numberOfRepresentatives() const override { return 1; } const Representative * representativesOfSameDimension() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } - bool hasAdditionalExpressions(double value) const override { return false; } + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return false; } private: using Representative::Representative; }; @@ -211,7 +213,7 @@ public: int numberOfRepresentatives() const override { return 1; } const Representative * representativesOfSameDimension() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } - bool hasAdditionalExpressions(double value) const override { return false; } + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return false; } private: using Representative::Representative; }; @@ -224,7 +226,7 @@ public: int numberOfRepresentatives() const override { return 1; } const Representative * representativesOfSameDimension() const override; bool isBaseUnit() const override { return this == representativesOfSameDimension(); } - bool hasAdditionalExpressions(double value) const override { return false; } + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return false; } private: using Representative::Representative; }; @@ -236,7 +238,7 @@ public: const Vector dimensionVector() const override { return Vector{.time = -1, .distance = 0, .mass = 0, .current = 0, .temperature = 0, .amountOfSubstance = 0, .luminuousIntensity = 0}; } int numberOfRepresentatives() const override { return 1; } const Representative * representativesOfSameDimension() const override; - bool hasAdditionalExpressions(double value) const override { return false; } + bool hasAdditionalExpressions(double value, Preferences::UnitFormat unitFormat) const override { return false; } private: using Representative::Representative; }; @@ -652,7 +654,7 @@ public: static Unit Builder(const Representative * representative, const Prefix * prefix); static bool CanParse(const char * symbol, size_t length, const Representative * * representative, const Prefix * * prefix); static void ChooseBestRepresentativeAndPrefixForValue(Expression units, double * value, ExpressionNode::ReductionContext reductionContext); - static bool ShouldDisplayAdditionalOutputs(double value, Expression unit); + static bool ShouldDisplayAdditionalOutputs(double value, Expression unit, Preferences::UnitFormat unitFormat); static int SetAdditionalExpressions(Expression units, double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext); static Expression BuildSplit(double value, const Unit * units, int length, ExpressionNode::ReductionContext reductionContext); diff --git a/poincare/src/unit.cpp b/poincare/src/unit.cpp index ff341199a..8ea2607c3 100644 --- a/poincare/src/unit.cpp +++ b/poincare/src/unit.cpp @@ -437,6 +437,9 @@ const UnitNode::Representative * UnitNode::DistanceRepresentative::standardRepre int UnitNode::DistanceRepresentative::setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const { assert(availableLength >= 1); + if (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) { + return 0; + } const Unit splitUnits[] = { Unit::Builder(representativesOfSameDimension() + Unit::k_inchRepresentativeIndex, Prefix::EmptyPrefix()), Unit::Builder(representativesOfSameDimension() + Unit::k_footRepresentativeIndex, Prefix::EmptyPrefix()), @@ -461,6 +464,9 @@ const UnitNode::Representative * UnitNode::MassRepresentative::standardRepresent int UnitNode::MassRepresentative::setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const { assert(availableLength >= 1); + if (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) { + return 0; + } const Unit splitUnits[] = { Unit::Builder(representativesOfSameDimension() + Unit::k_ounceRepresentativeIndex, Prefix::EmptyPrefix()), Unit::Builder(representativesOfSameDimension() + Unit::k_poundRepresentativeIndex, Prefix::EmptyPrefix()), @@ -501,13 +507,21 @@ const UnitNode::Representative * UnitNode::SurfaceRepresentative::standardRepres int UnitNode::SurfaceRepresentative::setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const { assert(availableLength >= 2); - int k = (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) ? 0 : 1; - Expression * destMetric = dest + k; - Expression * destImperial = dest + (1 - k); + Expression * destMetric; + Expression * destImperial = nullptr; + if (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) { + destMetric = dest; + } else { + destImperial = dest; + destMetric = dest + 1; + } // 1. Convert to hectares const Representative * hectare = representativesOfSameDimension() + Unit::k_hectareRepresentativeIndex; *destMetric = Multiplication::Builder(Float::Builder(value / hectare->ratio()), Unit::Builder(hectare, Prefix::EmptyPrefix())); // 2. Convert to acres + if (!destImperial) { + return 1; + } const Representative * acre = representativesOfSameDimension() + Unit::k_acreRepresentativeIndex; *destImperial = Multiplication::Builder(Float::Builder(value / acre->ratio()), Unit::Builder(acre, Prefix::EmptyPrefix())); return 2; @@ -523,9 +537,14 @@ const UnitNode::Representative * UnitNode::VolumeRepresentative::standardReprese int UnitNode::VolumeRepresentative::setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const { assert(availableLength >= 2); - int k = (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) ? 0 : 1; - Expression * destMetric = dest + k; - Expression * destImperial = dest + (1 - k); + Expression * destMetric; + Expression * destImperial = nullptr; + if (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) { + destMetric = dest; + } else { + destImperial = dest; + destMetric = dest + 1; + } // 1. Convert to liters const Representative * liter = representativesOfSameDimension() + Unit::k_literRepresentativeIndex; double adjustedValue = value / liter->ratio(); @@ -534,6 +553,9 @@ int UnitNode::VolumeRepresentative::setAdditionalExpressions(double value, Expre Float::Builder(adjustedValue * pow(10., -literPrefix->exponent())), Unit::Builder(liter, literPrefix)); // 2. Convert to imperial volumes + if (!destImperial) { + return 1; + } const Unit splitUnits[] = { Unit::Builder(representativesOfSameDimension() + Unit::k_cupRepresentativeIndex, Prefix::EmptyPrefix()), Unit::Builder(representativesOfSameDimension() + Unit::k_pintRepresentativeIndex, Prefix::EmptyPrefix()), @@ -546,9 +568,14 @@ int UnitNode::VolumeRepresentative::setAdditionalExpressions(double value, Expre int UnitNode::SpeedRepresentative::setAdditionalExpressions(double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) const { assert(availableLength >= 2); - int k = (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) ? 0 : 1; - Expression * destMetric = dest + k; - Expression * destImperial = dest + (1 - k); + Expression * destMetric; + Expression * destImperial = nullptr; + if (reductionContext.unitFormat() == Preferences::UnitFormat::Metric) { + destMetric = dest; + } else { + destImperial = dest; + destMetric = dest + 1; + } // 1. Convert to km/h const Representative * meter = DistanceRepresentative::Default().representativesOfSameDimension() + Unit::k_meterRepresentativeIndex; const Representative * hour = TimeRepresentative::Default().representativesOfSameDimension() + Unit::k_hourRepresentativeIndex; @@ -558,6 +585,9 @@ int UnitNode::SpeedRepresentative::setAdditionalExpressions(double value, Expres Unit::Builder(meter, Prefix::Prefixes() + Unit::k_kiloPrefixIndex), Power::Builder(Unit::Builder(hour, Prefix::EmptyPrefix()), Rational::Builder(-1)))); // 2. Convert to mph + if (!destImperial) { + return 1; + } const Representative * mile = DistanceRepresentative::Default().representativesOfSameDimension() + Unit::k_mileRepresentativeIndex; *destImperial = Multiplication::Builder( Float::Builder(value / mile->ratio() * hour->ratio()), @@ -676,10 +706,12 @@ void Unit::ChooseBestRepresentativeAndPrefixForValue(Expression units, double * } } -bool Unit::ShouldDisplayAdditionalOutputs(double value, Expression unit) { +bool Unit::ShouldDisplayAdditionalOutputs(double value, Expression unit, Preferences::UnitFormat unitFormat) { UnitNode::Vector vector = UnitNode::Vector::FromBaseUnits(unit); const Representative * representative = Representative::RepresentativeForDimension(vector); - return representative != nullptr && representative->hasAdditionalExpressions(value); + return representative != nullptr + && ((unit.type() == ExpressionNode::Type::Unit && !unit.convert().isBaseUnit()) + || representative->hasAdditionalExpressions(value, unitFormat)); } int Unit::SetAdditionalExpressions(Expression units, double value, Expression * dest, int availableLength, ExpressionNode::ReductionContext reductionContext) { diff --git a/poincare/test/expression_properties.cpp b/poincare/test/expression_properties.cpp index 26d07d749..79f10e8e4 100644 --- a/poincare/test/expression_properties.cpp +++ b/poincare/test/expression_properties.cpp @@ -394,18 +394,18 @@ QUIZ_CASE(poincare_properties_remove_unit) { assert_reduced_expression_unit_is("_L^2×3×_s", "_m^6×_s"); } -void assert_additional_results_compute_to(const char * expression, const char * * results, int length) { +void assert_additional_results_compute_to(const char * expression, const char * * results, int length, Preferences::UnitFormat unitFormat = Metric) { Shared::GlobalContext globalContext; constexpr int maxNumberOfResults = 5; assert(length <= maxNumberOfResults); Expression additional[maxNumberOfResults]; - ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, Metric, User, ReplaceAllSymbolsWithUndefined, DefaultUnitConversion); + ExpressionNode::ReductionContext reductionContext = ExpressionNode::ReductionContext(&globalContext, Cartesian, Degree, unitFormat, User, ReplaceAllSymbolsWithUndefined, DefaultUnitConversion); Expression e = parse_expression(expression, &globalContext, false).reduce(reductionContext); Expression units; e = e.removeUnit(&units); double value = e.approximateToScalar(&globalContext, Cartesian, Degree); - if (!Unit::ShouldDisplayAdditionalOutputs(value, units)) { + if (!Unit::ShouldDisplayAdditionalOutputs(value, units, unitFormat)) { quiz_assert(length == 0); return; } @@ -429,27 +429,33 @@ QUIZ_CASE(poincare_expression_additional_results) { // Distance const char * array4[1] = {"19×_mi+853×_yd+1×_ft+7×_in"}; - assert_additional_results_compute_to("1234567×_in", array4, 1); + assert_additional_results_compute_to("1234567×_in", array4, 1, Imperial); const char * array5[1] = {"1×_yd+7.700787×_in"}; - assert_additional_results_compute_to("1.11×_m", array5, 1); + assert_additional_results_compute_to("1.11×_m", array5, 1, Imperial); + assert_additional_results_compute_to("1.11×_m", nullptr, 0, Metric); // Masses const char * array6[1] = {"1×_shtn+240×_lb"}; - assert_additional_results_compute_to("1×_lgtn", array6, 1); + assert_additional_results_compute_to("1×_lgtn", array6, 1, Imperial); const char * array7[1] = {"2×_lb+3.273962×_oz"}; - assert_additional_results_compute_to("1×_kg", array7, 1); + assert_additional_results_compute_to("1×_kg", array7, 1, Imperial); + assert_additional_results_compute_to("1×_kg", nullptr, 0, Metric); // Energy const char * array8[2] = {"1×_kW×_h", "2.246943ᴇ13×_TeV"}; assert_additional_results_compute_to("3.6×_MN_m", array8, 2); // Volume - const char * array9[2] = {"1000×_L", "264×_gal+1×_pt+0.7528377×_cup"}; - assert_additional_results_compute_to("1×_m^3", array9, 2); - const char * array10[2] = {"182.5426×_L", "48×_gal+1×_pt+1.5625×_cup"}; - assert_additional_results_compute_to("12345×_tbsp", array10, 2); + const char * array9[2] = {"264×_gal+1×_pt+0.7528377×_cup", "1000×_L"}; + assert_additional_results_compute_to("1×_m^3", array9, 2, Imperial); + const char * array10[2] = {"48×_gal+1×_pt+1.5625×_cup", "182.5426×_L"}; + assert_additional_results_compute_to("12345×_tbsp", array10, 2, Imperial); + const char * array11[2] = {"182.5426×_L"}; + assert_additional_results_compute_to("12345×_tbsp", array11, 1, Metric); // Speed - const char * array11[2] = {"3.6×_km×_h^\x12-1\x13", "2.236936×_mi×_h^\x12-1\x13"}; - assert_additional_results_compute_to("1×_m/_s", array11, 2); + const char * array12[1] = {"3.6×_km×_h^\x12-1\x13"}; + assert_additional_results_compute_to("1×_m/_s", array12, 1, Metric); + const char * array13[2] = {"2.236936×_mi×_h^\x12-1\x13", "3.6×_km×_h^\x12-1\x13"}; + assert_additional_results_compute_to("1×_m/_s", array13, 2, Imperial); }