Why does C# TryParse not handle NaN? - c#

I have some common methods for parsing with default value overrides when reading in some old Fortran data. Occasionally the data has NaN (Not a number) where there should be a numeric value. I expected that the TryParse would see the string "NaN" and fail to parse. However, TryParse successfully parses and places NaN in for the numeric value. Is this expected behavior? If this is expected, are there any other "gotcha" values that I should be looking for?
public static double GetDoubleFromString(string s, double defaultOnFailure = 0)
{
//Must be here due to TryParse returning NaN to d and result is set to true below
if (s.Contains("NaN"))
{
log.Warn(string.Format("String contained NaN, returning defaultOnFailure {0} string was {1}", defaultOnFailure, s));
return defaultOnFailure;
}
var d = defaultOnFailure;
if (!double.TryParse(s.Trim(), out d))
{
log.Warn(string.Format("Failed to parse double from string returning defaultOnFailure {0} string was {1}", defaultOnFailure, s));
}
return d;
}
UPDATE
I feel that it should be mentioned, that this only happens for double, long and int do not return the NaN value. See the example code below, the Common.... code is just formatted Console.WriteLine or stops for console execution. See screenshot below for output.
public static void NanTestMain()
{
Common.WriteBlankWithTitle("Test parse NaN");
string s = "NaN";
Common.WriteBlankWithTitle("NaN to Int");
int i;
var intSuccess = int.TryParse(s, out i);
Console.WriteLine(string.Format("Int parse of {0} parse = {1}", i, intSuccess));
Common.WriteBlankWithTitle("NaN to Double");
double d;
var doubleSuccess = double.TryParse(s, out d);
Console.WriteLine(string.Format("Double parse of {0} parse = {1}", d, doubleSuccess));
Common.WriteBlankWithTitle("NaN to Long");
long l;
var longSuccess = long.TryParse(s, out l);
Console.WriteLine(string.Format("Long parse of {0} parse = {1}", l, longSuccess));
Common.Pause();
}

From MSDN:
The s parameter can contain NumberFormatInfo.PositiveInfinitySymbol, NumberFormatInfo.NegativeInfinitySymbol, or NumberFormatInfo.NaNSymbol for the culture indicated by provider.
There are three "special" values to look out for. However, the last few words are key - depending on the current culture, you might see something other than "NaN"!

Double.NaN is a valid value for a double, so this is normal.
There is also negative and positive infinity. Check here for other possible 'special' values.

Related

Compare comma and point(dot) in decimal separator

Can someone help me?
I'm not sure whether it is ignorance or lack of knowledge, but it's really annoying.
What the best way compare this decimal format 123.456,22 and 123,456.22.
i try this way :
decimal val1 = 0; decimal val2 = 0;
decimal.TryParse("123,456.22", out val1);
decimal.TryParse("123.456,22", out val2);
if the computer have 123.456,22 format,
i try decimal.TryParse(123,456.22, out val1) --> val1 = 0;
now i am using code : Split by "," or "." , i just wondering what easier way to do that.
Use the Decimal.Parse method: http://msdn.microsoft.com/en-us/library/cafs243z.aspx
Decimal.Parse(value);
You can use the overloaded method to pass in the Culture (http://msdn.microsoft.com/en-us/library/t7xswkc6.aspx)
Decimal.Parse(value, new CultureInfo("en-GB"));
Try this:
decimal d1;
string s1 = "123,456.22";
if (Decimal.TryParse(s1,
System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.GetCultureInfo("ro-RO"),
out d1))
{
Console.WriteLine("Success: {0} converted into {1} using the ro-RO number format",
s1, d1);
}
else if (Decimal.TryParse(s1, out d1))
{
Console.WriteLine("Success: {0} converted into {1} using the {2} number format",
s1, d1,System.Globalization.CultureInfo.CurrentCulture.Name);
}
}
}
You might find this Wikipedia article interesting: Decimal mark.
123.456,22 and 123,456.22 have a different separator, while in one case its point(.) in the other case its a comma(,) when you just use Parse it would rely on the current culture, so one of them would fail the parse.
In such case you should build up the relevant NumberFormatInfo and set it as per your needs for the decimal separator(NumberDecimalSeparator) and the thousands separator(NumberGroupSeparator)
So you should use TryParse and if that returns false then build your custom one like this and make it available to the Parse as Parameter.
// check with TryParse first and if it returns false then try as below
NumberFormatInfo numinf = new NumberFormatInfo();
numinf.NumberDecimalSeparator= ",";
numinf.NumberGroupSeparator= ".";
decimal.Parse("your failed tryparse", numinf);
decimal d1;
string s1 = "123,456.22";
if (Decimal.TryParse(s1,
System.Globalization.NumberStyles.Any,
System.Globalization.CultureInfo.GetCultureInfo("ro-RO"),
out d1))
{
Console.WriteLine("Success: {0} converted into {1} using the ro-RO number format",
s1, d1);
}
else if (Decimal.TryParse(s1, out d1))
{
Console.WriteLine("Success: {0} converted into {1} using the {2} number format",
s1, d1,System.Globalization.CultureInfo.CurrentCulture.Name);
}
}
}
can be used only on console application??

C# How to assign a string to a double

