diff options
author | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2024-08-15 16:51:45 -0500 |
---|---|---|
committer | Adrien Hopkins <adrien.p.hopkins@gmail.com> | 2024-08-22 11:45:36 -0500 |
commit | e74668b91c247e7395362e8e411c3e1a13ec10d1 (patch) | |
tree | c5d70af1cf84ee6b1c8012745ce1288d8050a1b6 /src/main/java/sevenUnits/unit/LinearUnitValue.java | |
parent | fbb2f4a997e7e7043a2bdf15303b88907f6bcbc6 (diff) |
Add ability to convert expression to sum of units
Diffstat (limited to 'src/main/java/sevenUnits/unit/LinearUnitValue.java')
-rw-r--r-- | src/main/java/sevenUnits/unit/LinearUnitValue.java | 103 |
1 files changed, 71 insertions, 32 deletions
diff --git a/src/main/java/sevenUnits/unit/LinearUnitValue.java b/src/main/java/sevenUnits/unit/LinearUnitValue.java index 3a9428b..fad3eb0 100644 --- a/src/main/java/sevenUnits/unit/LinearUnitValue.java +++ b/src/main/java/sevenUnits/unit/LinearUnitValue.java @@ -17,10 +17,13 @@ package sevenUnits.unit; import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.Optional; import sevenUnits.utils.DecimalComparison; +import sevenUnits.utils.ObjectProduct; import sevenUnits.utils.UncertainDouble; /** @@ -34,7 +37,7 @@ import sevenUnits.utils.UncertainDouble; */ public final class LinearUnitValue { public static final LinearUnitValue ONE = getExact(Metric.ONE, 1); - + /** * Gets an exact {@code LinearUnitValue} * @@ -49,7 +52,7 @@ public final class LinearUnitValue { Objects.requireNonNull(unit, "unit must not be null"), UncertainDouble.of(value, 0)); } - + /** * Gets an uncertain {@code LinearUnitValue} * @@ -65,11 +68,11 @@ public final class LinearUnitValue { Objects.requireNonNull(unit, "unit must not be null"), Objects.requireNonNull(value, "value may not be null")); } - + private final LinearUnit unit; - + private final UncertainDouble value; - + /** * @param unit unit to express as * @param value value to express @@ -79,7 +82,7 @@ public final class LinearUnitValue { this.unit = unit; this.value = value; } - + /** * @return this value as a {@code UnitValue}. All uncertainty information is * removed from the returned value. @@ -88,7 +91,7 @@ public final class LinearUnitValue { public final UnitValue asUnitValue() { return UnitValue.of(this.unit, this.value.value()); } - + /** * @param other a {@code LinearUnit} * @return true iff this value can be represented with {@code other}. @@ -97,7 +100,7 @@ public final class LinearUnitValue { public final boolean canConvertTo(final LinearUnit other) { return this.unit.canConvertTo(other); } - + /** * Returns a LinearUnitValue that represents the same value expressed in a * different unit @@ -109,7 +112,43 @@ public final class LinearUnitValue { public final LinearUnitValue convertTo(final LinearUnit other) { return LinearUnitValue.of(other, this.unit.convertTo(other, this.value)); } - + + /** + * Convert a LinearUnitValue to a sum of multiple units, where all but the + * last have exact integer values. + * + * @param others units to convert to + * @throws IllegalArgumentException if no units are provided or units + * provided have incompatible bases + * @since 2024-08-15 + */ + public final List<LinearUnitValue> convertToMultiple( + final List<LinearUnit> others) { + if (others.size() < 1) + throw new IllegalArgumentException("Must have at least one unit"); + final ObjectProduct<BaseUnit> unitBase = others.get(0).getBase(); + for (final LinearUnit unit : others) { + if (!unitBase.equals(unit.getBase())) + throw new IllegalArgumentException( + "All units must have the same base."); + } + + LinearUnitValue remaining = this; + final List<LinearUnitValue> values = new ArrayList<>(others.size()); + for (final LinearUnit unit : others.subList(0, others.size() - 1)) { + final LinearUnitValue remainingInUnit = remaining.convertTo(unit); + final LinearUnitValue value = getExact(unit, + Math.floor(remainingInUnit.getValueExact())); + values.add(value); + remaining = remaining.minus(value); + } + + final LinearUnitValue lastValue = remaining + .convertTo(others.get(others.size() - 1)); + values.add(lastValue); + return values; + } + /** * Divides this value by a scalar * @@ -120,7 +159,7 @@ public final class LinearUnitValue { public LinearUnitValue dividedBy(final double divisor) { return LinearUnitValue.of(this.unit, this.value.dividedByExact(divisor)); } - + /** * Divides this value by another value * @@ -132,7 +171,7 @@ public final class LinearUnitValue { return LinearUnitValue.of(this.unit.dividedBy(divisor.unit), this.value.dividedBy(divisor.value)); } - + /** * Returns true if this and obj represent the same value, regardless of * whether or not they are expressed in the same unit. So (1000 m).equals(1 @@ -150,7 +189,7 @@ public final class LinearUnitValue { && this.unit.convertToBase(this.value) .equals(other.unit.convertToBase(other.value)); } - + /** * Returns true if this and obj represent the same value, regardless of * whether or not they are expressed in the same unit. So (1000 m).equals(1 @@ -171,7 +210,7 @@ public final class LinearUnitValue { && DecimalComparison.equals(this.unit.convertToBase(this.value), other.unit.convertToBase(other.value)); } - + /** * @param other another {@code LinearUnitValue} * @return true iff this and other are within each other's uncertainty range @@ -185,10 +224,10 @@ public final class LinearUnitValue { final LinearUnit base = LinearUnit.valueOf(this.unit.getBase(), 1); final LinearUnitValue thisBase = this.convertTo(base); final LinearUnitValue otherBase = other.convertTo(base); - + return thisBase.value.equivalent(otherBase.value); } - + /** * @return the unit * @since 2020-09-29 @@ -196,7 +235,7 @@ public final class LinearUnitValue { public final LinearUnit getUnit() { return this.unit; } - + /** * @return the value * @since 2020-09-29 @@ -204,7 +243,7 @@ public final class LinearUnitValue { public final UncertainDouble getValue() { return this.value; } - + /** * @return the exact value * @since 2020-09-07 @@ -212,13 +251,13 @@ public final class LinearUnitValue { public final double getValueExact() { return this.value.value(); } - + @Override public int hashCode() { return Objects.hash(this.unit.getBase(), this.unit.convertToBase(this.getValue())); } - + /** * Returns the difference of this value and another, expressed in this * value's unit @@ -231,17 +270,17 @@ public final class LinearUnitValue { */ public LinearUnitValue minus(final LinearUnitValue subtrahend) { Objects.requireNonNull(subtrahend, "subtrahend may not be null"); - + if (!this.canConvertTo(subtrahend.unit)) throw new IllegalArgumentException(String.format( "Incompatible units for subtraction \"%s\" and \"%s\".", this.unit, subtrahend.unit)); - + final LinearUnitValue otherConverted = subtrahend.convertTo(this.unit); return LinearUnitValue.of(this.unit, this.value.minus(otherConverted.value)); } - + /** * Returns the sum of this value and another, expressed in this value's unit * @@ -253,17 +292,17 @@ public final class LinearUnitValue { */ public LinearUnitValue plus(final LinearUnitValue addend) { Objects.requireNonNull(addend, "addend may not be null"); - + if (!this.canConvertTo(addend.unit)) throw new IllegalArgumentException(String.format( "Incompatible units for addition \"%s\" and \"%s\".", this.unit, addend.unit)); - + final LinearUnitValue otherConverted = addend.convertTo(this.unit); return LinearUnitValue.of(this.unit, this.value.plus(otherConverted.value)); } - + /** * Multiplies this value by a scalar * @@ -274,7 +313,7 @@ public final class LinearUnitValue { public LinearUnitValue times(final double multiplier) { return LinearUnitValue.of(this.unit, this.value.timesExact(multiplier)); } - + /** * Multiplies this value by another value * @@ -286,7 +325,7 @@ public final class LinearUnitValue { return LinearUnitValue.of(this.unit.times(multiplier.unit), this.value.times(multiplier.value)); } - + /** * Raises a value to an exponent * @@ -298,12 +337,12 @@ public final class LinearUnitValue { return LinearUnitValue.of(this.unit.toExponent(exponent), this.value.toExponentExact(exponent)); } - + @Override public String toString() { return this.toString(!this.value.isExact(), RoundingMode.HALF_EVEN); } - + /** * Returns a string representing the object. <br> * If the attached unit has a name or symbol, the string looks like "12 km". @@ -321,9 +360,9 @@ public final class LinearUnitValue { final Optional<String> primaryName = this.unit.getPrimaryName(); final Optional<String> symbol = this.unit.getSymbol(); final String chosenName = symbol.orElse(primaryName.orElse(null)); - + final UncertainDouble baseValue = this.unit.convertToBase(this.value); - + // get rounded strings // if showUncertainty is true, add brackets around the string final String valueString = (showUncertainty ? "(" : "") @@ -332,7 +371,7 @@ public final class LinearUnitValue { final String baseValueString = (showUncertainty ? "(" : "") + baseValue.toString(showUncertainty, roundingMode) + (showUncertainty ? ")" : ""); - + // create string if (chosenName == null) return String.format("%s unnamed unit (= %s %s)", valueString, |