summaryrefslogtreecommitdiff
path: root/src/main/java/sevenUnits/utils/UncertainDouble.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/sevenUnits/utils/UncertainDouble.java')
-rw-r--r--src/main/java/sevenUnits/utils/UncertainDouble.java251
1 files changed, 157 insertions, 94 deletions
diff --git a/src/main/java/sevenUnits/utils/UncertainDouble.java b/src/main/java/sevenUnits/utils/UncertainDouble.java
index 66d8103..24ada20 100644
--- a/src/main/java/sevenUnits/utils/UncertainDouble.java
+++ b/src/main/java/sevenUnits/utils/UncertainDouble.java
@@ -1,5 +1,5 @@
/**
- * Copyright (C) 2020 Adrien Hopkins
+ * Copyright (C) 2020-2022, 2024, 2025 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
@@ -19,7 +19,6 @@ package sevenUnits.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Objects;
-import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
@@ -29,56 +28,59 @@ import java.util.regex.Pattern;
* arguments is null.
*
* @since 2020-09-07
+ * @since v0.3.0
*/
public final class UncertainDouble implements Comparable<UncertainDouble> {
- /**
- * The exact value 0
- */
+ /** The exact value 0 */
public static final UncertainDouble ZERO = UncertainDouble.of(0, 0);
static final String NUMBER_REGEX = "(\\d+(?:[\\.,]\\d+))";
- /**
- * A regular expression that can recognize toString forms
- */
+ /** A regular expression that can recognize toString forms */
static final Pattern TO_STRING = Pattern.compile(NUMBER_REGEX
- // optional "� [number]"
- + "(?:\\s*(?:�|\\+-)\\s*" + NUMBER_REGEX + ")?");
+ // optional "± [number]"
+ + "(?:\\s*(?:±|\\+-)\\s*" + NUMBER_REGEX + ")?");
/**
* Gets an UncertainDouble from a double string. The uncertainty of the
* double will be one of the lowest decimal place of the number. For example,
- * "12345.678" will become 12345.678 � 0.001.
- *
+ * "12345.678" will become 12345.678 ± 0.001.
+ *
+ * @param s string to parse
+ * @return parsed {@code UncertainDouble}
+ *
* @throws NumberFormatException if the argument is not a number
*
* @since 2022-04-18
+ * @since v0.4.0
*/
- public static final UncertainDouble fromRoundedString(String s) {
- final BigDecimal value = new BigDecimal(s);
- final double uncertainty = Math.pow(10, -value.scale());
+ public static UncertainDouble fromRoundedString(String s) {
+ final var value = new BigDecimal(s);
+ final var uncertainty = Math.pow(10, -value.scale());
return UncertainDouble.of(value.doubleValue(), uncertainty);
}
/**
- * Parses a string in the form of {@link UncertainDouble#toString(boolean)}
- * and returns the corresponding {@code UncertainDouble} instance.
+ * Parses a string in the form of
+ * {@link UncertainDouble#toString(boolean, RoundingMode)} and returns the
+ * corresponding {@code UncertainDouble} instance.
* <p>
* This method allows some alternative forms of the string representation,
- * such as using "+-" instead of "�".
- *
+ * 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
+ * @since v0.3.0
*/
- public static final UncertainDouble fromString(String s) {
+ public static UncertainDouble fromString(String s) {
Objects.requireNonNull(s, "s may not be null");
- final Matcher matcher = TO_STRING.matcher(s);
+ final var matcher = TO_STRING.matcher(s);
if (!matcher.matches())
throw new IllegalArgumentException(
- "Could not parse stirng \"" + s + "\".");
+ "Could not parse string \"" + s + "\".");
double value, uncertainty;
try {
@@ -88,7 +90,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
"String " + s + " not in correct format.");
}
- final String uncertaintyString = matcher.group(2);
+ final var uncertaintyString = matcher.group(2);
if (uncertaintyString == null) {
uncertainty = 0;
} else {
@@ -106,20 +108,32 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Gets an {@code UncertainDouble} from its value and <b>absolute</b>
* uncertainty.
- *
+ *
+ * @param value double's value
+ * @param uncertainty double's uncertainty (non-negative)
+ * @return {@code UncertainDouble} instance with these parameters
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public static final UncertainDouble of(double value, double uncertainty) {
+ public static UncertainDouble of(double value, double uncertainty) {
return new UncertainDouble(value, uncertainty);
}
/**
* Gets an {@code UncertainDouble} from its value and <b>relative</b>
* uncertainty.
- *
+ *
+ * @param value double's value
+ * @param relativeUncertainty double's uncertainty (non-negative); the
+ * absolute uncertainty is equal to this value
+ * multiplied by {@code relativeUncertainty}
+ * @return {@code UncertainDouble} instance with these parameters
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public static final UncertainDouble ofRelative(double value,
+ public static UncertainDouble ofRelative(double value,
double relativeUncertainty) {
return new UncertainDouble(value, value * relativeUncertainty);
}
@@ -132,6 +146,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
* @param value
* @param uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
private UncertainDouble(double value, double uncertainty) {
this.value = value;
@@ -153,16 +168,20 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
* {@code false}.
*/
@Override
- public final int compareTo(UncertainDouble o) {
+ public int compareTo(UncertainDouble o) {
return Double.compare(this.value, o.value);
}
/**
* Returns the quotient of {@code this} and {@code other}.
- *
+ *
+ * @param other number to divide by
+ * @return quotient
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble dividedBy(UncertainDouble other) {
+ public 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()));
@@ -170,23 +189,26 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Returns the quotient of {@code this} and the exact value {@code other}.
- *
+ *
+ * @param other number to divide by
+ * @return quotient
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble dividedByExact(double other) {
+ public UncertainDouble dividedByExact(double other) {
return UncertainDouble.of(this.value / other, this.uncertainty / other);
}
@Override
- public final boolean equals(Object obj) {
+ public 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)
+ final var other = (UncertainDouble) obj;
+ if ((Double.compare(this.value, other.value) != 0)
+ || (Double.compare(this.uncertainty, other.uncertainty) != 0))
return false;
return true;
}
@@ -196,8 +218,9 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
* @return true iff this and {@code other} are within each other's
* uncertainty range.
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final boolean equivalent(UncertainDouble other) {
+ public 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);
@@ -205,10 +228,11 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Gets the preferred scale for rounding a value for toString.
- *
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- private final int getDisplayScale() {
+ private int getDisplayScale() {
// round based on uncertainty
// if uncertainty starts with 1 (ignoring zeroes and the decimal
// point), rounds
@@ -216,24 +240,23 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
// 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);
+ final var bigUncertainty = BigDecimal.valueOf(this.uncertainty);
// the scale that will give the uncertainty two decimal places
- final int twoDecimalPlacesScale = bigUncertainty.scale()
+ final var twoDecimalPlacesScale = bigUncertainty.scale()
- bigUncertainty.precision() + 2;
- final BigDecimal roundedUncertainty = bigUncertainty
+ final var roundedUncertainty = bigUncertainty
.setScale(twoDecimalPlacesScale, RoundingMode.HALF_EVEN);
if (roundedUncertainty.unscaledValue().intValue() >= 20)
return twoDecimalPlacesScale - 1; // one decimal place
- else
- return twoDecimalPlacesScale;
+ return twoDecimalPlacesScale;
}
@Override
- public final int hashCode() {
- final int prime = 31;
- int result = 1;
+ public int hashCode() {
+ final var prime = 31;
+ var result = 1;
result = prime * result + Double.hashCode(this.value);
result = prime * result + Double.hashCode(this.uncertainty);
return result;
@@ -241,19 +264,24 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* @return true iff the value has no uncertainty
- *
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final boolean isExact() {
+ public boolean isExact() {
return this.uncertainty == 0;
}
/**
* Returns the difference of {@code this} and {@code other}.
- *
+ *
+ * @param other number to subtract
+ * @return result of subtraction
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble minus(UncertainDouble other) {
+ public 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));
@@ -261,19 +289,27 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Returns the difference of {@code this} and the exact value {@code other}.
- *
+ *
+ * @param other number to subtract
+ * @return result of subtraction
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble minusExact(double other) {
+ public UncertainDouble minusExact(double other) {
return UncertainDouble.of(this.value - other, this.uncertainty);
}
/**
* Returns the sum of {@code this} and {@code other}.
- *
+ *
+ * @param other number to add
+ * @return result of addition
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble plus(UncertainDouble other) {
+ public 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));
@@ -281,27 +317,36 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Returns the sum of {@code this} and the exact value {@code other}.
- *
+ *
+ * @param other number to add
+ * @return result of addition
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble plusExact(double other) {
+ public UncertainDouble plusExact(double other) {
return UncertainDouble.of(this.value + other, this.uncertainty);
}
/**
* @return relative uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final double relativeUncertainty() {
+ public double relativeUncertainty() {
return this.uncertainty / this.value;
}
/**
* Returns the product of {@code this} and {@code other}.
- *
+ *
+ * @param other number to multiply
+ * @return product
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble times(UncertainDouble other) {
+ public 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()));
@@ -309,23 +354,31 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Returns the product of {@code this} and the exact value {@code other}.
- *
+ *
+ * @param other number to multiply
+ * @return product
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble timesExact(double other) {
+ public 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}.
- *
+ *
+ * @param other exponent
+ * @return result of exponentation
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble toExponent(UncertainDouble other) {
+ public 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(
+ final var result = Math.pow(this.value, other.value);
+ final var relativeUncertainty = Math.hypot(
other.value * this.relativeUncertainty(),
Math.log(this.value) * other.uncertainty);
@@ -335,10 +388,14 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* Returns the result of {@code this} raised the exact exponent
* {@code other}.
- *
+ *
+ * @param other exponent
+ * @return result of exponentation
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final UncertainDouble toExponentExact(double other) {
+ public UncertainDouble toExponentExact(double other) {
return UncertainDouble.ofRelative(Math.pow(this.value, other),
this.relativeUncertainty() * other);
}
@@ -346,23 +403,24 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
/**
* 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.
- *
+ * This method returns the same value as
+ * {@link #toString(boolean, RoundingMode)}, 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
+ * @since v0.3.0
*/
@Override
- public final String toString() {
+ public String toString() {
return this.toString(!this.isExact(), RoundingMode.HALF_EVEN);
}
@@ -370,7 +428,7 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
* 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"
+ * ± 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
@@ -382,20 +440,24 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
* 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.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(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"
+ * UncertainDouble.of(-5.01, 0).toString(true) = "-5.01 ± 0.0"
* </pre>
- *
+ *
+ * @param showUncertainty uncertainty is only shown if this parameter is true
+ * @param roundingMode how to round values
+ * @return string representation of this {@code UncertainDouble}
+ *
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final String toString(boolean showUncertainty,
- RoundingMode roundingMode) {
+ public String toString(boolean showUncertainty, RoundingMode roundingMode) {
String valueString, uncertaintyString;
// generate the string representation of value and uncertainty
@@ -405,36 +467,37 @@ public final class UncertainDouble implements Comparable<UncertainDouble> {
} else {
// round the value and uncertainty according to getDisplayScale()
- final BigDecimal bigValue = BigDecimal.valueOf(this.value);
- final BigDecimal bigUncertainty = BigDecimal.valueOf(this.uncertainty);
+ final var bigValue = BigDecimal.valueOf(this.value);
+ final var bigUncertainty = BigDecimal.valueOf(this.uncertainty);
- final int displayScale = this.getDisplayScale();
- final BigDecimal roundedUncertainty = bigUncertainty
- .setScale(displayScale, roundingMode);
- final BigDecimal roundedValue = bigValue.setScale(displayScale,
+ final var displayScale = this.getDisplayScale();
+ final var roundedUncertainty = bigUncertainty.setScale(displayScale,
roundingMode);
+ final var roundedValue = bigValue.setScale(displayScale, roundingMode);
valueString = roundedValue.toString();
uncertaintyString = roundedUncertainty.toString();
}
- // return "value" or "value � uncertainty" depending on showUncertainty
- return valueString + (showUncertainty ? " � " + uncertaintyString : "");
+ // return "value" or "value ± uncertainty" depending on showUncertainty
+ return valueString + (showUncertainty ? " ± " + uncertaintyString : "");
}
/**
* @return absolute uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final double uncertainty() {
+ public double uncertainty() {
return this.uncertainty;
}
/**
* @return value without uncertainty
* @since 2020-09-07
+ * @since v0.3.0
*/
- public final double value() {
+ public double value() {
return this.value;
}
}