I'm an experienced developer but not a math expert. I know enough about the IEEE floating point specification to be afraid of making assumptions about parsing, printing, and comparing them.
I know I can parse a double
from a String
using Double.parseDouble(String s)
. I know I can also parse that same string into a BigDecimal
using new BigDecimal(String s)
, and then ask the BigDecimal
for a double
using BigDecimal.doubleValue()
.
I glanced at the API and code for both techniques, and it seems that BigDecimal
has a lot of different parsing and conversion options.
Are both techniques (Double.parseDouble(s)
and new BigDecimal(s).doubleValue()
) guaranteed, for all string inputs, to produce exactly the same double
primitive value, provided the value is not outside the range of plus or minus Double.MAX_DOUBLE
?
For most input values, both techniques should yield the same values. While it's still possible they might not, it doesn't seem likely.
The BigDecimal(String)
constructor Javadocs states:
API Note:
For values other than
float
anddouble
NaN and ±Infinity, this constructor is compatible with the values returned byFloat.toString(float)
andDouble.toString(double)
.
However, the Double.parseDouble(String)
method states:
Returns a new
double
initialized to the value represented by the specifiedString
, as performed by thevalueOf
method of classDouble
.
And that goes on to describe the format accepted by the method.
Let's Test It!
Let's test some values. It looks like an incredibly huge effort to test this exhaustively, but let's test including some string values that represent values known to produce floating-point errors or to be inexact representations.
public static void main(String[] args)
{
String[] values = {"0", "0.1", "0.33333333333333333333", "-0", "-3.14159265", "10.1e100",
"0.00000000000000000000000000000000000000000000000000142857142857",
"10000000000.000000000000000001", "2.718281828459",
"-1.23456789e-123", "9.87654321e+71", "66666666.66666667",
"1.7976931348623157E308", "2.2250738585072014E-308", "4.9E-324",
"3.4028234663852886E38", "1.1754943508222875E-38", "1.401298464324817E-45",
String.valueOf(Math.E), String.valueOf(Math.PI), String.valueOf(Math.sqrt(2))
};
for (String value : values) {
System.out.println(isDoubleEqual(value));
}
}
// Test if the representations yield the same exact double value.
public static boolean isDoubleEqual(String s) {
double d1 = Double.parseDouble(s);
double d2 = new BigDecimal(s).doubleValue();
return d1 == d2;
}
For these values, I get all true
s. This is not by any means exhaustive, so it would be very difficult to prove it true for all possible double
values. All it would take is one false
to show a counterexample. However, this seems to be some evidence that it is true for all legal double
string representations.
I also tried leading spaces, e.g. " 4"
. The BigDecimal(String)
constructor threw a NumberFormatException
but Double.parseDouble
trimmed the input correctly.
The BigDecimal(String)
constructor won't accept Infinity
or NaN
, but you only asked about the normal finite range. The Double.parseDouble
method accepts hexadecimal floating point representations but BigDecimal(String)
does not.
If you include these edge cases, one method may throw an exception where the other would not. If you're looking for normal base-10 strings of finite values within range, the answer is "it seems likely".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With