summaryrefslogtreecommitdiff
path: root/src/org/unitConverter/unit
diff options
context:
space:
mode:
authorAdrien Hopkins <adrien.p.hopkins@gmail.com>2019-03-22 17:00:58 -0400
committerAdrien Hopkins <adrien.p.hopkins@gmail.com>2019-03-22 17:00:58 -0400
commit943496888d18b031be19ba8e7348ec188dc8eb6b (patch)
tree03b440bf7d7789be5fd88b8ce3785f900804c773 /src/org/unitConverter/unit
parentea940f2c5b6450231ff9ce61f4b6704babdb0d9e (diff)
Made BaseUnit a subclass of LinearUnit and made an expression parser
Diffstat (limited to 'src/org/unitConverter/unit')
-rwxr-xr-xsrc/org/unitConverter/unit/BaseUnit.java151
-rw-r--r--src/org/unitConverter/unit/LinearUnit.java164
-rw-r--r--src/org/unitConverter/unit/OperatableUnit.java169
3 files changed, 133 insertions, 351 deletions
diff --git a/src/org/unitConverter/unit/BaseUnit.java b/src/org/unitConverter/unit/BaseUnit.java
index 894d338..2def48e 100755
--- a/src/org/unitConverter/unit/BaseUnit.java
+++ b/src/org/unitConverter/unit/BaseUnit.java
@@ -28,7 +28,7 @@ import org.unitConverter.dimension.UnitDimension;
* @since 2018-12-23
* @since v0.1.0
*/
-public final class BaseUnit extends AbstractUnit implements OperatableUnit {
+public final class BaseUnit extends LinearUnit {
/**
* Is this unit a full base (i.e. m, s, ... but not N, J, ...)
*
@@ -52,156 +52,65 @@ public final class BaseUnit extends AbstractUnit implements OperatableUnit {
* @since v0.1.0
*/
BaseUnit(final UnitDimension dimension, final UnitSystem system) {
- super(dimension, system);
+ super(dimension, system, 1);
this.isFullBase = dimension.isBase();
}
/**
- * @return this unit as a {@code LinearUnit}
- * @since 2019-01-25
- * @since v0.1.0
- */
- public LinearUnit asLinearUnit() {
- return this.times(1);
- }
-
- @Override
- public double convertFromBase(final double value) {
- return value;
- }
-
- @Override
- public double convertToBase(final double value) {
- return value;
- }
-
- /**
- * Divides this unit by another unit.
+ * Returns the quotient of this unit and another.
+ * <p>
+ * Two units can be divided if they are part of the same unit system. If {@code divisor} does not meet this
+ * condition, an {@code IllegalArgumentException} should be thrown.
+ * </p>
*
- * @param other
+ * @param divisor
* unit to divide by
* @return quotient of two units
* @throws IllegalArgumentException
- * if this unit's system is not other's system
+ * if {@code divisor} is not compatible for division as described above
* @throws NullPointerException
- * if other is null
+ * if {@code divisor} is null
* @since 2018-12-22
* @since v0.1.0
*/
- public BaseUnit dividedBy(final BaseUnit other) {
- Objects.requireNonNull(other, "other must not be null.");
- if (!this.getSystem().equals(other.getSystem()))
- throw new IllegalArgumentException("Incompatible base units for division.");
- return new BaseUnit(this.getDimension().dividedBy(other.getDimension()), this.getSystem());
- }
+ public BaseUnit dividedBy(final BaseUnit divisor) {
+ Objects.requireNonNull(divisor, "other must not be null.");
- /**
- * Divides this unit by a divisor
- *
- * @param divisor
- * amount to divide by
- * @return quotient
- * @since 2018-12-23
- * @since v0.1.0
- */
- public LinearUnit dividedBy(final double divisor) {
- return new LinearUnit(this, 1 / divisor);
- }
-
- @Override
- public boolean equals(final Object obj) {
- if (!(obj instanceof BaseUnit))
- return false;
- final BaseUnit other = (BaseUnit) obj;
- return Objects.equals(this.getSystem(), other.getSystem())
- && Objects.equals(this.getDimension(), other.getDimension());
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = result * prime + this.getSystem().hashCode();
- result = result * prime + this.getDimension().hashCode();
- return result;
- }
-
- @Override
- public LinearUnit negated() {
- return this.times(-1);
- }
-
- @Override
- public OperatableUnit plus(final OperatableUnit addend) {
- Objects.requireNonNull(addend, "addend must not be null.");
-
- // reject addends that cannot be added to this unit
- if (!this.getSystem().equals(addend.getSystem()))
- throw new IllegalArgumentException(
- String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
- if (!this.getDimension().equals(addend.getDimension()))
+ // check that these units can be multiplied
+ if (!this.getSystem().equals(divisor.getSystem()))
throw new IllegalArgumentException(
- String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
-
- // add them together
- if (addend instanceof BaseUnit)
- return this.times(2);
- else
- return addend.plus(this);
- }
+ String.format("Incompatible units for division \"%s\" and \"%s\".", this, divisor));
- @Override
- public BaseUnit reciprocal() {
- return this.toExponent(-1);
+ return new BaseUnit(this.getDimension().dividedBy(divisor.getDimension()), this.getSystem());
}
/**
- * Multiplies this unit by another unit.
+ * Returns the product of this unit and another.
+ * <p>
+ * Two units can be multiplied if they are part of the same unit system. If {@code multiplier} does not meet this
+ * condition, an {@code IllegalArgumentException} should be thrown.
+ * </p>
*
- * @param other
+ * @param multiplier
* unit to multiply by
* @return product of two units
* @throws IllegalArgumentException
- * if this unit's system is not other's system
+ * if {@code multiplier} is not compatible for multiplication as described above
* @throws NullPointerException
- * if other is null
+ * if {@code multiplier} is null
* @since 2018-12-22
* @since v0.1.0
*/
- public BaseUnit times(final BaseUnit other) {
- Objects.requireNonNull(other, "other must not be null.");
- if (!this.getSystem().equals(other.getSystem()))
- throw new IllegalArgumentException("Incompatible base units for multiplication.");
- return new BaseUnit(this.getDimension().times(other.getDimension()), this.getSystem());
- }
-
- /**
- * Multiplies this unit by a multiplier.
- *
- * @param multiplier
- * amount to multiply by
- * @return product
- * @since 2018-12-23
- * @since v0.1.0
- */
- public LinearUnit times(final double multiplier) {
- return new LinearUnit(this, multiplier);
- }
+ public BaseUnit times(final BaseUnit multiplier) {
+ Objects.requireNonNull(multiplier, "other must not be null");
- @Override
- public OperatableUnit times(final OperatableUnit multiplier) {
- Objects.requireNonNull(multiplier, "multiplier must not be null.");
-
- // reject multipliers that cannot be muliplied by this unit
+ // check that these units can be multiplied
if (!this.getSystem().equals(multiplier.getSystem()))
- throw new IllegalArgumentException(String
- .format("Incompatible units for multiplication or division \"%s\" and \"%s\".", this, multiplier));
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for multiplication \"%s\" and \"%s\".", this, multiplier));
// multiply the units
- if (multiplier instanceof BaseUnit)
- return new BaseUnit(this.getDimension().times(multiplier.getDimension()), this.getSystem());
- else
- return multiplier.times(this);
+ return new BaseUnit(this.getDimension().times(multiplier.getDimension()), this.getSystem());
}
/**
diff --git a/src/org/unitConverter/unit/LinearUnit.java b/src/org/unitConverter/unit/LinearUnit.java
index 64eff1f..c755f79 100644
--- a/src/org/unitConverter/unit/LinearUnit.java
+++ b/src/org/unitConverter/unit/LinearUnit.java
@@ -19,6 +19,7 @@ package org.unitConverter.unit;
import java.util.Objects;
import org.unitConverter.dimension.UnitDimension;
+import org.unitConverter.math.DecimalComparison;
/**
* A unit that is equal to a certain number multiplied by its base.
@@ -27,7 +28,7 @@ import org.unitConverter.dimension.UnitDimension;
* @since 2018-12-22
* @since v0.1.0
*/
-public final class LinearUnit extends AbstractUnit implements OperatableUnit {
+public class LinearUnit extends AbstractUnit {
/**
* The value of one of this unit in this unit's base unit
*
@@ -91,20 +92,33 @@ public final class LinearUnit extends AbstractUnit implements OperatableUnit {
}
/**
- * Divides this unit by another unit.
+ * Returns the quotient of this unit and another.
+ * <p>
+ * Two units can be divided if they are part of the same unit system. If {@code divisor} does not meet this
+ * condition, an {@code IllegalArgumentException} should be thrown.
+ * </p>
*
- * @param other
+ * @param divisor
* unit to divide by
* @return quotient of two units
+ * @throws IllegalArgumentException
+ * if {@code divisor} is not compatible for division as described above
* @throws NullPointerException
- * if other is null
+ * if {@code divisor} is null
* @since 2018-12-22
* @since v0.1.0
*/
- public LinearUnit dividedBy(final LinearUnit other) {
- Objects.requireNonNull(other, "other must not be null");
- final BaseUnit base = this.getBase().dividedBy(other.getBase());
- return new LinearUnit(base, this.getConversionFactor() / other.getConversionFactor());
+ public LinearUnit dividedBy(final LinearUnit divisor) {
+ Objects.requireNonNull(divisor, "other must not be null");
+
+ // check that these units can be multiplied
+ if (!this.getSystem().equals(divisor.getSystem()))
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for division \"%s\" and \"%s\".", this, divisor));
+
+ // divide the units
+ final BaseUnit base = this.getBase().dividedBy(divisor.getBase());
+ return new LinearUnit(base, this.getConversionFactor() / divisor.getConversionFactor());
}
@Override
@@ -112,12 +126,13 @@ public final class LinearUnit extends AbstractUnit implements OperatableUnit {
if (!(obj instanceof LinearUnit))
return false;
final LinearUnit other = (LinearUnit) obj;
- return Objects.equals(this.getBase(), other.getBase())
- && Objects.equals(this.getConversionFactor(), other.getConversionFactor());
+ return Objects.equals(this.getSystem(), other.getSystem())
+ && Objects.equals(this.getDimension(), other.getDimension())
+ && DecimalComparison.equals(this.getConversionFactor(), other.getConversionFactor());
}
/**
- * @return conversionFactor
+ * @return conversion factor between this unit and its base
* @since 2018-12-22
* @since v0.1.0
*/
@@ -129,43 +144,66 @@ public final class LinearUnit extends AbstractUnit implements OperatableUnit {
public int hashCode() {
final int prime = 31;
int result = 1;
- result = result * prime + this.getBase().hashCode();
+ result = result * prime + this.getSystem().hashCode();
+ result = result * prime + this.getDimension().hashCode();
result = result * prime + Double.hashCode(this.getConversionFactor());
return result;
}
- @Override
- public LinearUnit negated() {
- return new LinearUnit(this.getBase(), -this.getConversionFactor());
+ /**
+ * Returns the difference of this unit and another.
+ * <p>
+ * Two units can be subtracted if they have the same base. If {@code subtrahend} does not meet this condition, an
+ * {@code IllegalArgumentException} will be thrown.
+ * </p>
+ *
+ * @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
+ * @since 2019-03-17
+ */
+ public LinearUnit minus(final LinearUnit subtrahendend) {
+ Objects.requireNonNull(subtrahendend, "addend must not be null.");
+
+ // reject subtrahends that cannot be added to this unit
+ if (!this.getBase().equals(subtrahendend.getBase()))
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for subtraction \"%s\" and \"%s\".", this, subtrahendend));
+
+ // add the units
+ return new LinearUnit(this.getBase(), this.getConversionFactor() - subtrahendend.getConversionFactor());
}
- @Override
- public OperatableUnit plus(final OperatableUnit addend) {
+ /**
+ * Returns the sum of this unit and another.
+ * <p>
+ * Two units can be added if they have the same base. If {@code addend} does not meet this condition, an
+ * {@code IllegalArgumentException} will be thrown.
+ * </p>
+ *
+ * @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
+ * @since 2019-03-17
+ */
+ 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.getSystem().equals(addend.getSystem()))
- throw new IllegalArgumentException(
- String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
- if (!this.getDimension().equals(addend.getDimension()))
+ if (!this.getBase().equals(addend.getBase()))
throw new IllegalArgumentException(
- String.format("Incompatible units for addition or subtraction \"%s\" and \"%s\".", this, addend));
+ String.format("Incompatible units for addition \"%s\" and \"%s\".", this, addend));
// add the units
- if (addend instanceof BaseUnit)
- // since addend's dimension is equal to this unit's dimension, and there is only one base unit per
- // system-dimension, addend must be this unit's base.
- return new LinearUnit(this.getBase(), this.getConversionFactor() + 1);
- else if (addend instanceof LinearUnit)
- return new LinearUnit(this.getBase(),
- this.getConversionFactor() + ((LinearUnit) addend).getConversionFactor());
- else
- return addend.times(this);
- }
-
- @Override
- public LinearUnit reciprocal() {
- return this.toExponent(-1);
+ return new LinearUnit(this.getBase(), this.getConversionFactor() + addend.getConversionFactor());
}
/**
@@ -182,40 +220,33 @@ public final class LinearUnit extends AbstractUnit implements OperatableUnit {
}
/**
- * Multiplies this unit by another unit.
+ * Returns the product of this unit and another.
+ * <p>
+ * Two units can be multiplied if they are part of the same unit system. If {@code multiplier} does not meet this
+ * condition, an {@code IllegalArgumentException} should be thrown.
+ * </p>
*
- * @param other
- * unit to multiply by=
+ * @param multiplier
+ * unit to multiply by
* @return product of two units
+ * @throws IllegalArgumentException
+ * if {@code multiplier} is not compatible for multiplication as described above
* @throws NullPointerException
- * if other is null
+ * if {@code multiplier} is null
* @since 2018-12-22
* @since v0.1.0
*/
- public LinearUnit times(final LinearUnit other) {
- Objects.requireNonNull(other, "other must not be null");
- final BaseUnit base = this.getBase().times(other.getBase());
- return new LinearUnit(base, this.getConversionFactor() * other.getConversionFactor());
- }
-
- @Override
- public OperatableUnit times(final OperatableUnit multiplier) {
- Objects.requireNonNull(multiplier, "multiplier must not be null.");
+ public LinearUnit times(final LinearUnit multiplier) {
+ Objects.requireNonNull(multiplier, "other must not be null");
- // reject multipliers that cannot be muliplied by this unit
+ // check that these units can be multiplied
if (!this.getSystem().equals(multiplier.getSystem()))
- throw new IllegalArgumentException(String
- .format("Incompatible units for multiplication or division \"%s\" and \"%s\".", this, multiplier));
+ throw new IllegalArgumentException(
+ String.format("Incompatible units for multiplication \"%s\" and \"%s\".", this, multiplier));
// multiply the units
- if (multiplier instanceof BaseUnit) {
- final BaseUnit newBase = this.getBase().times((BaseUnit) multiplier);
- return new LinearUnit(newBase, this.getConversionFactor());
- } else if (multiplier instanceof LinearUnit) {
- final BaseUnit base = this.getBase().times(multiplier.getBase());
- return new LinearUnit(base, this.getConversionFactor() * ((LinearUnit) multiplier).getConversionFactor());
- } else
- return multiplier.times(this);
+ final BaseUnit base = this.getBase().times(multiplier.getBase());
+ return new LinearUnit(base, this.getConversionFactor() * multiplier.getConversionFactor());
}
/**
@@ -227,7 +258,6 @@ public final class LinearUnit extends AbstractUnit implements OperatableUnit {
* @since 2019-01-15
* @since v0.1.0
*/
- @Override
public LinearUnit toExponent(final int exponent) {
return new LinearUnit(this.getBase().toExponent(exponent), Math.pow(this.conversionFactor, exponent));
}
@@ -236,4 +266,16 @@ public final class LinearUnit extends AbstractUnit implements OperatableUnit {
public String toString() {
return super.toString() + String.format(" (equal to %s * base)", this.getConversionFactor());
}
+
+ /**
+ * Returns the result of applying {@code prefix} to this unit.
+ *
+ * @param prefix
+ * prefix to apply
+ * @return unit with prefix
+ * @since 2019-03-18
+ */
+ public LinearUnit withPrefix(final UnitPrefix prefix) {
+ return this.times(prefix.getMultiplier());
+ }
}
diff --git a/src/org/unitConverter/unit/OperatableUnit.java b/src/org/unitConverter/unit/OperatableUnit.java
deleted file mode 100644
index ae11c41..0000000
--- a/src/org/unitConverter/unit/OperatableUnit.java
+++ /dev/null
@@ -1,169 +0,0 @@
-/**
- * Copyright (C) 2019 Adrien Hopkins
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-package org.unitConverter.unit;
-
-/**
- * A unit that can be added, subtracted, multiplied or divided by another operatable unit, and raised to an integer
- * exponent.
- * <p>
- * In order to use two units in an operation, they must be part of the same unit system. In addition, in order for two
- * units to add or subtract, they must measure the same dimension.
- * </p>
- * <p>
- * It is okay for an operation to throw a {@code ClassCastException} if the operator's class cannot operate with another
- * class. However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
- * {@code LinearUnit}.
- * </p>
- *
- * @author Adrien Hopkins
- * @since 2019-03-17
- */
-public interface OperatableUnit extends Unit {
- /**
- * Returns the quotient of this unit and another.
- * <p>
- * Two units can be divided if they are part of the same unit system. If {@code divisor} does not meet this
- * condition, an {@code IllegalArgumentException} should be thrown.
- * </p>
- * <p>
- * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code divisor}'s class.
- * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
- * {@code LinearUnit}.
- * </p>
- *
- * @param divisor
- * unit to divide by
- * @return quotient
- * @throws IllegalArgumentException
- * if {@code divisor} is not compatible for division as described above
- * @throws NullPointerException
- * if {@code divisor} is null
- * @throws ClassCastException
- * if {@code divisor}'s class is incompatible with this unit's class
- * @since 2019-03-17
- */
- default OperatableUnit dividedBy(final OperatableUnit divisor) {
- return this.times(divisor.reciprocal());
- }
-
- /**
- * Returns the difference of this unit and another.
- * <p>
- * Two units can be subtracted if they meet the following conditions:
- * <ul>
- * <li>The two units are part of the same UnitSystem.</li>
- * <li>The two units have the same {@code dimension}.</li>
- * </ul>
- * If {@code subtrahend} does not meet these conditions, an {@code IllegalArgumentException} should be thrown.
- * </p>
- * <p>
- * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code subtrahend}'s class.
- * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
- * {@code LinearUnit}.
- * </p>
- *
- * @param subtrahend
- * unit to subtract
- * @return difference
- * @throws IllegalArgumentException
- * if {@code subtrahend} is not compatible for subtraction as described above
- * @throws NullPointerException
- * if {@code subtrahend} is null
- * @throws ClassCastException
- * if {@code subtrahend}'s class is incompatible with this unit's class
- * @since 2019-03-17
- */
- default OperatableUnit minus(final OperatableUnit subtrahend) {
- return this.plus(subtrahend.negated());
- }
-
- /**
- * @return this unit negated, i.e. -this
- * @since 2019-03-17
- */
- OperatableUnit negated();
-
- /**
- * Returns the sum of this unit and another.
- * <p>
- * Two units can be added if they meet the following conditions:
- * <ul>
- * <li>The two units are part of the same UnitSystem.</li>
- * <li>The two units have the same {@code dimension}.</li>
- * </ul>
- * If {@code addend} does not meet these conditions, an {@code IllegalArgumentException} should be thrown.
- * </p>
- * <p>
- * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code addend}'s class.
- * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
- * {@code LinearUnit}.
- * </p>
- *
- * @param addend
- * unit to add
- * @return sum
- * @throws IllegalArgumentException
- * if {@code addend} is not compatible for addition as described above
- * @throws NullPointerException
- * if {@code addend} is null
- * @throws ClassCastException
- * if {@code addend}'s class is incompatible with this unit's class
- * @since 2019-03-17
- */
- OperatableUnit plus(OperatableUnit addend);
-
- /**
- * @return reciprocal of this unit
- * @since 2019-03-17
- */
- OperatableUnit reciprocal();
-
- /**
- * Returns the product of this unit and another.
- * <p>
- * Two units can be multiplied if they are part of the same unit system. If {@code multiplier} does not meet this
- * condition, an {@code IllegalArgumentException} should be thrown.
- * </p>
- * <p>
- * It is okay for a unit to throw a {@code ClassCastException} if it cannot operate with {@code multiplier}'s class.
- * However, all classes that implement this interface should be able to interoperate with {@code BaseUnit} and
- * {@code LinearUnit}.
- * </p>
- *
- * @param multiplier
- * unit to multiply by
- * @return product
- * @throws IllegalArgumentException
- * if {@code multiplier} is not compatible for multiplication as described above
- * @throws NullPointerException
- * if {@code multiplier} is null
- * @throws ClassCastException
- * if {@code multiplier}'s class is incompatible with this unit's class
- * @since 2019-03-17
- */
- OperatableUnit times(OperatableUnit multiplier);
-
- /**
- * Returns the result of raising this unit to the exponent {@code exponent}.
- *
- * @param exponent
- * exponent to exponentiate by
- * @return result of exponentiation
- * @since 2019-03-17
- */
- OperatableUnit toExponent(int exponent);
-}