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).
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * 4) + * + * + * + * + * 4) + * + *
StringCountReasonNote
0.003The first whole zero is significant (Rule 6), and the two trailing zeros are significant + * (Rule 4)
0e201The first whole zero is significant (Rule 6) and the exponent is not (Rule 7)
00001The 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.03First whole zero is significant (Rule 6) and the last two are also significant (Rule + *
0000.4First whole zero is significant (Rule 6) and the last three are also significant (Rule + *
+ * 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("")); }