mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-19 00:37:25 +01:00
[poincare/unit] Generalized BuildTimeSplit method
BuildTimesplit (used to create expressions of the form h+min+s) is now based on the more general BuildSplit. Change-Id: I3e55359cc6b9735269140942b29bd1d364fc35e7
This commit is contained in:
committed by
Émilie Feral
parent
5a31a6c1e2
commit
4d9f3aae97
@@ -840,6 +840,7 @@ public:
|
||||
static Unit Liter() { return Builder(VolumeDimension, LiterRepresentative, &EmptyPrefix); }
|
||||
static Unit ElectronVolt() { return Builder(EnergyDimension, ElectronVoltRepresentative, &EmptyPrefix); }
|
||||
static Unit Watt() { return Builder(PowerDimension, WattRepresentative, &EmptyPrefix); }
|
||||
static Expression BuildSplit(double baseValue, const Unit * units, const double * conversionFactors, int numberOfUnits, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
|
||||
static Expression BuildTimeSplit(double seconds, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit);
|
||||
|
||||
static bool IsSI(Expression & e);
|
||||
|
||||
@@ -514,43 +514,49 @@ bool Unit::IsSITime(Expression & e) {
|
||||
return e.type() == ExpressionNode::Type::Unit && static_cast<Unit &>(e).isSecond();
|
||||
}
|
||||
|
||||
Expression Unit::BuildTimeSplit(double seconds, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) {
|
||||
assert(!std::isnan(seconds));
|
||||
if (std::isinf(seconds) || std::fabs(seconds) < Expression::Epsilon<double>()) {
|
||||
return Multiplication::Builder(Number::FloatNumber(seconds), Unit::Second());
|
||||
Expression Unit::BuildSplit(double baseValue, Unit const * units, double const * conversionFactors, const int numberOfUnits, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) {
|
||||
assert(!std::isnan(baseValue));
|
||||
if (std::isinf(baseValue) || std::fabs(baseValue) < Expression::Epsilon<double>()) {
|
||||
return Multiplication::Builder(Number::FloatNumber(baseValue), units[numberOfUnits-1]);
|
||||
}
|
||||
/* Round the number of seconds to 13 significant digits
|
||||
* (= k_numberOfStoredSignificantDigits - 1).
|
||||
* Indeed, the user input has been converted to the most adequate unit
|
||||
* which might have led to approximating the value to 14 significants
|
||||
* digits. The number of seconds was then computed from this approximation.
|
||||
* We thus round it to avoid displaying small numbers of seconds that are
|
||||
* artifacts of the previous approximations. */
|
||||
double err = std::pow(10.0, Poincare::PrintFloat::k_numberOfStoredSignificantDigits - 1 - std::ceil(log10(std::fabs(seconds))));
|
||||
double remain = std::round(seconds*err)/err;
|
||||
|
||||
constexpr static int numberOfTimeUnits = 6;
|
||||
constexpr static double timeFactors[numberOfTimeUnits] = {MonthPerYear*DaysPerMonth*HoursPerDay*MinutesPerHour*SecondsPerMinute, DaysPerMonth*HoursPerDay*MinutesPerHour*SecondsPerMinute, HoursPerDay*MinutesPerHour*SecondsPerMinute, MinutesPerHour*SecondsPerMinute, SecondsPerMinute, 1.0 };
|
||||
Unit units[numberOfTimeUnits] = {Unit::Year(), Unit::Month(), Unit::Day(), Unit::Hour(), Unit::Minute(), Unit::Second() };
|
||||
double valuesPerUnit[numberOfTimeUnits];
|
||||
/* Round the base value to 13 significant digits
|
||||
* (= k_numberOfStoredSignificantDigits - 1).
|
||||
* Indeed, the user input has been converted to the most adequate unit
|
||||
* which might have led to approximating the value to 14 significants
|
||||
* digits. The value was then computed from this approximation.
|
||||
* We thus round it to avoid displaying small numbers that are
|
||||
* artifacts of the previous approximations. */
|
||||
double err = std::pow(10.0, Poincare::PrintFloat::k_numberOfStoredSignificantDigits - 1 - std::ceil(log10(std::fabs(baseValue))));
|
||||
double remain = std::round(baseValue*err)/err;
|
||||
|
||||
double valuesPerUnit[numberOfUnits];
|
||||
Addition a = Addition::Builder();
|
||||
for (size_t i = 0; i < numberOfTimeUnits; i++) {
|
||||
valuesPerUnit[i] = remain/timeFactors[i];
|
||||
for (int i = 0; i < numberOfUnits; i++) {
|
||||
valuesPerUnit[i] = remain/conversionFactors[i];
|
||||
// Keep only the floor of the values except for the last unit (seconds)
|
||||
if (i < numberOfTimeUnits - 1) {
|
||||
if (i < numberOfUnits - 1) {
|
||||
valuesPerUnit[i] = valuesPerUnit[i] >= 0.0 ? std::floor(valuesPerUnit[i]) : std::ceil(valuesPerUnit[i]);
|
||||
}
|
||||
remain -= valuesPerUnit[i]*timeFactors[i];
|
||||
remain -= valuesPerUnit[i] * conversionFactors[i];
|
||||
if (std::fabs(valuesPerUnit[i]) > Expression::Epsilon<double>()) {
|
||||
Multiplication m = Multiplication::Builder(Float<double>::Builder(valuesPerUnit[i]), units[i]);
|
||||
a.addChildAtIndexInPlace(m, a.numberOfChildren(), a.numberOfChildren());
|
||||
}
|
||||
}
|
||||
|
||||
ExpressionNode::ReductionContext reductionContext(context, complexFormat, angleUnit, ExpressionNode::ReductionTarget::User, ExpressionNode::SymbolicComputation::ReplaceAllDefinedSymbolsWithDefinition, ExpressionNode::UnitConversion::None);
|
||||
// Beautify the addition into an subtraction if necessary
|
||||
return a.squashUnaryHierarchyInPlace().shallowBeautify(reductionContext);
|
||||
}
|
||||
|
||||
Expression Unit::BuildTimeSplit(double seconds, Context * context, Preferences::ComplexFormat complexFormat, Preferences::AngleUnit angleUnit) {
|
||||
constexpr static int numberOfTimeUnits = 6;
|
||||
Unit units[numberOfTimeUnits] = {Unit::Year(), Unit::Month(), Unit::Day(), Unit::Hour(), Unit::Minute(), Unit::Second()};
|
||||
constexpr static double timeFactors[numberOfTimeUnits] = {MonthPerYear*DaysPerMonth*HoursPerDay*MinutesPerHour*SecondsPerMinute, DaysPerMonth*HoursPerDay*MinutesPerHour*SecondsPerMinute, HoursPerDay*MinutesPerHour*SecondsPerMinute, MinutesPerHour*SecondsPerMinute, SecondsPerMinute, 1.0};
|
||||
return BuildSplit(seconds, units, timeFactors, numberOfTimeUnits, context, complexFormat, angleUnit);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user