From 8a1042959df80c06dbfa83896594caa8e20ff9d6 Mon Sep 17 00:00:00 2001 From: Sebastian Bazley Date: Sun, 19 May 2013 10:22:13 +0000 Subject: [PATCH] LANG-693 Method createNumber from NumberUtils doesn't work for floating point numbers other than Float git-svn-id: https://svn.apache.org/repos/asf/commons/proper/lang/trunk@1484263 13f79535-47bb-0310-9956-ffa450edef68 --- src/changes/changes.xml | 1 + .../apache/commons/lang3/math/NumberUtils.java | 18 ++++++++++++------ .../commons/lang3/math/NumberUtilsTest.java | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3c6f46d96..4859882a2 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -22,6 +22,7 @@ + Method createNumber from NumberUtils doesn't work for floating point numbers other than Float FastDateFormat does not use the locale specific cache correctly Simplify FastDateFormat; eliminate boxing LookupTranslator now works with implementations of CharSequence other than String 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 064f5043f..1e6ccdc02 100644 --- a/src/main/java/org/apache/commons/lang3/math/NumberUtils.java +++ b/src/main/java/org/apache/commons/lang3/math/NumberUtils.java @@ -482,6 +482,7 @@ public static Number createNumber(final String str) throws NumberFormatException // if both e and E are present, this is caught by the checks on expPos (which prevent IOOBE) // and the parsing which will detect if e or E appear in a number due to using the wrong offset + int numDecimals = 0; // Check required precision (LANG-693) if (decPos > -1) { // there is a decimal point if (expPos > -1) { // there is an exponent @@ -493,6 +494,7 @@ public static Number createNumber(final String str) throws NumberFormatException dec = str.substring(decPos + 1); } mant = str.substring(0, decPos); + numDecimals = dec.length(); // gets number of digits past the decimal to ensure no loss of precision for floating point numbers. } else { if (expPos > -1) { if (expPos > str.length()) { // prevents double exponent causing IOOBE @@ -588,17 +590,21 @@ public static Number createNumber(final String str) throws NumberFormatException //Must be a Float, Double, BigDecimal final boolean allZeros = isAllZeros(mant) && isAllZeros(exp); try { - final Float f = createFloat(str); - if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) { - return f; + if(numDecimals <= 7){// If number has 7 or fewer digits past the decimal point then make it a float + final Float f = createFloat(str); + if (!(f.isInfinite() || (f.floatValue() == 0.0F && !allZeros))) { + return f; + } } } catch (final NumberFormatException nfe) { // NOPMD // ignore the bad number } try { - final Double d = createDouble(str); - if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) { - return d; + if(numDecimals <= 16){// If number has between 8 and 16 digits past the decimal point then make it a double + final Double d = createDouble(str); + if (!(d.isInfinite() || (d.doubleValue() == 0.0D && !allZeros))) { + return d; + } } } catch (final NumberFormatException nfe) { // NOPMD // ignore the bad number 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 b41c03037..56b0597e7 100644 --- a/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/math/NumberUtilsTest.java @@ -115,7 +115,20 @@ public void testToFloatStringF() { assertTrue("toFloat(String,int) 1 failed", NumberUtils.toFloat("1.2345", 5.1f) == 1.2345f); assertTrue("toFloat(String,int) 2 failed", NumberUtils.toFloat("a", 5.0f) == 5.0f); } - + + /** + * Test for {(@link NumberUtils#createNumber(String)} + */ + @Test + public void testStringCreateNumberEnsureNoPrecisionLoss(){ + String shouldBeFloat = "1.23"; + String shouldBeDouble = "3.40282354e+38"; + String shouldBeBigDecimal = "1.797693134862315759e+308"; + + assertTrue(NumberUtils.createNumber(shouldBeFloat) instanceof Float); + assertTrue(NumberUtils.createNumber(shouldBeDouble) instanceof Double); + assertTrue(NumberUtils.createNumber(shouldBeBigDecimal) instanceof BigDecimal); + } /** * Test for {@link NumberUtils#toDouble(String)}. */