From 2b70ebf41d2bd4707a927f9d316ae0b0da29ea86 Mon Sep 17 00:00:00 2001
From: theshoeshiner <2922868+theshoeshiner@users.noreply.github.com>
Date: Mon, 14 Aug 2023 10:45:48 -0400
Subject: [PATCH 1/2] countSignificantFigures method
---
.../commons/lang3/math/NumberUtils.java | 203 +++++++++++++++++-
.../commons/lang3/math/NumberUtilsTest.java | 90 ++++++++
2 files changed, 292 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
index 1059b4cd10c..f1ec76ed9fa 100644
--- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
+++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
@@ -22,6 +22,7 @@
import java.math.RoundingMode;
import java.util.Objects;
+import org.apache.commons.lang3.CharUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
@@ -32,6 +33,14 @@
*/
public class NumberUtils {
+ /** Reusable char constant for zero. */
+ public static final char CHAR_ZERO = '0';
+ /** Reusable char constant for decimal separator character period. */
+ public static final char CHAR_DECIMAL_PERIOD = '.';
+ /** Reusable char constant for decimal separator character comma. */
+ public static final char CHAR_DECIMAL_COMMA = ',';
+ /** Reusable char constant for exponent character (lowercase e). */
+ public static final char CHAR_EXPONENT = 'e';
/** Reusable Long constant for zero. */
public static final Long LONG_ZERO = Long.valueOf(0L);
/** Reusable Long constant for one. */
@@ -1847,4 +1856,196 @@ public static int compare(final short x, final short y) {
public static int compare(final byte x, final byte y) {
return x - y;
}
-}
+
+ /**
+ * Counts the number of significant figures within a decimal value string.
+ * {@link org.apache.commons.lang3.math.NumberUtils#countSignificantFigures(String, char)}
+ *
+ * @param decimalNumber The decimal number string. Must be numeric digits with optional decimal
+ * and optional integer exponential suffix
+ * @return The number of significant figures in the string
+ */
+ public static int countSignificantFigures(String decimalNumber) {
+ return countSignificantFigures(decimalNumber, CHAR_DECIMAL_PERIOD);
+ }
+
+ /**
+ * Counts the number of significant figures within a decimal value string. This method must
+ * accept a string because significant figures can only be inferred from the a user provided
+ * representation, and not from a binary numerical value. This logic is useful/necessary when
+ * working with measured values where it is critical to retain the implied uncertainty in the
+ * initial value for use in formatting after calculations.
+ * The rules that are followed, outlined below, are widely accepted standard conventions,
+ * discussed in many texts [1][2]. Note: Zero values are an exceptional case that is
+ * unfortunately not often discussed or handled. This implementation aims to retain the implied
+ * uncertainty and precision in a zero value such that further mathematical operations can
+ * continue to report it. The goal of this logic is to allow zero values to be reported with
+ * significant figure counts that match measurements in the same dataset. i.e. if the values 2.1
+ * and 0.0 are measured on the same apparatus and reported in the same dataset, we should be
+ * able to convey that they both have 2 significant figures.
+ * Note: Rules 1-6 deal with the non-exponent portion of the string, and by rule apply
+ * only to characters prior to the optional exponent character ('e'). Rule 7 covers the
+ * exponential portion.
+ * 1) All nonzero digits are always significant.
+ * 2) Zeros that appear between other nonzero digits are called "middle zeros", and are always
+ * significant.
+ * 3) Zeros that appear in front of all of the nonzero digits are called "leading zeros", and
+ * are never significant.
+ * 4) Zeros that appear after all nonzero digits are called "trailing zeros". In a value with a
+ * decimal point they are significant.
+ * 5) "Trailing zeros" in a value that does not contain a decimal are not significant.
+ * 6) Zero values are strings that only contain zeros and an optional decimal. In these values,
+ * the first leading zero is considered to be significant, and all trailing zeros are handled as
+ * if the first were nonzero (See Examples Below).
+ *
+ *
+ * String |
+ * Count |
+ * Reason |
+ * Note |
+ *
+ *
+ * 0.00 |
+ * 3 |
+ * The first whole zero is significant (Rule 6), and the two trailing zeros are significant
+ * (Rule 4) |
+ * |
+ *
+ *
+ * 0e20 |
+ * 1 |
+ * The first whole zero is significant (Rule 6) and the exponent is not (Rule 7) |
+ * |
+ *
+ *
+ * 0000 |
+ * 1 |
+ * The first whole zero is significant (Rule 6) and the last three are not significant (Rule
+ * 5) |
+ * This is an extreme case, documented here for clarity, uncommon in practice |
+ *
+ *
+ * 00.0 |
+ * 3 |
+ * First whole zero is significant (Rule 6) and the last two are also significant (Rule
+ * | | 4)
+ *
+ *
+ * 0000. |
+ * 4 |
+ * First whole zero is significant (Rule 6) and the last three are also significant (Rule
+ * | | 4)
+ *
+ *
+ * 7) Integers present after an optional 'e' character are the "exponent". These may only be
+ * decimal digit characters, and are never significant.
+ *
+ * [1] Measurement
+ * and Significant Figures [2]
+ * Significant
+ * Figures
+ *
+ * @param decimalNumber The decimal number string. Must be numeric digits with optional decimal
+ * and optional integer exponential suffix
+ * @param decimalSeparator the decimal separator character to use
+ * @return The number of significant figures in the string
+ */
+ public static int countSignificantFigures(String decimalNumber, char decimalSeparator) {
+ if (decimalNumber.length() == 0) {
+ throw new IllegalArgumentException("Decimal Number string was empty");
+ }
+ if (CharUtils.isAsciiNumeric(decimalSeparator)) {
+ throw new IllegalArgumentException("Decimal Separator cannot be numeric");
+ }
+ if (decimalSeparator == CHAR_EXPONENT) {
+ throw new IllegalArgumentException("Decimal Separator cannot be exponent character 'e'");
+ }
+ // track current part
+ boolean foundNonZero = false;
+ boolean rightSide = false;
+ int exponentIndex = -1;
+ // track count of zeros that are potential sigfigs
+ int leadingZeros = 0;
+ int middleZeros = 0;
+ //track known sigfigs
+ int sigFigs = 0;
+ for (int i = 0; i < decimalNumber.length(); i++) {
+ char c = decimalNumber.charAt(i);
+ if (c == CHAR_ZERO) {
+ if (!rightSide) {
+ if (foundNonZero) {
+ // whole trailing zeros MIGHT be middle zeros (Rule 2)
+ middleZeros++;
+ } else {
+ //whole leading zeros might be middle zeros (Rule 6 / Rule 3)
+ leadingZeros++;
+ }
+ } else {
+ if (foundNonZero) {
+ //decimal trailing zeros are always significant (Rule 4)
+ sigFigs++;
+ } else {
+ // decimal leading zeros might be middle zeros (Rule 6 / Rule 2)
+ middleZeros++;
+ }
+ }
+ } else if (c == decimalSeparator) {
+ rightSide = true;
+ // if a decimal is present, all whole trailing zeros are middle zeros and are
+ // significant significant (Rule 4)
+ sigFigs += middleZeros;
+ middleZeros = 0;
+ } else if (c == CHAR_EXPONENT) {
+ // exponent is not significant and ends the parsing of sigfigs
+ exponentIndex = i;
+ if (exponentIndex == 0) {
+ throw new IllegalArgumentException("Decimal part was empty");
+ }
+ break;
+ } else if (CharUtils.isAsciiNumeric(c)) {
+ // non zero digits are ALWAYS significant (Rule 1)
+ sigFigs++;
+ if (!foundNonZero) {
+ // this was the first nonzero
+ foundNonZero = true;
+ // reset the zero count because the middle zeros were actually leading zeros
+ middleZeros = 0;
+ } else {
+ // zeros between nonzeros are middle zeros and are always significant (Rule 2)
+ sigFigs += middleZeros;
+ middleZeros = 0;
+ }
+ } else {
+ throw new IllegalArgumentException("Illegal character '" + c + "' at index " + i);
+ }
+ }
+ // any remaining zeros were trailing and are not significant (Rule 5)
+
+ // if we found no nonzeros, then this is a zero value measurement.
+ if (!foundNonZero) {
+ sigFigs += middleZeros;
+ if (rightSide) {
+ sigFigs += leadingZeros;
+ } else {
+ //only one leading zero is significant, others are trailing
+ sigFigs += 1;
+ }
+ }
+
+ if (exponentIndex > -1) {
+ // Exponent is numeric digits only and not significant (Rule 7)
+ if (exponentIndex + 1 == decimalNumber.length()) {
+ throw new IllegalArgumentException("Exponent part was empty");
+ }
+ for (int i = exponentIndex + 1; i < decimalNumber.length(); i++) {
+ char c = decimalNumber.charAt(i);
+ if (!CharUtils.isAsciiNumeric(c)) {
+ throw new IllegalArgumentException("Illegal character '" + c + "' at index " + i);
+ }
+ }
+ }
+ return sigFigs;
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
index 2a01fab163c..78aa724c464 100644
--- a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
@@ -1743,4 +1743,94 @@ public void testToShortStringI() {
assertEquals(12345, NumberUtils.toShort("12345", (short) 5), "toShort(String, short) 1 failed");
assertEquals(5, NumberUtils.toShort("1234.5", (short) 5), "toShort(String, short) 2 failed");
}
+
+ @Test
+ public void testCountSignificantFiguresSeparator() {
+ assertEquals(5, NumberUtils.countSignificantFigures("113.33", NumberUtils.CHAR_DECIMAL_PERIOD));
+ assertEquals(5, NumberUtils.countSignificantFigures("113,33", NumberUtils.CHAR_DECIMAL_COMMA));
+ assertEquals(5, NumberUtils.countSignificantFigures("113|33", '|'));
+ assertEquals(5, NumberUtils.countSignificantFigures("113 33", ' '));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e1", '1'));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e1", 'e'));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e1", '0'));
+ }
+
+ @Test
+ public void testCountSignificantFiguresNonZeroDigitsRule1() {
+ assertEquals(1, NumberUtils.countSignificantFigures("1"));
+ assertEquals(1, NumberUtils.countSignificantFigures("1."));
+ assertEquals(1, NumberUtils.countSignificantFigures("1e2"));
+ assertEquals(4, NumberUtils.countSignificantFigures("123.4"));
+ assertEquals(5, NumberUtils.countSignificantFigures("123.44"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresMiddleZerosRule2() {
+ assertEquals(5, NumberUtils.countSignificantFigures("10001"));
+ assertEquals(5, NumberUtils.countSignificantFigures("100.44"));
+ assertEquals(3, NumberUtils.countSignificantFigures("101"));
+ assertEquals(3, NumberUtils.countSignificantFigures("1.01"));
+ assertEquals(3, NumberUtils.countSignificantFigures("101e2"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresLeadingZerosRule3() {
+ assertEquals(5, NumberUtils.countSignificantFigures("0010001"));
+ assertEquals(5, NumberUtils.countSignificantFigures("00100.44"));
+ assertEquals(3, NumberUtils.countSignificantFigures("0000101"));
+ assertEquals(3, NumberUtils.countSignificantFigures("01.01"));
+ assertEquals(3, NumberUtils.countSignificantFigures("0000000101e2"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresTrailingZerosRule4() {
+ assertEquals(5, NumberUtils.countSignificantFigures("1.4400"));
+ assertEquals(9, NumberUtils.countSignificantFigures("101.430000"));
+ assertEquals(2, NumberUtils.countSignificantFigures("1.0e1"));
+ assertEquals(4, NumberUtils.countSignificantFigures("1.000e3"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresTrailingZerosRule5() {
+ assertEquals(3, NumberUtils.countSignificantFigures("14400"));
+ assertEquals(5, NumberUtils.countSignificantFigures("101430000"));
+ assertEquals(1, NumberUtils.countSignificantFigures("10e1"));
+ assertEquals(2, NumberUtils.countSignificantFigures("1200e3"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresZeroValuesRule6() {
+ assertEquals(3, NumberUtils.countSignificantFigures("00.0"));
+ assertEquals(1, NumberUtils.countSignificantFigures("000"));
+ assertEquals(3, NumberUtils.countSignificantFigures("000."));
+ assertEquals(4, NumberUtils.countSignificantFigures("0.000"));
+ assertEquals(1, NumberUtils.countSignificantFigures("000"));
+ assertEquals(1, NumberUtils.countSignificantFigures("000000"));
+ assertEquals(1, NumberUtils.countSignificantFigures("0"));
+ assertEquals(4, NumberUtils.countSignificantFigures("00.00e0"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresExponentRule7() {
+ assertEquals(3, NumberUtils.countSignificantFigures("10.0e1"));
+ assertEquals(1, NumberUtils.countSignificantFigures("100e232"));
+ assertEquals(3, NumberUtils.countSignificantFigures("1.11e1"));
+ assertEquals(7, NumberUtils.countSignificantFigures("12424.22e1442"));
+
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("00e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("0e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e10"));
+ }
+
+ @Test
+ public void testCountSignificantFiguresEmptyParts() {
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("0e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e10"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures(""));
+ }
+
}
+
From 813d80de053f2e7485118c406981f239308dc718 Mon Sep 17 00:00:00 2001
From: theshoeshiner <2922868+theshoeshiner@users.noreply.github.com>
Date: Mon, 14 Aug 2023 12:25:31 -0400
Subject: [PATCH 2/2] allow sign char, uppercase 'E' and check for dup. sep
---
.../commons/lang3/math/NumberUtils.java | 45 +++++++++++-----
.../commons/lang3/math/NumberUtilsTest.java | 51 ++++++++++++++++---
2 files changed, 77 insertions(+), 19 deletions(-)
diff --git a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
index f1ec76ed9fa..cb64bc0f85a 100644
--- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
+++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java
@@ -39,8 +39,14 @@ public class NumberUtils {
public static final char CHAR_DECIMAL_PERIOD = '.';
/** Reusable char constant for decimal separator character comma. */
public static final char CHAR_DECIMAL_COMMA = ',';
- /** Reusable char constant for exponent character (lowercase e). */
- public static final char CHAR_EXPONENT = 'e';
+ /** Reusable char constant for exponent character - lowercase */
+ public static final char CHAR_EXPONENT_LOWER = 'e';
+ /** Reusable char constant for exponent character - uppercase */
+ public static final char CHAR_EXPONENT_UPPER = 'E';
+ /** Reusable char constant for positive sign */
+ public static final char CHAR_SIGN_POSITIVE = '+';
+ /** Reusable char constant for negative sign */
+ public static final char CHAR_SIGN_NEGATIVE = '-';
/** Reusable Long constant for zero. */
public static final Long LONG_ZERO = Long.valueOf(0L);
/** Reusable Long constant for one. */
@@ -1884,7 +1890,7 @@ public static int countSignificantFigures(String decimalNumber) {
* and 0.0 are measured on the same apparatus and reported in the same dataset, we should be
* able to convey that they both have 2 significant figures.
* Note: Rules 1-6 deal with the non-exponent portion of the string, and by rule apply
- * only to characters prior to the optional exponent character ('e'). Rule 7 covers the
+ * only to characters prior to the optional exponent character ('e'|'E'). Rule 7 covers the
* exponential portion.
* 1) All nonzero digits are always significant.
* 2) Zeros that appear between other nonzero digits are called "middle zeros", and are always
@@ -1946,8 +1952,8 @@ public static int countSignificantFigures(String decimalNumber) {
* Significant
* Figures
*
- * @param decimalNumber The decimal number string. Must be numeric digits with optional decimal
- * and optional integer exponential suffix
+ * @param decimalNumber The decimal number string. Must be optional sign + numeric digits with optional decimal
+ * and optional e|E + sign + integer exponential suffix
* @param decimalSeparator the decimal separator character to use
* @return The number of significant figures in the string
*/
@@ -1958,7 +1964,7 @@ public static int countSignificantFigures(String decimalNumber, char decimalSepa
if (CharUtils.isAsciiNumeric(decimalSeparator)) {
throw new IllegalArgumentException("Decimal Separator cannot be numeric");
}
- if (decimalSeparator == CHAR_EXPONENT) {
+ if (decimalSeparator == CHAR_EXPONENT_UPPER || decimalSeparator == CHAR_EXPONENT_LOWER) {
throw new IllegalArgumentException("Decimal Separator cannot be exponent character 'e'");
}
// track current part
@@ -1970,8 +1976,14 @@ public static int countSignificantFigures(String decimalNumber, char decimalSepa
int middleZeros = 0;
//track known sigfigs
int sigFigs = 0;
- for (int i = 0; i < decimalNumber.length(); i++) {
- char c = decimalNumber.charAt(i);
+ int index = 0;
+ //skip first character if its the sign
+ char firstChar = decimalNumber.charAt(0);
+ if (firstChar == CHAR_SIGN_NEGATIVE || firstChar == CHAR_SIGN_POSITIVE) {
+ index++;
+ }
+ for (; index < decimalNumber.length(); index++) {
+ char c = decimalNumber.charAt(index);
if (c == CHAR_ZERO) {
if (!rightSide) {
if (foundNonZero) {
@@ -1991,14 +2003,17 @@ public static int countSignificantFigures(String decimalNumber, char decimalSepa
}
}
} else if (c == decimalSeparator) {
+ if (rightSide) {
+ throw new IllegalArgumentException("Illegal duplicate separator found at index "+index);
+ }
rightSide = true;
// if a decimal is present, all whole trailing zeros are middle zeros and are
// significant significant (Rule 4)
sigFigs += middleZeros;
middleZeros = 0;
- } else if (c == CHAR_EXPONENT) {
+ } else if (c == CHAR_EXPONENT_UPPER || c == CHAR_EXPONENT_LOWER) {
// exponent is not significant and ends the parsing of sigfigs
- exponentIndex = i;
+ exponentIndex = index;
if (exponentIndex == 0) {
throw new IllegalArgumentException("Decimal part was empty");
}
@@ -2017,7 +2032,7 @@ public static int countSignificantFigures(String decimalNumber, char decimalSepa
middleZeros = 0;
}
} else {
- throw new IllegalArgumentException("Illegal character '" + c + "' at index " + i);
+ throw new IllegalArgumentException("Illegal character '" + c + "' at index " + index);
}
}
// any remaining zeros were trailing and are not significant (Rule 5)
@@ -2038,7 +2053,13 @@ public static int countSignificantFigures(String decimalNumber, char decimalSepa
if (exponentIndex + 1 == decimalNumber.length()) {
throw new IllegalArgumentException("Exponent part was empty");
}
- for (int i = exponentIndex + 1; i < decimalNumber.length(); i++) {
+ int expIndex = exponentIndex+1;
+ //skip first character if its the sign
+ char firstExpChar = decimalNumber.charAt(expIndex);
+ if (firstExpChar == CHAR_SIGN_NEGATIVE || firstExpChar == CHAR_SIGN_POSITIVE) {
+ expIndex++;
+ }
+ for (int i = expIndex; i < decimalNumber.length(); i++) {
char c = decimalNumber.charAt(i);
if (!CharUtils.isAsciiNumeric(c)) {
throw new IllegalArgumentException("Illegal character '" + c + "' at index " + i);
diff --git a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
index 78aa724c464..8a2381e7b45 100644
--- a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java
@@ -1744,12 +1744,21 @@ public void testToShortStringI() {
assertEquals(5, NumberUtils.toShort("1234.5", (short) 5), "toShort(String, short) 2 failed");
}
+ @Test
+ public void testCountSignificantFiguresSign() {
+ assertEquals(6, NumberUtils.countSignificantFigures("+113.343", NumberUtils.CHAR_DECIMAL_PERIOD));
+ assertEquals(5, NumberUtils.countSignificantFigures("-123,33", NumberUtils.CHAR_DECIMAL_COMMA));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1+3"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1-3"));
+ }
+
@Test
public void testCountSignificantFiguresSeparator() {
assertEquals(5, NumberUtils.countSignificantFigures("113.33", NumberUtils.CHAR_DECIMAL_PERIOD));
assertEquals(5, NumberUtils.countSignificantFigures("113,33", NumberUtils.CHAR_DECIMAL_COMMA));
assertEquals(5, NumberUtils.countSignificantFigures("113|33", '|'));
assertEquals(5, NumberUtils.countSignificantFigures("113 33", ' '));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34.1", '.'));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e1", '1'));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e1", 'e'));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e1", '0'));
@@ -1760,6 +1769,7 @@ public void testCountSignificantFiguresNonZeroDigitsRule1() {
assertEquals(1, NumberUtils.countSignificantFigures("1"));
assertEquals(1, NumberUtils.countSignificantFigures("1."));
assertEquals(1, NumberUtils.countSignificantFigures("1e2"));
+ assertEquals(1, NumberUtils.countSignificantFigures("1E3"));
assertEquals(4, NumberUtils.countSignificantFigures("123.4"));
assertEquals(5, NumberUtils.countSignificantFigures("123.44"));
}
@@ -1792,10 +1802,10 @@ public void testCountSignificantFiguresTrailingZerosRule4() {
@Test
public void testCountSignificantFiguresTrailingZerosRule5() {
- assertEquals(3, NumberUtils.countSignificantFigures("14400"));
+ assertEquals(3, NumberUtils.countSignificantFigures("14400e0"));
assertEquals(5, NumberUtils.countSignificantFigures("101430000"));
- assertEquals(1, NumberUtils.countSignificantFigures("10e1"));
- assertEquals(2, NumberUtils.countSignificantFigures("1200e3"));
+ assertEquals(1, NumberUtils.countSignificantFigures("10e-1"));
+ assertEquals(2, NumberUtils.countSignificantFigures("1200e+3"));
}
@Test
@@ -1812,10 +1822,14 @@ public void testCountSignificantFiguresZeroValuesRule6() {
@Test
public void testCountSignificantFiguresExponentRule7() {
- assertEquals(3, NumberUtils.countSignificantFigures("10.0e1"));
- assertEquals(1, NumberUtils.countSignificantFigures("100e232"));
- assertEquals(3, NumberUtils.countSignificantFigures("1.11e1"));
- assertEquals(7, NumberUtils.countSignificantFigures("12424.22e1442"));
+ assertEquals(3, NumberUtils.countSignificantFigures("+10.0e1"));
+ assertEquals(3, NumberUtils.countSignificantFigures("-10.0e1"));
+ assertEquals(3, NumberUtils.countSignificantFigures("-10.0e+1"));
+ assertEquals(3, NumberUtils.countSignificantFigures("-10.0e-1"));
+ assertEquals(1, NumberUtils.countSignificantFigures("100E232"));
+ assertEquals(3, NumberUtils.countSignificantFigures("1.11E1"));
+ assertEquals(7, NumberUtils.countSignificantFigures("12424.22e+1442"));
+ assertEquals(7, NumberUtils.countSignificantFigures("12424.22E-1442"));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("1.34e"));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("00e"));
@@ -1824,11 +1838,34 @@ public void testCountSignificantFiguresExponentRule7() {
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e10"));
}
+ @Test
+ public void testCountSignificantFiguresFloats() {
+ assertEquals(5, NumberUtils.countSignificantFigures(Float.toString(123.34f)));
+ assertEquals(2, NumberUtils.countSignificantFigures(Float.toString(1.1f)));
+ //2.34234241E13
+ assertEquals(9, NumberUtils.countSignificantFigures(Float.toString(23423423499234.23423f)));
+ assertEquals(9, NumberUtils.countSignificantFigures(Float.toString(-23423423499234.23423f)));
+ //8.4345691E11
+ assertEquals(8, NumberUtils.countSignificantFigures(Float.toString(843456890686.255f)));
+ assertEquals(8, NumberUtils.countSignificantFigures(Float.toString(-843456890686.255f)));
+ //6.6644332E11
+ assertEquals(8, NumberUtils.countSignificantFigures(Float.toString(666443345435.038492f)));
+ assertEquals(8, NumberUtils.countSignificantFigures(Float.toString(-666443345435.038492f)));
+ //3.4028235E38
+ assertEquals(8, NumberUtils.countSignificantFigures(Float.toString(Float.MAX_VALUE)));
+ //1.4E-45
+ assertEquals(2, NumberUtils.countSignificantFigures(Float.toString(Float.MIN_VALUE)));
+ //1.17549435E-38
+ assertEquals(9, NumberUtils.countSignificantFigures(Float.toString(Float.MIN_NORMAL)));
+ }
+
@Test
public void testCountSignificantFiguresEmptyParts() {
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("0e"));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("E"));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("e10"));
+ assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures("E10"));
assertThrows(IllegalArgumentException.class, () -> NumberUtils.countSignificantFigures(""));
}