summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/main/java/sevenUnits/unit/BritishImperial.java39
-rw-r--r--src/main/java/sevenUnits/unit/LinearUnitValue.java5
-rw-r--r--src/main/java/sevenUnits/unit/UnitValue.java3
-rw-r--r--src/main/java/sevenUnits/utils/ObjectProduct.java135
-rw-r--r--src/test/java/sevenUnits/unit/UnitDatabaseTest.java6
-rw-r--r--src/test/java/sevenUnits/unit/UnitTest.java86
6 files changed, 182 insertions, 92 deletions
diff --git a/src/main/java/sevenUnits/unit/BritishImperial.java b/src/main/java/sevenUnits/unit/BritishImperial.java
index 81a3f2a..743beeb 100644
--- a/src/main/java/sevenUnits/unit/BritishImperial.java
+++ b/src/main/java/sevenUnits/unit/BritishImperial.java
@@ -37,7 +37,7 @@ public final class BritishImperial {
public static final LinearUnit ROOD = Length.ROD.times(Length.FURLONG);
public static final LinearUnit ACRE = Length.FURLONG.times(Length.CHAIN);
}
-
+
/**
* Imperial units that measure length
*
@@ -46,7 +46,8 @@ public final class BritishImperial {
*/
public static final class Length {
/**
- * According to the International Yard and Pound of 1959, a yard is defined as exactly 0.9144 metres.
+ * According to the International Yard and Pound of 1959, a yard is
+ * defined as exactly 0.9144 metres.
*/
public static final LinearUnit YARD = Metric.METRE.times(0.9144);
public static final LinearUnit FOOT = YARD.dividedBy(3);
@@ -56,15 +57,15 @@ public final class BritishImperial {
public static final LinearUnit FURLONG = CHAIN.times(10);
public static final LinearUnit MILE = FURLONG.times(8);
public static final LinearUnit LEAGUE = MILE.times(3);
-
+
public static final LinearUnit NAUTICAL_MILE = Metric.METRE.times(1852);
public static final LinearUnit CABLE = NAUTICAL_MILE.dividedBy(10);
public static final LinearUnit FATHOM = CABLE.dividedBy(100);
-
+
public static final LinearUnit ROD = YARD.times(5.5);
public static final LinearUnit LINK = ROD.dividedBy(25);
}
-
+
/**
* British Imperial units that measure mass.
*
@@ -82,7 +83,7 @@ public final class BritishImperial {
public static final LinearUnit LONG_TON = HUNDREDWEIGHT.times(20);
public static final LinearUnit SLUG = Metric.KILOGRAM.times(14.59390294);
}
-
+
/**
* British Imperial units that measure volume
*
@@ -90,27 +91,33 @@ public final class BritishImperial {
* @since 2019-11-08
*/
public static final class Volume {
- public static final LinearUnit FLUID_OUNCE = Metric.LITRE.withPrefix(Metric.MILLI).times(28.4130625);
+ public static final LinearUnit FLUID_OUNCE = Metric.LITRE
+ .withPrefix(Metric.MILLI).times(28.4130625);
public static final LinearUnit GILL = FLUID_OUNCE.times(5);
public static final LinearUnit PINT = FLUID_OUNCE.times(20);
public static final LinearUnit QUART = PINT.times(2);
public static final LinearUnit GALLON = QUART.times(4);
public static final LinearUnit PECK = GALLON.times(2);
public static final LinearUnit BUSHEL = PECK.times(4);
-
+
public static final LinearUnit CUBIC_INCH = Length.INCH.toExponent(3);
public static final LinearUnit CUBIC_FOOT = Length.FOOT.toExponent(3);
public static final LinearUnit CUBIC_YARD = Length.YARD.toExponent(3);
public static final LinearUnit ACRE_FOOT = Area.ACRE.times(Length.FOOT);
}
-
- public static final LinearUnit OUNCE_FORCE = Mass.OUNCE.times(Metric.Constants.EARTH_GRAVITY);
- public static final LinearUnit POUND_FORCE = Mass.POUND.times(Metric.Constants.EARTH_GRAVITY);
-
- public static final LinearUnit BRITISH_THERMAL_UNIT = Metric.JOULE.times(1055.06);
+
+ public static final LinearUnit OUNCE_FORCE = Mass.OUNCE
+ .times(Metric.Constants.EARTH_GRAVITY);
+ public static final LinearUnit POUND_FORCE = Mass.POUND
+ .times(Metric.Constants.EARTH_GRAVITY);
+
+ public static final LinearUnit BRITISH_THERMAL_UNIT = Metric.JOULE
+ .times(1055.06);
public static final LinearUnit CALORIE = Metric.JOULE.times(4.184);
public static final LinearUnit KILOCALORIE = Metric.JOULE.times(4184);
-
- public static final Unit FAHRENHEIT = Unit.fromConversionFunctions(Metric.KELVIN.getBase(),
- tempK -> tempK * 1.8 - 459.67, tempF -> (tempF + 459.67) / 1.8);
+
+ public static final Unit FAHRENHEIT = Unit
+ .fromConversionFunctions(Metric.KELVIN.getBase(),
+ tempK -> tempK * 1.8 - 459.67, tempF -> (tempF + 459.67) / 1.8)
+ .withName(NameSymbol.of("degrees Fahrenheit", "\u00B0F"));
}
diff --git a/src/main/java/sevenUnits/unit/LinearUnitValue.java b/src/main/java/sevenUnits/unit/LinearUnitValue.java
index 2219ffd..a50e1f5 100644
--- a/src/main/java/sevenUnits/unit/LinearUnitValue.java
+++ b/src/main/java/sevenUnits/unit/LinearUnitValue.java
@@ -332,9 +332,10 @@ public final class LinearUnitValue {
+ (showUncertainty ? ")" : "");
// create string
- if (primaryName.isEmpty() && symbol.isEmpty())
+ if (chosenName == null)
return String.format("%s unnamed unit (= %s %s)", valueString,
- baseValueString, this.unit.getBase());
+ baseValueString, this.unit.getBase()
+ .toString(unit -> unit.getSymbol().orElseThrow()));
else
return String.format("%s %s", valueString, chosenName);
}
diff --git a/src/main/java/sevenUnits/unit/UnitValue.java b/src/main/java/sevenUnits/unit/UnitValue.java
index 2fedd81..f6d18f8 100644
--- a/src/main/java/sevenUnits/unit/UnitValue.java
+++ b/src/main/java/sevenUnits/unit/UnitValue.java
@@ -163,7 +163,8 @@ public final class UnitValue {
if (primaryName.isEmpty() && symbol.isEmpty()) {
final double baseValue = this.getUnit().convertToBase(this.getValue());
return String.format("%s unnamed unit (= %s %s)", this.getValue(),
- baseValue, this.getUnit().getBase());
+ baseValue, this.getUnit().getBase()
+ .toString(unit -> unit.getSymbol().orElseThrow()));
} else {
final String unitName = symbol.orElse(primaryName.get());
return this.getValue() + " " + unitName;
diff --git a/src/main/java/sevenUnits/utils/ObjectProduct.java b/src/main/java/sevenUnits/utils/ObjectProduct.java
index 1dacb7d..5b1b739 100644
--- a/src/main/java/sevenUnits/utils/ObjectProduct.java
+++ b/src/main/java/sevenUnits/utils/ObjectProduct.java
@@ -27,8 +27,8 @@ import java.util.Set;
import java.util.function.Function;
/**
- * An immutable product of multiple objects of a type, such as base units. The objects can be multiplied and
- * exponentiated.
+ * An immutable product of multiple objects of a type, such as base units. The
+ * objects can be multiplied and exponentiated.
*
* @author Adrien Hopkins
* @since 2019-10-16
@@ -37,38 +37,35 @@ public final class ObjectProduct<T> {
/**
* Returns an empty ObjectProduct of a certain type
*
- * @param <T>
- * type of objects that can be multiplied
+ * @param <T> type of objects that can be multiplied
* @return empty product
* @since 2019-10-16
*/
public static final <T> ObjectProduct<T> empty() {
return new ObjectProduct<>(new HashMap<>());
}
-
+
/**
* Gets an {@code ObjectProduct} from an object-to-integer mapping
*
- * @param <T>
- * type of object in product
- * @param map
- * map mapping objects to exponents
+ * @param <T> type of object in product
+ * @param map map mapping objects to exponents
* @return object product
* @since 2019-10-16
*/
- public static final <T> ObjectProduct<T> fromExponentMapping(final Map<T, Integer> map) {
+ public static final <T> ObjectProduct<T> fromExponentMapping(
+ final Map<T, Integer> map) {
return new ObjectProduct<>(new HashMap<>(map));
}
-
+
/**
- * Gets an ObjectProduct that has one of the inputted argument, and nothing else.
+ * Gets an ObjectProduct that has one of the inputted argument, and nothing
+ * else.
*
- * @param object
- * object that will be in the product
+ * @param object object that will be in the product
* @return product
* @since 2019-10-16
- * @throws NullPointerException
- * if object is null
+ * @throws NullPointerException if object is null
*/
public static final <T> ObjectProduct<T> oneOf(final T object) {
Objects.requireNonNull(object, "object must not be null.");
@@ -76,35 +73,34 @@ public final class ObjectProduct<T> {
map.put(object, 1);
return new ObjectProduct<>(map);
}
-
+
/**
- * The objects that make up the product, mapped to their exponents. This map treats zero as null, and is immutable.
+ * The objects that make up the product, mapped to their exponents. This map
+ * treats zero as null, and is immutable.
*
* @since 2019-10-16
*/
final Map<T, Integer> exponents;
-
+
/**
* Creates the {@code ObjectProduct}.
*
- * @param exponents
- * objects that make up this product
+ * @param exponents objects that make up this product
* @since 2019-10-16
*/
private ObjectProduct(final Map<T, Integer> exponents) {
- this.exponents = Collections.unmodifiableMap(ConditionalExistenceCollections.conditionalExistenceMap(exponents,
- e -> !Integer.valueOf(0).equals(e.getValue())));
+ this.exponents = Collections.unmodifiableMap(
+ ConditionalExistenceCollections.conditionalExistenceMap(exponents,
+ e -> !Integer.valueOf(0).equals(e.getValue())));
}
-
+
/**
* Calculates the quotient of two products
*
- * @param other
- * other product
+ * @param other other product
* @return quotient of two products
* @since 2019-10-16
- * @throws NullPointerException
- * if other is null
+ * @throws NullPointerException if other is null
*/
public ObjectProduct<T> dividedBy(final ObjectProduct<T> other) {
Objects.requireNonNull(other, "other must not be null.");
@@ -112,17 +108,17 @@ public final class ObjectProduct<T> {
final Set<T> objects = new HashSet<>();
objects.addAll(this.getBaseSet());
objects.addAll(other.getBaseSet());
-
+
// get a list of all exponents
final Map<T, Integer> map = new HashMap<>(objects.size());
for (final T key : objects) {
map.put(key, this.getExponent(key) - other.getExponent(key));
}
-
+
// create the product
return new ObjectProduct<>(map);
}
-
+
// this method relies on the use of ZeroIsNullMap
@Override
public boolean equals(final Object obj) {
@@ -133,7 +129,7 @@ public final class ObjectProduct<T> {
final ObjectProduct<?> other = (ObjectProduct<?>) obj;
return Objects.equals(this.exponents, other.exponents);
}
-
+
/**
* @return immutable map mapping objects to exponents
* @since 2019-10-16
@@ -141,30 +137,31 @@ public final class ObjectProduct<T> {
public Map<T, Integer> exponentMap() {
return this.exponents;
}
-
+
/**
- * @return a set of all of the base objects with non-zero exponents that make up this dimension.
+ * @return a set of all of the base objects with non-zero exponents that make
+ * up this dimension.
* @since 2018-12-12
* @since v0.1.0
*/
public final Set<T> getBaseSet() {
final Set<T> dimensions = new HashSet<>();
-
- // add all dimensions with a nonzero exponent - zero exponents shouldn't be there in the first place
+
+ // add all dimensions with a nonzero exponent - zero exponents shouldn't
+ // be there in the first place
for (final T dimension : this.exponents.keySet()) {
if (!this.exponents.get(dimension).equals(0)) {
dimensions.add(dimension);
}
}
-
+
return dimensions;
}
-
+
/**
* Gets the exponent for a specific dimension.
*
- * @param dimension
- * dimension to check
+ * @param dimension dimension to check
* @return exponent for that dimension
* @since 2018-12-12
* @since v0.1.0
@@ -172,14 +169,15 @@ public final class ObjectProduct<T> {
public int getExponent(final T dimension) {
return this.exponents.getOrDefault(dimension, 0);
}
-
+
@Override
public int hashCode() {
return Objects.hash(this.exponents);
}
-
+
/**
- * @return true if this product is a single object, i.e. it has one exponent of one and no other nonzero exponents
+ * @return true if this product is a single object, i.e. it has one exponent
+ * of one and no other nonzero exponents
* @since 2019-10-16
*/
public boolean isSingleObject() {
@@ -194,16 +192,14 @@ public final class ObjectProduct<T> {
}
return oneCount == 1 && !twoOrMore;
}
-
+
/**
* Multiplies this product by another
*
- * @param other
- * other product
+ * @param other other product
* @return product of two products
* @since 2019-10-16
- * @throws NullPointerException
- * if other is null
+ * @throws NullPointerException if other is null
*/
public ObjectProduct<T> times(final ObjectProduct<T> other) {
Objects.requireNonNull(other, "other must not be null.");
@@ -211,22 +207,21 @@ public final class ObjectProduct<T> {
final Set<T> objects = new HashSet<>();
objects.addAll(this.getBaseSet());
objects.addAll(other.getBaseSet());
-
+
// get a list of all exponents
final Map<T, Integer> map = new HashMap<>(objects.size());
for (final T key : objects) {
map.put(key, this.getExponent(key) + other.getExponent(key));
}
-
+
// create the product
return new ObjectProduct<>(map);
}
-
+
/**
* Returns this product, but to an exponent
*
- * @param exponent
- * exponent
+ * @param exponent exponent
* @return result of exponentiation
* @since 2019-10-16
*/
@@ -237,11 +232,12 @@ public final class ObjectProduct<T> {
}
return new ObjectProduct<>(map);
}
-
+
/**
- * Converts this product to a string using the objects' {@link Object#toString()} method. If objects have a long
- * toString representation, it is recommended to use {@link #toString(Function)} instead to shorten the returned
- * string.
+ * Converts this product to a string using the objects'
+ * {@link Object#toString()} method. If objects have a long toString
+ * representation, it is recommended to use {@link #toString(Function)}
+ * instead to shorten the returned string.
*
* <p>
* {@inheritDoc}
@@ -250,35 +246,38 @@ public final class ObjectProduct<T> {
public String toString() {
return this.toString(Object::toString);
}
-
+
/**
- * Converts this product to a string. The objects that make up this product are represented by
- * {@code objectToString}
+ * Converts this product to a string. The objects that make up this product
+ * are represented by {@code objectToString}
*
- * @param objectToString
- * function to convert objects to strings
+ * @param objectToString function to convert objects to strings
* @return string representation of product
* @since 2019-10-16
*/
public String toString(final Function<T, String> objectToString) {
final List<String> positiveStringComponents = new ArrayList<>();
final List<String> negativeStringComponents = new ArrayList<>();
-
+
// for each base object that makes up this object, add it and its exponent
for (final T object : this.getBaseSet()) {
final int exponent = this.exponents.get(object);
- if (exponent > 0) {
- positiveStringComponents.add(String.format("%s^%d", objectToString.apply(object), exponent));
+ if (exponent > 1) {
+ positiveStringComponents.add(String.format("%s^%d",
+ objectToString.apply(object), exponent));
+ } else if (exponent == 1) {
+ positiveStringComponents.add(objectToString.apply(object));
} else if (exponent < 0) {
- negativeStringComponents.add(String.format("%s^%d", objectToString.apply(object), -exponent));
+ negativeStringComponents.add(String.format("%s^%d",
+ objectToString.apply(object), -exponent));
}
}
-
+
final String positiveString = positiveStringComponents.isEmpty() ? "1"
: String.join(" * ", positiveStringComponents);
final String negativeString = negativeStringComponents.isEmpty() ? ""
: " / " + String.join(" * ", negativeStringComponents);
-
+
return positiveString + negativeString;
}
}
diff --git a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
index 033d763..2276d7c 100644
--- a/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
+++ b/src/test/java/sevenUnits/unit/UnitDatabaseTest.java
@@ -568,6 +568,12 @@ class UnitDatabaseTest {
final Unit actual2 = database.getUnitFromExpression("2 fj + 6 ej");
assertEquals(expected2, actual2);
+
+ // test incorrect expressions
+ assertThrows(IllegalArgumentException.class,
+ () -> database.getUnitFromExpression("U + V"));
+ assertThrows(IllegalArgumentException.class,
+ () -> database.getUnitFromExpression("U - V"));
}
/**
diff --git a/src/test/java/sevenUnits/unit/UnitTest.java b/src/test/java/sevenUnits/unit/UnitTest.java
index e495338..bb2e6a4 100644
--- a/src/test/java/sevenUnits/unit/UnitTest.java
+++ b/src/test/java/sevenUnits/unit/UnitTest.java
@@ -27,6 +27,7 @@ import java.util.concurrent.ThreadLocalRandom;
import org.junit.jupiter.api.Test;
import sevenUnits.utils.DecimalComparison;
+import sevenUnits.utils.UncertainDouble;
/**
* Testing the various Unit classes. This is NOT part of this program's public
@@ -53,8 +54,10 @@ class UnitTest {
// test with LinearUnitValue
final LinearUnitValue value1 = LinearUnitValue.getExact(Metric.METRE, 15);
final LinearUnitValue value2 = LinearUnitValue.getExact(foot, 120);
- final LinearUnitValue value3 = LinearUnitValue.getExact(Metric.METRE, 0.5);
- final LinearUnitValue value4 = LinearUnitValue.getExact(Metric.KILOGRAM, 60);
+ final LinearUnitValue value3 = LinearUnitValue.getExact(Metric.METRE,
+ 0.5);
+ final LinearUnitValue value4 = LinearUnitValue.getExact(Metric.KILOGRAM,
+ 60);
// make sure addition is done correctly
assertEquals(51.576, value1.plus(value2).getValueExact(), 0.001);
@@ -71,6 +74,7 @@ class UnitTest {
// make sure errors happen when they should
assertThrows(IllegalArgumentException.class, () -> value1.plus(value4));
+ assertThrows(IllegalArgumentException.class, () -> value1.minus(value4));
}
@Test
@@ -122,7 +126,8 @@ class UnitTest {
public void testMultiplicationAndDivision() {
// test unit-times-unit multiplication
final LinearUnit generatedJoule = Metric.KILOGRAM
- .times(Metric.METRE.toExponent(2)).dividedBy(Metric.SECOND.toExponent(2));
+ .times(Metric.METRE.toExponent(2))
+ .dividedBy(Metric.SECOND.toExponent(2));
final LinearUnit actualJoule = Metric.JOULE;
assertEquals(generatedJoule, actualJoule);
@@ -132,16 +137,87 @@ class UnitTest {
final LinearUnit hour = Metric.SECOND.times(3600);
final LinearUnit generatedKPH = kilometre.dividedBy(hour);
- final LinearUnit actualKPH = Metric.METRE.dividedBy(Metric.SECOND).dividedBy(3.6);
+ final LinearUnit actualKPH = Metric.METRE.dividedBy(Metric.SECOND)
+ .dividedBy(3.6);
assertEquals(generatedKPH, actualKPH);
}
@Test
public void testPrefixes() {
- final LinearUnit generatedKilometre = Metric.METRE.withPrefix(Metric.KILO);
+ final LinearUnit generatedKilometre = Metric.METRE
+ .withPrefix(Metric.KILO);
final LinearUnit actualKilometre = Metric.METRE.times(1000);
assertEquals(generatedKilometre, actualKilometre);
}
+
+ /**
+ * Tests converting an uncertain LinearUnitValue to a string.
+ *
+ * @since 2021-11-04
+ */
+ @Test
+ public void testValueToString1() {
+ final LinearUnitValue value = LinearUnitValue.of(Metric.METRE,
+ UncertainDouble.of(10, 0.24));
+
+ assertEquals("(10.0 ± 0.2) m", value.toString());
+ assertEquals("(10.0 ± 0.2) m", value.toString(true));
+ assertEquals("10.0 m", value.toString(false));
+ }
+
+ /**
+ * Tests converting a certain LinearUnitValue to a string.
+ *
+ * @since 2021-11-04
+ */
+ @Test
+ public void testValueToString2() {
+ final LinearUnitValue value = LinearUnitValue.of(Metric.METRE,
+ UncertainDouble.of(10, 0));
+
+ assertEquals("10.0 m", value.toString());
+ assertEquals("(10.0 ± 0.0) m", value.toString(true));
+ assertEquals("10.0 m", value.toString(false));
+ }
+
+ /**
+ * Tests converting an unnamed LinearUnitValue to a string.
+ *
+ * @since 2021-11-04
+ */
+ @Test
+ public void testValueToString3() {
+ final LinearUnitValue value = LinearUnitValue.of(
+ Metric.METRE.withName(NameSymbol.EMPTY),
+ UncertainDouble.of(10, 0.24));
+
+ assertEquals("10.0 unnamed unit (= 10.0 m)", value.toString(false));
+ }
+
+ /**
+ * Tests converting a named UnitValue to a string.
+ *
+ * @since 2021-11-04
+ */
+ @Test
+ public void testValueToString4() {
+ final UnitValue value = UnitValue.of(BritishImperial.FAHRENHEIT, 80);
+
+ assertEquals("80.0 \u00B0F", value.toString());
+ }
+
+ /**
+ * Tests converting an unnamed UnitValue to a string.
+ *
+ * @since 2021-11-04
+ */
+ @Test
+ public void testValueToString5() {
+ final UnitValue value = UnitValue
+ .of(USCustomary.FAHRENHEIT.withName(NameSymbol.EMPTY), 50);
+
+ assertEquals("50.0 unnamed unit (= 283.15 K)", value.toString());
+ }
}