summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnits/math/UncertainDouble.java
diff options
context:
space:
mode:
authorAdrien Hopkins <ahopk127@my.yorku.ca>2021-08-26 15:09:23 -0400
committerAdrien Hopkins <ahopk127@my.yorku.ca>2021-08-26 15:09:23 -0400
commit816f744169d1ecdb689aba27cb396ab452fdc3fe (patch)
tree1eed1edbbf6f3131dfb6a26c1480d023e44f6c51 /src/main/java/sevenUnits/math/UncertainDouble.java
parent236b497f516694929b9fe409508a7cce21ca9e6e (diff)
parent75a5a1a2a40b0eb4361d6fc046eb8918ef6f5292 (diff)
Merge branch 'new-documentation-0.3.1' into develop
Diffstat (limited to 'src/main/java/sevenUnits/math/UncertainDouble.java')
-rw-r--r--src/main/java/sevenUnits/math/UncertainDouble.java419
1 files changed, 0 insertions, 419 deletions
diff --git a/src/main/java/sevenUnits/math/UncertainDouble.java b/src/main/java/sevenUnits/math/UncertainDouble.java
deleted file mode 100644
index b81bb79..0000000
--- a/src/main/java/sevenUnits/math/UncertainDouble.java
+++ /dev/null
@@ -1,419 +0,0 @@
-/**
- * Copyright (C) 2020 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 sevenUnits.math;
-
-import java.math.BigDecimal;
-import java.math.RoundingMode;
-import java.util.Objects;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A double with an associated uncertainty value. For example, 3.2 ± 0.2.
- * <p>
- * All methods in this class throw a NullPointerException if any of their
- * arguments is null.
- *
- * @since 2020-09-07
- */
-public final class UncertainDouble implements Comparable<UncertainDouble> {
- /**
- * The exact value 0
- */
- public static final UncertainDouble ZERO = UncertainDouble.of(0, 0);
-
- /**
- * A regular expression that can recognize toString forms
- */
- private static final Pattern TO_STRING = Pattern
- .compile("([a-zA-Z_0-9\\.\\,]+)" // a number
- // optional "± [number]"
- + "(?:\\s*(?:±|\\+-)\\s*([a-zA-Z_0-9\\.\\,]+))?");
-
- /**
- * Parses a string in the form of {@link UncertainDouble#toString(boolean)}
- * and returns the corresponding {@code UncertainDouble} instance.
- * <p>
- * This method allows some alternative forms of the string representation,
- * such as using "+-" instead of "±".
- *
- * @param s string to parse
- * @return {@code UncertainDouble} instance
- * @throws IllegalArgumentException if the string is invalid
- * @since 2020-09-07
- */
- public static final UncertainDouble fromString(String s) {
- Objects.requireNonNull(s, "s may not be null");
- final Matcher matcher = TO_STRING.matcher(s);
-
- double value, uncertainty;
- try {
- value = Double.parseDouble(matcher.group(1));
- } catch (IllegalStateException | NumberFormatException e) {
- throw new IllegalArgumentException(
- "String " + s + " not in correct format.");
- }
-
- final String uncertaintyString = matcher.group(2);
- if (uncertaintyString == null) {
- uncertainty = 0;
- } else {
- try {
- uncertainty = Double.parseDouble(uncertaintyString);
- } catch (final NumberFormatException e) {
- throw new IllegalArgumentException(
- "String " + s + " not in correct format.");
- }
- }
-
- return UncertainDouble.of(value, uncertainty);
- }
-
- /**
- * Gets an {@code UncertainDouble} from its value and <b>absolute</b>
- * uncertainty.
- *
- * @since 2020-09-07
- */
- public static final UncertainDouble of(double value, double uncertainty) {
- return new UncertainDouble(value, uncertainty);
- }
-
- /**
- * Gets an {@code UncertainDouble} from its value and <b>relative</b>
- * uncertainty.
- *
- * @since 2020-09-07
- */
- public static final UncertainDouble ofRelative(double value,
- double relativeUncertainty) {
- return new UncertainDouble(value, value * relativeUncertainty);
- }
-
- private final double value;
-
- private final double uncertainty;
-
- /**
- * @param value
- * @param uncertainty
- * @since 2020-09-07
- */
- private UncertainDouble(double value, double uncertainty) {
- this.value = value;
- // uncertainty should only ever be positive
- this.uncertainty = Math.abs(uncertainty);
- }
-
- /**
- * Compares this {@code UncertainDouble} with another
- * {@code UncertainDouble}.
- * <p>
- * This method only compares the values, not the uncertainties. So 3.1 ± 0.5
- * is considered less than 3.2 ± 0.5, even though they are equivalent.
- * <p>
- * <b>Note:</b> The natural ordering of this class is inconsistent with
- * equals. Specifically, if two {@code UncertainDouble} instances {@code a}
- * and {@code b} have the same value but different uncertainties,
- * {@code a.compareTo(b)} will return 0 but {@code a.equals(b)} will return
- * {@code false}.
- */
- @Override
- public final int compareTo(UncertainDouble o) {
- return Double.compare(this.value, o.value);
- }
-
- /**
- * Returns the quotient of {@code this} and {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble dividedBy(UncertainDouble other) {
- Objects.requireNonNull(other, "other may not be null");
- return UncertainDouble.ofRelative(this.value / other.value, Math
- .hypot(this.relativeUncertainty(), other.relativeUncertainty()));
- }
-
- /**
- * Returns the quotient of {@code this} and the exact value {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble dividedByExact(double other) {
- return UncertainDouble.of(this.value / other, this.uncertainty / other);
- }
-
- @Override
- public final boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (!(obj instanceof UncertainDouble))
- return false;
- final UncertainDouble other = (UncertainDouble) obj;
- if (Double.compare(this.value, other.value) != 0)
- return false;
- if (Double.compare(this.uncertainty, other.uncertainty) != 0)
- return false;
- return true;
- }
-
- /**
- * @param other another {@code UncertainDouble}
- * @return true iff this and {@code other} are within each other's
- * uncertainty range.
- * @since 2020-09-07
- */
- public final boolean equivalent(UncertainDouble other) {
- Objects.requireNonNull(other, "other may not be null");
- return Math.abs(this.value - other.value) <= Math.min(this.uncertainty,
- other.uncertainty);
- }
-
- /**
- * Gets the preferred scale for rounding a value for toString.
- *
- * @since 2020-09-07
- */
- private final int getDisplayScale() {
- // 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.
- final BigDecimal bigUncertainty = BigDecimal.valueOf(this.uncertainty);
-
- // the scale that will give the uncertainty two decimal places
- final int twoDecimalPlacesScale = bigUncertainty.scale()
- - bigUncertainty.precision() + 2;
- final BigDecimal roundedUncertainty = bigUncertainty
- .setScale(twoDecimalPlacesScale, RoundingMode.HALF_EVEN);
-
- if (roundedUncertainty.unscaledValue().intValue() >= 20)
- return twoDecimalPlacesScale - 1; // one decimal place
- else
- return twoDecimalPlacesScale;
- }
-
- @Override
- public final int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + Double.hashCode(this.value);
- result = prime * result + Double.hashCode(this.uncertainty);
- return result;
- }
-
- /**
- * @return true iff the value has no uncertainty
- *
- * @since 2020-09-07
- */
- public final boolean isExact() {
- return this.uncertainty == 0;
- }
-
- /**
- * Returns the difference of {@code this} and {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble minus(UncertainDouble other) {
- Objects.requireNonNull(other, "other may not be null");
- return UncertainDouble.of(this.value - other.value,
- Math.hypot(this.uncertainty, other.uncertainty));
- }
-
- /**
- * Returns the difference of {@code this} and the exact value {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble minusExact(double other) {
- return UncertainDouble.of(this.value - other, this.uncertainty);
- }
-
- /**
- * Returns the sum of {@code this} and {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble plus(UncertainDouble other) {
- Objects.requireNonNull(other, "other may not be null");
- return UncertainDouble.of(this.value + other.value,
- Math.hypot(this.uncertainty, other.uncertainty));
- }
-
- /**
- * Returns the sum of {@code this} and the exact value {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble plusExact(double other) {
- return UncertainDouble.of(this.value + other, this.uncertainty);
- }
-
- /**
- * @return relative uncertainty
- * @since 2020-09-07
- */
- public final double relativeUncertainty() {
- return this.uncertainty / this.value;
- }
-
- /**
- * Returns the product of {@code this} and {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble times(UncertainDouble other) {
- Objects.requireNonNull(other, "other may not be null");
- return UncertainDouble.ofRelative(this.value * other.value, Math
- .hypot(this.relativeUncertainty(), other.relativeUncertainty()));
- }
-
- /**
- * Returns the product of {@code this} and the exact value {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble timesExact(double other) {
- return UncertainDouble.of(this.value * other, this.uncertainty * other);
- }
-
- /**
- * Returns the result of {@code this} raised to the exponent {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble toExponent(UncertainDouble other) {
- Objects.requireNonNull(other, "other may not be null");
-
- final double result = Math.pow(this.value, other.value);
- final double relativeUncertainty = Math.hypot(
- other.value * this.relativeUncertainty(),
- Math.log(this.value) * other.uncertainty);
-
- return UncertainDouble.ofRelative(result, relativeUncertainty);
- }
-
- /**
- * Returns the result of {@code this} raised the exact exponent
- * {@code other}.
- *
- * @since 2020-09-07
- */
- public final UncertainDouble toExponentExact(double other) {
- return UncertainDouble.ofRelative(Math.pow(this.value, other),
- this.relativeUncertainty() * other);
- }
-
- /**
- * Returns a string representation of this {@code UncertainDouble}.
- * <p>
- * This method returns the same value as {@link #toString(boolean)}, but
- * {@code showUncertainty} is true if and only if the uncertainty is
- * non-zero.
- *
- * <p>
- * Examples:
- *
- * <pre>
- * UncertainDouble.of(3.27, 0.22).toString() = "3.3 ± 0.2"
- * UncertainDouble.of(3.27, 0.13).toString() = "3.27 ± 0.13"
- * UncertainDouble.of(-5.01, 0).toString() = "-5.01"
- * </pre>
- *
- * @since 2020-09-07
- */
- @Override
- public final String toString() {
- return this.toString(!this.isExact());
- }
-
- /**
- * Returns a string representation of this {@code UncertainDouble}.
- * <p>
- * If {@code showUncertainty} is true, the string will be of the form "VALUE
- * ± UNCERTAINTY", and if it is false the string will be of the form "VALUE"
- * <p>
- * VALUE represents a string representation of this {@code UncertainDouble}'s
- * value. If the uncertainty is non-zero, the string will be rounded to the
- * same precision as the uncertainty, otherwise it will not be rounded. The
- * string is still rounded if {@code showUncertainty} is false.<br>
- * UNCERTAINTY represents a string representation of this
- * {@code UncertainDouble}'s uncertainty. If the uncertainty ends in 1X
- * (where X represents any digit) it will be rounded to two significant
- * digits otherwise it will be rounded to one significant digit.
- * <p>
- * Examples:
- *
- * <pre>
- * UncertainDouble.of(3.27, 0.22).toString(false) = "3.3"
- * UncertainDouble.of(3.27, 0.22).toString(true) = "3.3 ± 0.2"
- * UncertainDouble.of(3.27, 0.13).toString(false) = "3.27"
- * UncertainDouble.of(3.27, 0.13).toString(true) = "3.27 ± 0.13"
- * UncertainDouble.of(-5.01, 0).toString(false) = "-5.01"
- * UncertainDouble.of(-5.01, 0).toString(true) = "-5.01 ± 0.0"
- * </pre>
- *
- * @since 2020-09-07
- */
- public final String toString(boolean showUncertainty) {
- String valueString, uncertaintyString;
-
- // generate the string representation of value and uncertainty
- if (this.isExact()) {
- uncertaintyString = "0.0";
- valueString = Double.toString(this.value);
-
- } else {
- // round the value and uncertainty according to getDisplayScale()
- final BigDecimal bigValue = BigDecimal.valueOf(this.value);
- final BigDecimal bigUncertainty = BigDecimal.valueOf(this.uncertainty);
-
- final int displayScale = this.getDisplayScale();
- final BigDecimal roundedUncertainty = bigUncertainty
- .setScale(displayScale, RoundingMode.HALF_EVEN);
- final BigDecimal roundedValue = bigValue.setScale(displayScale,
- RoundingMode.HALF_EVEN);
-
- valueString = roundedValue.toString();
- uncertaintyString = roundedUncertainty.toString();
- }
-
- // return "value" or "value ± uncertainty" depending on showUncertainty
- return valueString + (showUncertainty ? " ± " + uncertaintyString : "");
- }
-
- /**
- * @return absolute uncertainty
- * @since 2020-09-07
- */
- public final double uncertainty() {
- return this.uncertainty;
- }
-
- /**
- * @return value without uncertainty
- * @since 2020-09-07
- */
- public final double value() {
- return this.value;
- }
-}