Reputation: 789
I have static method that takes a string for input and returns the original input string if the string represents a number. If the string does not represent a number the the input string is processed and a transformed string is returned. I'm writing test cases. I'm trying to verify that an input string containing either double.MinValue
or double.MaxValue
is returned unchanged. I've read through a number of forums, including StackOverflow, and have come up with the following logic:
string doubleMax = double.MaxValue.ToString();
double d;
CultureInfo cultureInfo = new CultureInfo("en-US", true);
if (Double.TryParse(doubleMax, NumberStyles.Any, cultureInfo.NumberFormat, out d))
{
Console.WriteLine("parsed");
}
else
{
Console.WriteLine("couldn't parse");
}
Problem is the Double.TryParse()
always returns false. I've called TryParse()
in a bunch of different ways, but the result is always the same, false.
This logic works if I use decimal.MinValue()
, int.MinValue()
, or float.MinValue()
.
Can someone tell me why my logic isn't working for double.MinValue
?
Upvotes: 17
Views: 7992
Reputation: 700362
That's because of the way that floating point numbers are stored and displayed. The value is rounded when it's turned into a human readable string, and for double.MaxValue
it happens to be rounded up so that it no longer fits in a double
.
You can use the round-trip format "R" to turn a value into a string that always can be parsed back to the same value, as it adds extra precision until the correct value is returned. Also, use the same culture when formatting the number as parsing it, to avoid culture differences:
CultureInfo cultureInfo = new CultureInfo("en-US", true);
string doubleMax = Double.MaxValue.ToString("R", cultureInfo);
Console.WriteLine(doubleMax);
double d;
if (Double.TryParse(doubleMax, NumberStyles.Any, cultureInfo.NumberFormat, out d)) {
if (d == Double.MaxValue) {
Console.WriteLine("parsed");
} else {
Console.WriteLine("value changed");
}
} else {
Console.WriteLine("couldn't parse");
}
Output:
1.7976931348623157E+308
parsed
I added output of the string, and verification that the parsed value actually still is MaxValue.
Upvotes: 22
Reputation: 2738
I got interested in this question and found that if you add E20 to ToString then it works.
double.MaxValue.ToString("E20")
Interesting question though.
UPDATE:
I test equality between d (the parsed double) and double.MaxValue and they are equal.
var abc = Double.Parse(double.MaxValue.ToString("E20"));
abc.Dump();
double d;
CultureInfo cultureInfo = new CultureInfo("en-US", true);
if (Double.TryParse(double.MaxValue.ToString("E20"), NumberStyles.Any, cultureInfo.NumberFormat, out d)) Console.WriteLine("parsed");
else Console.WriteLine("couldn't parse");
if(d == double.MaxValue) Console.WriteLine("parsed value is equal to MaxValue");
else Console.WriteLine("parsed value is NOT equal to MaxValue");
Upvotes: 1
Reputation: 9391
The problem is in the rounding of the ToString() method. The actual MaxValue according to the documentation is 1.7976931348623157E+308, but the ToString() of that gives you 1,79769313486232E+308, which is rounded up and thus too large to parse.
Upvotes: 1
Reputation: 754763
There's nothing wrong with your logic, it's just a limitation i the Double.TryParse
API. From the documentation
Ordinarily, if you pass the Double.TryParse method a string that is created by calling the Double.ToString method, the original Double value is returned. However, because of a loss of precision, the values may not be equal. In addition, attempting to parse the string representation of either MinValue or MaxValue throws an OverflowException, as the following example illustrates.
The documentation appears to be taken from the Parse
method and applied to TryParse
since TryParse
does not throw. But the sample code following the pargraph uses TryParse
and expects it to fail for MaxValue
and MinValue
Upvotes: 7