diff options
author | Adrien Hopkins <masterofnumbers17@gmail.com> | 2019-10-16 14:41:44 -0400 |
---|---|---|
committer | Adrien Hopkins <masterofnumbers17@gmail.com> | 2019-10-16 14:41:44 -0400 |
commit | 9eba2e72ecba1f33c73d358eb509f0a0816aa810 (patch) | |
tree | b5ad025a2fb2315b613516cea1fbc3e3ae8ac733 /src/org | |
parent | 45286c30f96f152f821098d878ede64ecbabe48a (diff) |
Added unit prefixes.
Diffstat (limited to 'src/org')
-rw-r--r-- | src/org/unitConverter/math/DecimalComparison.java | 67 | ||||
-rw-r--r-- | src/org/unitConverter/newUnits/LinearUnit.java | 29 | ||||
-rw-r--r-- | src/org/unitConverter/newUnits/UnitPrefix.java | 134 |
3 files changed, 229 insertions, 1 deletions
diff --git a/src/org/unitConverter/math/DecimalComparison.java b/src/org/unitConverter/math/DecimalComparison.java index 7cdbe5b..859e8da 100644 --- a/src/org/unitConverter/math/DecimalComparison.java +++ b/src/org/unitConverter/math/DecimalComparison.java @@ -16,6 +16,8 @@ */ package org.unitConverter.math; +import java.math.BigDecimal; + /** * A class that contains methods to compare float and double values. * @@ -44,6 +46,18 @@ public final class DecimalComparison { /** * Tests for equality of double values using {@link #DOUBLE_EPSILON}. + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon using {@link #equals(double, double, double)} (this does not make a violation of + * transitivity impossible, it just significantly reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code double} (this will make a violation of transitivity 100% impossible) + * </ol> * * @param a * first value to test @@ -52,6 +66,7 @@ public final class DecimalComparison { * @return whether they are equal * @since 2019-03-18 * @since v0.2.0 + * @see #hashCode(double) */ public static final boolean equals(final double a, final double b) { return DecimalComparison.equals(a, b, DOUBLE_EPSILON); @@ -60,6 +75,19 @@ public final class DecimalComparison { /** * Tests for double equality using a custom epsilon value. * + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon (this does not make a violation of transitivity impossible, it just significantly + * reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code double} (this will make a violation of transitivity 100% impossible) + * </ol> + * * @param a * first value to test * @param b @@ -77,6 +105,19 @@ public final class DecimalComparison { /** * Tests for equality of float values using {@link #FLOAT_EPSILON}. * + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon using {@link #equals(float, float, float)} (this does not make a violation of + * transitivity impossible, it just significantly reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code float} (this will make a violation of transitivity 100% impossible) + * </ol> + * * @param a * first value to test * @param b @@ -92,6 +133,19 @@ public final class DecimalComparison { /** * Tests for float equality using a custom epsilon value. * + * <p> + * <strong>WARNING: </strong>this method is not technically transitive. If a and b are off by slightly less than + * {@code epsilon * max(abs(a), abs(b))}, and b and c are off by slightly less than + * {@code epsilon * max(abs(b), abs(c))}, then equals(a, b) and equals(b, c) will both return true, but equals(a, c) + * will return false. However, this situation is very unlikely to ever happen in a real programming situation. + * <p> + * If this does become a concern, some ways to solve this problem: + * <ol> + * <li>Raise the value of epsilon (this does not make a violation of transitivity impossible, it just significantly + * reduces the chances of it happening) + * <li>Use {@link BigDecimal} instead of {@code float} (this will make a violation of transitivity 100% impossible) + * </ol> + * * @param a * first value to test * @param b @@ -106,6 +160,19 @@ public final class DecimalComparison { return Math.abs(a - b) <= epsilon * Math.max(Math.abs(a), Math.abs(b)); } + /** + * Takes the hash code of doubles. Values that are equal according to {@link #equals(double, double)} will have the + * same hash code. + * + * @param d + * double to hash + * @return hash code of double + * @since 2019-10-16 + */ + public static final int hash(final double d) { + return Float.hashCode((float) d); + } + // You may NOT get any DecimalComparison instances private DecimalComparison() { throw new AssertionError(); diff --git a/src/org/unitConverter/newUnits/LinearUnit.java b/src/org/unitConverter/newUnits/LinearUnit.java index 5a589b7..7600dad 100644 --- a/src/org/unitConverter/newUnits/LinearUnit.java +++ b/src/org/unitConverter/newUnits/LinearUnit.java @@ -29,6 +29,21 @@ import org.unitConverter.math.ObjectProduct; */ public final class LinearUnit extends AbstractUnit { /** + * 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 + * @return value expressed as a {@code LinearUnit} + * @since 2019-10-16 + */ + public static LinearUnit fromValue(final Unit unit, final double value) { + return new LinearUnit(unit.getBase(), unit.convertToBase(value)); + } + + /** * 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}. * @@ -129,7 +144,7 @@ public final class LinearUnit extends AbstractUnit { @Override public int hashCode() { - return Objects.hash(this.getBase(), this.getConversionFactor()); + return 31 * this.getBase().hashCode() + DecimalComparison.hash(this.getConversionFactor()); } /** @@ -258,4 +273,16 @@ public final class LinearUnit extends AbstractUnit { return Double.toString(this.conversionFactor) + " * " + this.getBase().toString(BaseUnit::getSymbol); } + /** + * Returns the result of applying {@code prefix} to this unit. + * + * @param prefix + * prefix to apply + * @return unit with prefix + * @since 2019-03-18 + * @since v0.2.0 + */ + public LinearUnit withPrefix(final UnitPrefix prefix) { + return this.times(prefix.getMultiplier()); + } } diff --git a/src/org/unitConverter/newUnits/UnitPrefix.java b/src/org/unitConverter/newUnits/UnitPrefix.java new file mode 100644 index 0000000..905ca19 --- /dev/null +++ b/src/org/unitConverter/newUnits/UnitPrefix.java @@ -0,0 +1,134 @@ +/** + * 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.newUnits; + +import org.unitConverter.math.DecimalComparison; + +/** + * A prefix that can be applied to a {@code LinearUnit} to multiply it by some value + * + * @author Adrien Hopkins + * @since 2019-10-16 + */ +public final class UnitPrefix { + /** + * The number that this prefix multiplies units by + * + * @since 2019-10-16 + */ + private final double multiplier; + + /** + * Creates the {@code DefaultUnitPrefix}. + * + * @param multiplier + * @since 2019-01-14 + * @since v0.2.0 + */ + private UnitPrefix(final double multiplier) { + this.multiplier = multiplier; + } + + /** + * Divides this prefix by a scalar + * + * @param divisor + * number to divide by + * @return quotient of prefix and scalar + * @since 2019-10-16 + */ + public UnitPrefix dividedBy(final double divisor) { + return new UnitPrefix(this.getMultiplier() / divisor); + } + + /** + * Divides this prefix by {@code other}. + * + * @param other + * prefix to divide by + * @return quotient of prefixes + * @since 2019-04-13 + * @since v0.2.0 + */ + public UnitPrefix dividedBy(final UnitPrefix other) { + return new UnitPrefix(this.getMultiplier() / other.getMultiplier()); + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof UnitPrefix)) + return false; + final UnitPrefix other = (UnitPrefix) obj; + return DecimalComparison.equals(this.getMultiplier(), other.getMultiplier()); + } + + public double getMultiplier() { + return this.multiplier; + } + + @Override + public int hashCode() { + return DecimalComparison.hash(this.getMultiplier()); + } + + /** + * Multiplies this prefix by a scalar + * + * @param multiplicand + * number to multiply by + * @return product of prefix and scalar + * @since 2019-10-16 + */ + public UnitPrefix times(final double multiplicand) { + return new UnitPrefix(this.getMultiplier() * multiplicand); + } + + /** + * Multiplies this prefix by {@code other}. + * + * @param other + * prefix to multiply by + * @return product of prefixes + * @since 2019-04-13 + * @since v0.2.0 + */ + public UnitPrefix times(final UnitPrefix other) { + return new UnitPrefix(this.getMultiplier() * other.getMultiplier()); + } + + /** + * Raises this prefix to an exponent. + * + * @param exponent + * exponent to raise to + * @return result of exponentiation. + * @since 2019-04-13 + * @since v0.2.0 + */ + public UnitPrefix toExponent(final double exponent) { + return new UnitPrefix(Math.pow(this.getMultiplier(), exponent)); + } + + @Override + public String toString() { + return String.format("Unit prefix equal to %s", this.multiplier); + } +} |