I need help figuring out how to assign a string to a double.
double value = "myString";
I have double value = double.Parse("myString"); but this throws a FormatException.
I have trying to concatenate like this:
string stringValue += doubleValue.toString() + intValue.ToString;
return stringValue;
I have double value = double.Parse("myString"); but this throws a string.Format error.
Yes, that's the behaviour you want in this case. "myString" doesn't have a numerical value, so the correct numerical value to give it, is to throw a formatting error.
double.Parse("1.2") would work or not depending on whether the culture in use was one where 1.2 was represented as "1.2" or as "1,2". double.Parse("1.2", CultureInfo.InvariantCulture) will always return 1.2, because it's specific about which culture to use.
double.TryParse is useful where it's likely for someone to pass an inappropriate string (like "myString") because it returns a boolean representing success or failure, rather than throwing an exception.
You can use TryParse
string x = "1234";
double y;
if(double.TryParse(x, out y))
{
Console.WriteLine("success y = " + y.ToString());
}
else
{
Console.WriteLine(x + " could not be converted to a double");
}
Parse it, assuming myString is a valid double string representation (eg "3.49", "1394.293", "-1.30E3")
double value = double.Parse(myString)
Most (All?) of the normal numerical types have parse methods. Use TryParse if you're unsure if it's valid (Trying to parse "abc" as a number will throw an exception)
#L.B For custom parsing you can define a NumberFormatInfo like this:
var a = new System.Globalization.NumberFormatInfo()
a.NumberDecimalSeparator = ",";
a.NumberGroupSeparator = ".";
double d = Double.Parse("1.000.000,5", a);
You cannot assign a string to a double. It's impossible. A double is a numerical type. A string is not.
If you parse a string that is a double it is possible.
var doubleThing = Double.Parse("9.99");
double.Parse(string);
Can and will through an exception if the format is incorrect. What are you trying to parse?
double.TryParse("1.05", out value);
Will return true or false if the parse succeeds or fails.

"value was not in a correct format" error when converting a string to an int32

this is my code;
string a="11.4";
int b,c;
b=2;
c= convert.toint32(a) * b
I get this error;
Input string was not in a correct format
how can i convert "a"?
Well a is just not an integer value - you could use Convert.ToDouble() instead. To guard against parsing errors in case that is a possibility use double.TryParse() instead:
string a = "11.4";
double d;
if (double.TryParse(a, out d))
{
//d now contains the double value
}
Edit:
Taking the comments into account, of course it is always best to specify the culture settings. Here an example using culture-indepenent settings with double.TryParse() which would result in 11.4 as result:
if (double.TryParse(a, NumberStyles.Number, CultureInfo.InvariantCulture, out d))
{
//d now contains the double value
}
A very first glance, the number literal "11.4" is not a actual "int". Try some other converting format, such as ToDouble()
I have tried following code in C# for your reference.
string a = "11.4";
double num_a = Convert.ToDouble(a);
int b = 2;
double ans = num_a * b;

string to double parsing error

i have the following code:
static void Main(string[] args)
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("mk-MK");
string s2 = "4.434,00";
double d;
if (Double.TryParse(s2, NumberStyles.Number, CultureInfo.CurrentCulture, out d))
{
//String.Format("{0:0.0,00}", d);
Console.WriteLine(d + " Type of: " + d.GetType());
}
else
{
Console.WriteLine("ne go parsirashe");
}
String.Format("{0:0.0,00}", d);
Console.WriteLine(d);
//Console.WriteLine(String.Format("{0:0,0.00}", d));
//Console.WriteLine(s2.GetType().ToString());
//Console.ReadLine();
//String.Format("{0:0.0,00}"
Console.ReadLine();
The output is: 4434 Type of: System.Double
4434
Why isn't the value of d in the format of : 4.434,00 ? Can you please help me with this? I've sent couple of hours trying to figure this out before trying to reach out to you guys. Thanks!!!
You are discarding your formatted string - you are not assigning it to a string and simply outputting the double to the console (which would call ToString() on it).
Try this:
string forDisplay = string.Format("{0:0.0,00}", d);
Console.WriteLine(forDisplay);
Or, even shorter:
Console.WriteLine(string.Format("{0:0.0,00}", d));
Update:
In order to format the string according to your culture, you will need to use the Format overload that takes an IFormatProvider (i.e. a culture) and ensure that the format string uses the right characters for the different parts (, for standard thousands separator and . for standard decimal separator - see here for the meanings of each such character in a format string):
var res = String.Format(CultureInfo.CurrentCulture, "{0:0,0.00}", d);
Console.WriteLine(forDisplay);
Result:
4.434,00
You meant to do:
string formatted = String.Format("{0:0.0,00}", d);
Console.WriteLine(formatted);
string.Format returns a string -- it cannot affect the formatting of a double, since doubles have no formatting at all. Doubles only store the raw numeric value (as bits, internally).
You have the . and , around the wrong way, if I'm understanding what you're trying to do.
If you read the Custom Numeric Format Strings page on MSDN, you can see that you need to use , for the thousands separator, and . for the decimal separator, and (the important part) the target culture is irrelevant here. The format is always the same, regardless of the current culture.
So what you want to use is:
Console.WriteLine("{0:0,0.00}", d);
Then the output is:
4434 Type of: System.Double
4.434,00

Why does Double.TryParse() return false for a string containing double.MaxValue or double.MinValue?

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?
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
Edit:
I added output of the string, and verification that the parsed value actually still is MaxValue.
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
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.
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");

Categories