summaryrefslogtreecommitdiff
path: root/src/org/unitConverter/unit
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/unitConverter/unit')
-rw-r--r--src/org/unitConverter/unit/LinearUnit.java302
-rw-r--r--src/org/unitConverter/unit/LinearUnitValue.java252
-rw-r--r--src/org/unitConverter/unit/UnitDatabase.java6
-rw-r--r--src/org/unitConverter/unit/UnitTest.java7
4 files changed, 233 insertions, 334 deletions
diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java
index 762572a..2d63ca7 100644
--- a/src/org/unitConverter/unit/LinearUnit.java
+++ b/src/org/unitConverter/unit/LinearUnit.java
@@ -20,89 +20,83 @@ import java.util.Objects;
import org.unitConverter.math.DecimalComparison;
import org.unitConverter.math.ObjectProduct;
+import org.unitConverter.math.UncertainDouble;
/**
- * A unit that can be expressed as a product of its base and a number. For example, kilometres, inches and pounds.
+ * A unit that can be expressed as a product of its base and a number. For
+ * example, kilometres, inches and pounds.
*
* @author Adrien Hopkins
* @since 2019-10-16
*/
public final class LinearUnit extends Unit {
/**
- * Gets a {@code LinearUnit} from a unit and a value. For example, converts '59 °F' to a linear unit with the value
- * of '288.15 K'
+ * Gets a {@code LinearUnit} from a unit and a value. For example, converts
+ * '59 °F' to a linear unit with the value of '288.15 K'
*
- * @param unit
- * unit to convert
- * @param value
- * value to convert
+ * @param unit unit to convert
+ * @param value value to convert
* @return value expressed as a {@code LinearUnit}
* @since 2019-10-16
- * @throws NullPointerException
- * if unit is null
+ * @throws NullPointerException if unit is null
*/
public static LinearUnit fromUnitValue(final Unit unit, final double value) {
- return new LinearUnit(Objects.requireNonNull(unit, "unit must not be null.").getBase(),
+ return new LinearUnit(
+ Objects.requireNonNull(unit, "unit must not be null.").getBase(),
unit.convertToBase(value), NameSymbol.EMPTY);
}
-
+
/**
- * Gets a {@code LinearUnit} from a unit and a value. For example, converts '59 °F' to a linear unit with the value
- * of '288.15 K'
+ * Gets a {@code LinearUnit} from a unit and a value. For example, converts
+ * '59 °F' to a linear unit with the value of '288.15 K'
*
- * @param unit
- * unit to convert
- * @param value
- * value to convert
- * @param ns
- * name(s) and symbol of unit
+ * @param unit unit to convert
+ * @param value value to convert
+ * @param ns name(s) and symbol of unit
* @return value expressed as a {@code LinearUnit}
* @since 2019-10-21
- * @throws NullPointerException
- * if unit or ns is null
+ * @throws NullPointerException if unit or ns is null
*/
- public static LinearUnit fromUnitValue(final Unit unit, final double value, final NameSymbol ns) {
- return new LinearUnit(Objects.requireNonNull(unit, "unit must not be null.").getBase(),
+ public static LinearUnit fromUnitValue(final Unit unit, final double value,
+ final NameSymbol ns) {
+ return new LinearUnit(
+ Objects.requireNonNull(unit, "unit must not be null.").getBase(),
unit.convertToBase(value), ns);
}
-
+
/**
- * Gets a {@code LinearUnit} from a unit base and a conversion factor. In other words, gets the product of
- * {@code unitBase} and {@code conversionFactor}, expressed as a {@code LinearUnit}.
+ * Gets a {@code LinearUnit} from a unit base and a conversion factor. In
+ * other words, gets the product of {@code unitBase} and
+ * {@code conversionFactor}, expressed as a {@code LinearUnit}.
*
- * @param unitBase
- * unit base to multiply by
- * @param conversionFactor
- * number to multiply base by
+ * @param unitBase unit base to multiply by
+ * @param conversionFactor number to multiply base by
* @return product of base and conversion factor
* @since 2019-10-16
- * @throws NullPointerException
- * if unitBase is null
+ * @throws NullPointerException if unitBase is null
*/
- public static LinearUnit valueOf(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor) {
+ public static LinearUnit valueOf(final ObjectProduct<BaseUnit> unitBase,
+ final double conversionFactor) {
return new LinearUnit(unitBase, conversionFactor, NameSymbol.EMPTY);
}
-
+
/**
- * Gets a {@code LinearUnit} from a unit base and a conversion factor. In other words, gets the product of
- * {@code unitBase} and {@code conversionFactor}, expressed as a {@code LinearUnit}.
+ * Gets a {@code LinearUnit} from a unit base and a conversion factor. In
+ * other words, gets the product of {@code unitBase} and
+ * {@code conversionFactor}, expressed as a {@code LinearUnit}.
*
- * @param unitBase
- * unit base to multiply by
- * @param conversionFactor
- * number to multiply base by
- * @param ns
- * name(s) and symbol of unit
+ * @param unitBase unit base to multiply by
+ * @param conversionFactor number to multiply base by
+ * @param ns name(s) and symbol of unit
* @return product of base and conversion factor
* @since 2019-10-21
- * @throws NullPointerException
- * if unitBase is null
+ * @throws NullPointerException if unitBase is null
*/
- public static LinearUnit valueOf(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor,
- final NameSymbol ns) {
+ public static LinearUnit valueOf(final ObjectProduct<BaseUnit> unitBase,
+ final double conversionFactor, final NameSymbol ns) {
return new LinearUnit(unitBase, conversionFactor, ns);
}
-
+
/**
* The value of this unit as represented in its base form. Mathematically,
*
@@ -113,21 +107,20 @@ public final class LinearUnit extends Unit {
* @since 2019-10-16
*/
private final double conversionFactor;
-
+
/**
* Creates the {@code LinearUnit}.
*
- * @param unitBase
- * base of linear unit
- * @param conversionFactor
- * conversion factor between base and unit
+ * @param unitBase base of linear unit
+ * @param conversionFactor conversion factor between base and unit
* @since 2019-10-16
*/
- private LinearUnit(final ObjectProduct<BaseUnit> unitBase, final double conversionFactor, final NameSymbol ns) {
+ private LinearUnit(final ObjectProduct<BaseUnit> unitBase,
+ final double conversionFactor, final NameSymbol ns) {
super(unitBase, ns);
this.conversionFactor = conversionFactor;
}
-
+
/**
* {@inheritDoc}
*
@@ -137,7 +130,32 @@ public final class LinearUnit extends Unit {
protected double convertFromBase(final double value) {
return value / this.getConversionFactor();
}
-
+
+ /**
+ * Converts an {@code UncertainDouble} value expressed in this unit to an
+ * {@code UncertainValue} value expressed in {@code other}.
+ *
+ * @param other unit to convert to
+ * @param value value to convert
+ * @return converted value
+ * @since 2019-09-07
+ * @throws IllegalArgumentException if {@code other} is incompatible for
+ * conversion with this unit (as tested by
+ * {@link Unit#canConvertTo}).
+ * @throws NullPointerException if value or other is null
+ */
+ public UncertainDouble convertTo(LinearUnit other, UncertainDouble value) {
+ Objects.requireNonNull(other, "other must not be null.");
+ Objects.requireNonNull(value, "value may not be null.");
+ if (this.canConvertTo(other))
+ return value.timesExact(
+ this.getConversionFactor() / other.getConversionFactor());
+ else
+ throw new IllegalArgumentException(
+ String.format("Cannot convert from %s to %s.", this, other));
+
+ }
+
/**
* {@inheritDoc}
*
@@ -147,12 +165,20 @@ public final class LinearUnit extends Unit {
protected double convertToBase(final double value) {
return value * this.getConversionFactor();
}
-
+
+ /**
+ * Converts an {@code UncertainDouble} to the base unit.
+ *
+ * @since 2020-09-07
+ */
+ UncertainDouble convertToBase(final UncertainDouble value) {
+ return value.timesExact(this.getConversionFactor());
+ }
+
/**
* Divides this unit by a scalar.
*
- * @param divisor
- * scalar to divide by
+ * @param divisor scalar to divide by
* @return quotient
* @since 2018-12-23
* @since v0.1.0
@@ -160,26 +186,26 @@ public final class LinearUnit extends Unit {
public LinearUnit dividedBy(final double divisor) {
return valueOf(this.getBase(), this.getConversionFactor() / divisor);
}
-
+
/**
* Returns the quotient of this unit and another.
*
- * @param divisor
- * unit to divide by
+ * @param divisor unit to divide by
* @return quotient of two units
- * @throws NullPointerException
- * if {@code divisor} is null
+ * @throws NullPointerException if {@code divisor} is null
* @since 2018-12-22
* @since v0.1.0
*/
public LinearUnit dividedBy(final LinearUnit divisor) {
Objects.requireNonNull(divisor, "other must not be null");
-
+
// divide the units
- final ObjectProduct<BaseUnit> base = this.getBase().dividedBy(divisor.getBase());
- return valueOf(base, this.getConversionFactor() / divisor.getConversionFactor());
+ final ObjectProduct<BaseUnit> base = this.getBase()
+ .dividedBy(divisor.getBase());
+ return valueOf(base,
+ this.getConversionFactor() / divisor.getConversionFactor());
}
-
+
/**
* {@inheritDoc}
*
@@ -191,9 +217,10 @@ public final class LinearUnit extends Unit {
return false;
final LinearUnit other = (LinearUnit) obj;
return Objects.equals(this.getBase(), other.getBase())
- && DecimalComparison.equals(this.getConversionFactor(), other.getConversionFactor());
+ && DecimalComparison.equals(this.getConversionFactor(),
+ other.getConversionFactor());
}
-
+
/**
* @return conversion factor
* @since 2019-10-16
@@ -201,7 +228,7 @@ public final class LinearUnit extends Unit {
public double getConversionFactor() {
return this.conversionFactor;
}
-
+
/**
* {@inheritDoc}
*
@@ -209,18 +236,20 @@ public final class LinearUnit extends Unit {
*/
@Override
public int hashCode() {
- return 31 * this.getBase().hashCode() + DecimalComparison.hash(this.getConversionFactor());
+ return 31 * this.getBase().hashCode()
+ + DecimalComparison.hash(this.getConversionFactor());
}
-
+
/**
- * @return whether this unit is equivalent to a {@code BaseUnit} (i.e. there is a {@code BaseUnit b} where
+ * @return whether this unit is equivalent to a {@code BaseUnit} (i.e. there
+ * is a {@code BaseUnit b} where
* {@code b.asLinearUnit().equals(this)} returns {@code true}.)
* @since 2019-10-16
*/
public boolean isBase() {
return this.isCoherent() && this.getBase().isSingleObject();
}
-
+
/**
* @return whether this unit is coherent (i.e. has conversion factor 1)
* @since 2019-10-16
@@ -228,70 +257,73 @@ public final class LinearUnit extends Unit {
public boolean isCoherent() {
return this.getConversionFactor() == 1;
}
-
+
/**
* Returns the difference of this unit and another.
* <p>
- * Two units can be subtracted if they have the same base. Note that {@link #canConvertTo} can be used to determine
- * this. If {@code subtrahend} does not meet this condition, an {@code IllegalArgumentException} will be thrown.
+ * Two units can be subtracted if they have the same base. Note that
+ * {@link #canConvertTo} can be used to determine this. If {@code subtrahend}
+ * does not meet this condition, an {@code IllegalArgumentException} will be
+ * thrown.
* </p>
*
- * @param subtrahend
- * unit to subtract
+ * @param subtrahend unit to subtract
* @return difference of units
- * @throws IllegalArgumentException
- * if {@code subtrahend} is not compatible for subtraction as described above
- * @throws NullPointerException
- * if {@code subtrahend} is null
+ * @throws IllegalArgumentException if {@code subtrahend} is not compatible
+ * for subtraction as described above
+ * @throws NullPointerException if {@code subtrahend} is null
* @since 2019-03-17
* @since v0.2.0
*/
public LinearUnit minus(final LinearUnit subtrahend) {
Objects.requireNonNull(subtrahend, "addend must not be null.");
-
+
// reject subtrahends that cannot be added to this unit
if (!this.getBase().equals(subtrahend.getBase()))
- throw new IllegalArgumentException(
- String.format("Incompatible units for subtraction \"%s\" and \"%s\".", this, subtrahend));
-
+ throw new IllegalArgumentException(String.format(
+ "Incompatible units for subtraction \"%s\" and \"%s\".", this,
+ subtrahend));
+
// subtract the units
- return valueOf(this.getBase(), this.getConversionFactor() - subtrahend.getConversionFactor());
+ return valueOf(this.getBase(),
+ this.getConversionFactor() - subtrahend.getConversionFactor());
}
-
+
/**
* Returns the sum of this unit and another.
* <p>
- * Two units can be added if they have the same base. Note that {@link #canConvertTo} can be used to determine this.
- * If {@code addend} does not meet this condition, an {@code IllegalArgumentException} will be thrown.
+ * Two units can be added if they have the same base. Note that
+ * {@link #canConvertTo} can be used to determine this. If {@code addend}
+ * does not meet this condition, an {@code IllegalArgumentException} will be
+ * thrown.
* </p>
*
- * @param addend
- * unit to add
+ * @param addend unit to add
* @return sum of units
- * @throws IllegalArgumentException
- * if {@code addend} is not compatible for addition as described above
- * @throws NullPointerException
- * if {@code addend} is null
+ * @throws IllegalArgumentException if {@code addend} is not compatible for
+ * addition as described above
+ * @throws NullPointerException if {@code addend} is null
* @since 2019-03-17
* @since v0.2.0
*/
public LinearUnit plus(final LinearUnit addend) {
Objects.requireNonNull(addend, "addend must not be null.");
-
+
// reject addends that cannot be added to this unit
if (!this.getBase().equals(addend.getBase()))
- throw new IllegalArgumentException(
- String.format("Incompatible units for addition \"%s\" and \"%s\".", this, addend));
-
+ throw new IllegalArgumentException(String.format(
+ "Incompatible units for addition \"%s\" and \"%s\".", this,
+ addend));
+
// add the units
- return valueOf(this.getBase(), this.getConversionFactor() + addend.getConversionFactor());
+ return valueOf(this.getBase(),
+ this.getConversionFactor() + addend.getConversionFactor());
}
-
+
/**
* Multiplies this unit by a scalar.
*
- * @param multiplier
- * scalar to multiply by
+ * @param multiplier scalar to multiply by
* @return product
* @since 2018-12-23
* @since v0.1.0
@@ -299,39 +331,39 @@ public final class LinearUnit extends Unit {
public LinearUnit times(final double multiplier) {
return valueOf(this.getBase(), this.getConversionFactor() * multiplier);
}
-
+
/**
* Returns the product of this unit and another.
*
- * @param multiplier
- * unit to multiply by
+ * @param multiplier unit to multiply by
* @return product of two units
- * @throws NullPointerException
- * if {@code multiplier} is null
+ * @throws NullPointerException if {@code multiplier} is null
* @since 2018-12-22
* @since v0.1.0
*/
public LinearUnit times(final LinearUnit multiplier) {
Objects.requireNonNull(multiplier, "other must not be null");
-
+
// multiply the units
- final ObjectProduct<BaseUnit> base = this.getBase().times(multiplier.getBase());
- return valueOf(base, this.getConversionFactor() * multiplier.getConversionFactor());
+ final ObjectProduct<BaseUnit> base = this.getBase()
+ .times(multiplier.getBase());
+ return valueOf(base,
+ this.getConversionFactor() * multiplier.getConversionFactor());
}
-
+
/**
* Returns this unit but to an exponent.
*
- * @param exponent
- * exponent to exponentiate unit to
+ * @param exponent exponent to exponentiate unit to
* @return exponentiated unit
* @since 2019-01-15
* @since v0.1.0
*/
public LinearUnit toExponent(final int exponent) {
- return valueOf(this.getBase().toExponent(exponent), Math.pow(this.conversionFactor, exponent));
+ return valueOf(this.getBase().toExponent(exponent),
+ Math.pow(this.conversionFactor, exponent));
}
-
+
/**
* @return a string providing a definition of this unit
* @since 2019-10-21
@@ -339,10 +371,13 @@ public final class LinearUnit extends Unit {
@Override
public String toString() {
return this.getPrimaryName().orElse("Unnamed unit")
- + (this.getSymbol().isPresent() ? String.format(" (%s)", this.getSymbol().get()) : "") + ", "
- + Double.toString(this.conversionFactor) + " * " + this.getBase().toString(u -> u.getSymbol().get());
+ + (this.getSymbol().isPresent()
+ ? String.format(" (%s)", this.getSymbol().get())
+ : "")
+ + ", " + Double.toString(this.conversionFactor) + " * "
+ + this.getBase().toString(u -> u.getSymbol().get());
}
-
+
@Override
public LinearUnit withName(final NameSymbol ns) {
return valueOf(this.getBase(), this.getConversionFactor(), ns);
@@ -351,37 +386,38 @@ public final class LinearUnit extends Unit {
/**
* Returns the result of applying {@code prefix} to this unit.
* <p>
- * If this unit and the provided prefix have a primary name, the returned unit will have a primary name (prefix's
- * name + unit's name). <br>
- * If this unit and the provided prefix have a symbol, the returned unit will have a symbol. <br>
- * This method ignores alternate names of both this unit and the provided prefix.
+ * If this unit and the provided prefix have a primary name, the returned
+ * unit will have a primary name (prefix's name + unit's name). <br>
+ * If this unit and the provided prefix have a symbol, the returned unit will
+ * have a symbol. <br>
+ * This method ignores alternate names of both this unit and the provided
+ * prefix.
*
- * @param prefix
- * prefix to apply
+ * @param prefix prefix to apply
* @return unit with prefix
* @since 2019-03-18
* @since v0.2.0
- * @throws NullPointerException
- * if prefix is null
+ * @throws NullPointerException if prefix is null
*/
public LinearUnit withPrefix(final UnitPrefix prefix) {
final LinearUnit unit = this.times(prefix.getMultiplier());
-
+
// create new name and symbol, if possible
final String name;
- if (this.getPrimaryName().isPresent() && prefix.getPrimaryName().isPresent()) {
+ if (this.getPrimaryName().isPresent()
+ && prefix.getPrimaryName().isPresent()) {
name = prefix.getPrimaryName().get() + this.getPrimaryName().get();
} else {
name = null;
}
-
+
final String symbol;
if (this.getSymbol().isPresent() && prefix.getSymbol().isPresent()) {
symbol = prefix.getSymbol().get() + this.getSymbol().get();
} else {
symbol = null;
}
-
+
return unit.withName(NameSymbol.ofNullable(name, symbol));
}
}
diff --git a/src/org/unitConverter/unit/LinearUnitValue.java b/src/org/unitConverter/unit/LinearUnitValue.java
index 5685a6d..d86d344 100644
--- a/src/org/unitConverter/unit/LinearUnitValue.java
+++ b/src/org/unitConverter/unit/LinearUnitValue.java
@@ -3,12 +3,11 @@
*/
package org.unitConverter.unit;
-import java.math.BigDecimal;
-import java.math.RoundingMode;
import java.util.Objects;
import java.util.Optional;
import org.unitConverter.math.DecimalComparison;
+import org.unitConverter.math.UncertainDouble;
/**
* A possibly uncertain value expressed in a linear unit.
@@ -33,7 +32,8 @@ public final class LinearUnitValue {
public static final LinearUnitValue getExact(final LinearUnit unit,
final double value) {
return new LinearUnitValue(
- Objects.requireNonNull(unit, "unit must not be null"), value, 0);
+ Objects.requireNonNull(unit, "unit must not be null"),
+ UncertainDouble.of(value, 0));
}
/**
@@ -46,41 +46,23 @@ public final class LinearUnitValue {
* @since 2020-07-26
*/
public static final LinearUnitValue of(final LinearUnit unit,
- final double value, final double uncertainty) {
+ final UncertainDouble value) {
return new LinearUnitValue(
- Objects.requireNonNull(unit, "unit must not be null"), value,
- uncertainty);
- }
-
- /**
- * Gets an uncertain {@code LinearUnitValue}
- *
- * @param unit unit to express with
- * @param value value to express
- * @param relativeUncertainty relative uncertainty of value
- * @return uncertain {@code LinearUnitValue} instance
- * @since 2020-07-28
- */
- public static final LinearUnitValue ofRelative(final LinearUnit unit,
- final double value, final double relativeUncertainty) {
- return LinearUnitValue.of(unit, value, relativeUncertainty * value);
+ Objects.requireNonNull(unit, "unit must not be null"),
+ Objects.requireNonNull(value, "value may not be null"));
}
private final LinearUnit unit;
- private final double value;
- private final double uncertainty;
+ private final UncertainDouble value;
/**
- * @param unit unit to express as
- * @param value value to express
- * @param uncertainty absolute uncertainty of value
+ * @param unit unit to express as
+ * @param value value to express
* @since 2020-07-26
*/
- private LinearUnitValue(final LinearUnit unit, final double value,
- final double uncertainty) {
+ private LinearUnitValue(final LinearUnit unit, final UncertainDouble value) {
this.unit = unit;
this.value = value;
- this.uncertainty = uncertainty;
}
/**
@@ -89,7 +71,7 @@ public final class LinearUnitValue {
* @since 2020-08-04
*/
public final UnitValue asUnitValue() {
- return UnitValue.of(this.unit, this.value);
+ return UnitValue.of(this.unit, this.value.value());
}
/**
@@ -110,8 +92,7 @@ public final class LinearUnitValue {
* @since 2020-07-26
*/
public final LinearUnitValue convertTo(final LinearUnit other) {
- return LinearUnitValue.of(other, this.unit.convertTo(other, this.value),
- this.unit.convertTo(other, this.uncertainty));
+ return LinearUnitValue.of(other, this.unit.convertTo(other, this.value));
}
/**
@@ -122,8 +103,7 @@ public final class LinearUnitValue {
* @since 2020-07-28
*/
public LinearUnitValue dividedBy(final double divisor) {
- return LinearUnitValue.of(this.unit, this.value / divisor,
- this.uncertainty / divisor);
+ return LinearUnitValue.of(this.unit, this.value.dividedByExact(divisor));
}
/**
@@ -134,10 +114,8 @@ public final class LinearUnitValue {
* @since 2020-07-28
*/
public LinearUnitValue dividedBy(final LinearUnitValue divisor) {
- return LinearUnitValue.ofRelative(this.unit.dividedBy(divisor.unit),
- this.value / divisor.value,
- Math.hypot(this.getRelativeUncertainty(),
- divisor.getRelativeUncertainty()));
+ return LinearUnitValue.of(this.unit.dividedBy(divisor.unit),
+ this.value.dividedBy(divisor.value));
}
/**
@@ -154,12 +132,8 @@ public final class LinearUnitValue {
return false;
final LinearUnitValue other = (LinearUnitValue) obj;
return Objects.equals(this.unit.getBase(), other.unit.getBase())
- && Double.doubleToLongBits(
- this.unit.convertToBase(this.getValue())) == Double
- .doubleToLongBits(
- other.unit.convertToBase(other.getValue()))
- && Double.doubleToLongBits(this.getRelativeUncertainty()) == Double
- .doubleToLongBits(other.getRelativeUncertainty());
+ && this.unit.convertToBase(this.value)
+ .equals(other.unit.convertToBase(other.value));
}
/**
@@ -180,9 +154,7 @@ public final class LinearUnitValue {
final LinearUnitValue other = (LinearUnitValue) obj;
return Objects.equals(this.unit.getBase(), other.unit.getBase())
&& DecimalComparison.equals(this.unit.convertToBase(this.value),
- other.unit.convertToBase(other.value))
- && DecimalComparison.equals(this.getRelativeUncertainty(),
- other.getRelativeUncertainty());
+ other.unit.convertToBase(other.value));
}
/**
@@ -195,32 +167,11 @@ public final class LinearUnitValue {
if (other == null
|| !Objects.equals(this.unit.getBase(), other.unit.getBase()))
return false;
- final double thisBaseValue = this.unit.convertToBase(this.value);
- final double otherBaseValue = other.unit.convertToBase(other.value);
- final double thisBaseUncertainty = this.unit
- .convertToBase(this.uncertainty);
- final double otherBaseUncertainty = other.unit
- .convertToBase(other.uncertainty);
- return Math.abs(thisBaseValue - otherBaseValue) <= Math
- .min(thisBaseUncertainty, otherBaseUncertainty);
- }
-
- /**
- * @return relative uncertainty of value
- *
- * @since 2020-07-26
- */
- public final double getRelativeUncertainty() {
- return this.uncertainty / this.value;
- }
-
- /**
- * @return absolute uncertainty of value
- *
- * @since 2020-07-26
- */
- public final double getUncertainty() {
- return this.uncertainty;
+ 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);
}
/**
@@ -237,24 +188,22 @@ public final class LinearUnitValue {
*
* @since 2020-07-26
*/
- public final double getValue() {
+ public final UncertainDouble getValue() {
return this.value;
}
+ /**
+ * @return the exact value
+ * @since 2020-09-07
+ */
+ public final double getValueExact() {
+ return this.value.value();
+ }
+
@Override
public int hashCode() {
return Objects.hash(this.unit.getBase(),
- this.unit.convertToBase(this.getValue()),
- this.getRelativeUncertainty());
- }
-
- /**
- * @return true iff the value has no uncertainty
- *
- * @since 2020-07-26
- */
- public final boolean isExact() {
- return this.uncertainty == 0;
+ this.unit.convertToBase(this.getValue()));
}
/**
@@ -276,8 +225,8 @@ public final class LinearUnitValue {
this.unit, subtrahend.unit));
final LinearUnitValue otherConverted = subtrahend.convertTo(this.unit);
- return LinearUnitValue.of(this.unit, this.value - otherConverted.value,
- Math.hypot(this.uncertainty, otherConverted.uncertainty));
+ return LinearUnitValue.of(this.unit,
+ this.value.minus(otherConverted.value));
}
/**
@@ -298,8 +247,8 @@ public final class LinearUnitValue {
addend.unit));
final LinearUnitValue otherConverted = addend.convertTo(this.unit);
- return LinearUnitValue.of(this.unit, this.value + otherConverted.value,
- Math.hypot(this.uncertainty, otherConverted.uncertainty));
+ return LinearUnitValue.of(this.unit,
+ this.value.plus(otherConverted.value));
}
/**
@@ -310,8 +259,7 @@ public final class LinearUnitValue {
* @since 2020-07-28
*/
public LinearUnitValue times(final double multiplier) {
- return LinearUnitValue.of(this.unit, this.value * multiplier,
- this.uncertainty * multiplier);
+ return LinearUnitValue.of(this.unit, this.value.timesExact(multiplier));
}
/**
@@ -322,10 +270,8 @@ public final class LinearUnitValue {
* @since 2020-07-28
*/
public LinearUnitValue times(final LinearUnitValue multiplier) {
- return LinearUnitValue.ofRelative(this.unit.times(multiplier.unit),
- this.value * multiplier.value,
- Math.hypot(this.getRelativeUncertainty(),
- multiplier.getRelativeUncertainty()));
+ return LinearUnitValue.of(this.unit.times(multiplier.unit),
+ this.value.times(multiplier.value));
}
/**
@@ -336,14 +282,13 @@ public final class LinearUnitValue {
* @since 2020-07-28
*/
public LinearUnitValue toExponent(final int exponent) {
- return LinearUnitValue.ofRelative(this.unit.toExponent(exponent),
- Math.pow(this.value, exponent),
- this.getRelativeUncertainty() * Math.sqrt(exponent));
+ return LinearUnitValue.of(this.unit.toExponent(exponent),
+ this.value.toExponentExact(exponent));
}
@Override
public String toString() {
- return this.toString(!this.isExact());
+ return this.toString(!this.value.isExact());
}
/**
@@ -363,107 +308,22 @@ public final class LinearUnitValue {
final Optional<String> symbol = this.unit.getSymbol();
final String chosenName = symbol.orElse(primaryName.orElse(null));
- final double baseValue = this.unit.convertToBase(this.value);
- final double baseUncertainty = this.unit.convertToBase(this.uncertainty);
+ final UncertainDouble baseValue = this.unit.convertToBase(this.value);
// get rounded strings
- String valueString, baseValueString, uncertaintyString,
- baseUncertaintyString;
- if (this.isExact()) {
- valueString = Double.toString(this.value);
- baseValueString = Double.toString(baseValue);
- uncertaintyString = "0";
- baseUncertaintyString = "0";
- } else {
- final BigDecimal bigValue = BigDecimal.valueOf(this.value);
- final BigDecimal bigUncertainty = BigDecimal.valueOf(this.uncertainty);
-
- // round based on uncertainty
- // if uncertainty starts with 1 (ignoring zeroes and the decimal
- // point), rounds
- // so that uncertainty has 2 significant digits.
- // otherwise, rounds so that uncertainty has 1 significant digits.
- // the value is rounded to the same number of decimal places as the
- // uncertainty.
- BigDecimal roundedUncertainty = bigUncertainty.setScale(
- bigUncertainty.scale() - bigUncertainty.precision() + 2,
- RoundingMode.HALF_EVEN);
- if (roundedUncertainty.unscaledValue().intValue() >= 20) {
- roundedUncertainty = bigUncertainty.setScale(
- bigUncertainty.scale() - bigUncertainty.precision() + 1,
- RoundingMode.HALF_EVEN);
- }
- final BigDecimal roundedValue = bigValue
- .setScale(roundedUncertainty.scale(), RoundingMode.HALF_EVEN);
-
- valueString = roundedValue.toString();
- uncertaintyString = roundedUncertainty.toString();
-
- if (primaryName.isEmpty() && symbol.isEmpty()) {
- final BigDecimal bigBaseValue = BigDecimal.valueOf(baseValue);
- final BigDecimal bigBaseUncertainty = BigDecimal
- .valueOf(baseUncertainty);
-
- BigDecimal roundedBaseUncertainty = bigBaseUncertainty
- .setScale(
- bigBaseUncertainty.scale()
- - bigBaseUncertainty.precision() + 2,
- RoundingMode.HALF_EVEN);
- if (roundedBaseUncertainty.unscaledValue().intValue() >= 20) {
- roundedBaseUncertainty = bigBaseUncertainty
- .setScale(
- bigBaseUncertainty.scale()
- - bigBaseUncertainty.precision() + 1,
- RoundingMode.HALF_EVEN);
- }
- final BigDecimal roundedBaseValue = bigBaseValue.setScale(
- roundedBaseUncertainty.scale(), RoundingMode.HALF_EVEN);
-
- baseValueString = roundedBaseValue.toString();
- baseUncertaintyString = roundedBaseUncertainty.toString();
- } else {
- // unused
- baseValueString = "";
- baseUncertaintyString = "";
- }
- }
+ // if showUncertainty is true, add brackets around the string
+ final String valueString = showUncertainty ? "("
+ : "" + this.value.toString(showUncertainty)
+ + (showUncertainty ? ")" : "");
+ final String baseValueString = showUncertainty ? "("
+ : "" + baseValue.toString(showUncertainty)
+ + (showUncertainty ? ")" : "");
// create string
- if (showUncertainty) {
- if (primaryName.isEmpty() && symbol.isEmpty())
- return String.format("(%s ± %s) unnamed unit (= %s ± %s %s)",
- valueString, uncertaintyString, baseValueString,
- baseUncertaintyString, this.unit.getBase());
- else
- return String.format("(%s ± %s) %s", valueString, uncertaintyString,
- chosenName);
- } else {
- // truncate excess zeroes
- if (valueString.contains(".")) {
- while (valueString.endsWith("0")) {
- valueString = valueString.substring(0, valueString.length() - 1);
- }
- if (valueString.endsWith(".")) {
- valueString = valueString.substring(0, valueString.length() - 1);
- }
- }
-
- if (baseValueString.contains(".")) {
- while (baseValueString.endsWith("0")) {
- baseValueString = baseValueString.substring(0,
- baseValueString.length() - 1);
- }
- if (baseValueString.endsWith(".")) {
- baseValueString = baseValueString.substring(0,
- baseValueString.length() - 1);
- }
- }
-
- if (primaryName.isEmpty() && symbol.isEmpty())
- return String.format("%s unnamed unit (= %s %s)", valueString,
- baseValueString, this.unit.getBase());
- else
- return String.format("%s %s", valueString, chosenName);
- }
+ if (primaryName.isEmpty() && symbol.isEmpty())
+ return String.format("%s unnamed unit (= %s %s)", valueString,
+ baseValueString, this.unit.getBase());
+ else
+ return String.format("%s %s", valueString, chosenName);
}
}
diff --git a/src/org/unitConverter/unit/UnitDatabase.java b/src/org/unitConverter/unit/UnitDatabase.java
index 9812bd0..9ca9617 100644
--- a/src/org/unitConverter/unit/UnitDatabase.java
+++ b/src/org/unitConverter/unit/UnitDatabase.java
@@ -46,6 +46,7 @@ import org.unitConverter.math.ConditionalExistenceCollections;
import org.unitConverter.math.DecimalComparison;
import org.unitConverter.math.ExpressionParser;
import org.unitConverter.math.ObjectProduct;
+import org.unitConverter.math.UncertainDouble;
/**
* A database of units, prefixes and dimensions, and their names.
@@ -1134,7 +1135,7 @@ public final class UnitDatabase {
// exponent function - first check if o2 is a number,
if (exponentValue.canConvertTo(SI.ONE)) {
// then check if it is an integer,
- final double exponent = exponentValue.getValue();
+ final double exponent = exponentValue.getValueExact();
if (DecimalComparison.equals(exponent % 1, 0))
// then exponentiate
return base.toExponent((int) (exponent + 0.5));
@@ -1650,7 +1651,8 @@ public final class UnitDatabase {
final BigDecimal number = new BigDecimal(name);
final double uncertainty = Math.pow(10, -number.scale());
- return LinearUnitValue.of(SI.ONE, number.doubleValue(), uncertainty);
+ return LinearUnitValue.of(SI.ONE,
+ UncertainDouble.of(number.doubleValue(), uncertainty));
} catch (final NumberFormatException e) {
return LinearUnitValue.getExact(this.getLinearUnit(name), 1);
}
diff --git a/src/org/unitConverter/unit/UnitTest.java b/src/org/unitConverter/unit/UnitTest.java
index ff83805..c0711dc 100644
--- a/src/org/unitConverter/unit/UnitTest.java
+++ b/src/org/unitConverter/unit/UnitTest.java
@@ -56,9 +56,10 @@ class UnitTest {
final LinearUnitValue value4 = LinearUnitValue.getExact(SI.KILOGRAM, 60);
// make sure addition is done correctly
- assertEquals(51.576, value1.plus(value2).getValue(), 0.001);
- assertEquals(15.5, value1.plus(value3).getValue());
- assertEquals(52.076, value1.plus(value2).plus(value3).getValue(), 0.001);
+ assertEquals(51.576, value1.plus(value2).getValueExact(), 0.001);
+ assertEquals(15.5, value1.plus(value3).getValueExact());
+ assertEquals(52.076, value1.plus(value2).plus(value3).getValueExact(),
+ 0.001);
// make sure addition uses the correct unit, and is still associative
// (ignoring floating-point rounding errors)