Converting double to string 1 - c#

I'm new to C#, I'm currently making a calculator, I want to make a simple calculation but it doesn't work properly.
Here is the current line:
Convert.ToString(Convert.ToDouble(A.Text)+Convert.ToDouble(B.Text)+Convert.ToDouble(C.Text));
Here is a sample output with 1.1 in every textbox:
1.1+1.1+1.1 = 33

The problem is that you are not specifying the culture in your conversions. Most likely you have a German culture (or some other European one) which uses the dot as group separator, not as the decimal point. The result is that 1.1 is interpreted as 11.
There are two solutions:
Enter your numbers in the current culture: 1,1 (Preferred)
Parse the numbers using the invariant culture:
Convert.ToString(
Convert.ToDouble(A.Text, CultureInfo.InvariantCulture) +
Convert.ToDouble(B.Text, CultureInfo.InvariantCulture) +
Convert.ToDouble(C.Text, CultureInfo.InvariantCulture),
CultureInfo.InvariantCulture)
The first approach is preferred, because it will ensure that the user can always enter the numbers in its own culture. Forcing a certain culture on users is something that was acceptable 20 years ago, but not nowadays.

You need to caluculate the sum and then add the parts together.
String.Format is a nice way to concat strings.
double sum = Convert.ToDouble(A.Text)+Convert.ToDouble(B.Text)+Convert.ToDouble(C.Text);
string resultStr = String.Format("{0}+{1}+{2}={3}", A.Text, B.Text, C.Text, sum);

You should assign your intermediate results to a double-variable first and then put it to a string, i.e.
double d = Double.Parse(A.Text) + Double.Parse(B.Text) + Double.Parse(C.Text);
Eventually you can just call
string result = d.ToString();
This is far easier.
See here.

Related

Convert.ToSingle(string) C# conversion ambiguity

I have this code:
string x = "-0.228469369833477";
Single s = Convert.ToSingle(x);
Console.WriteLine(s);
The console outputs: -2,284694E+14 .
What can I do to make it output: -0.228469369833477?
To output the number in its original form:
var s = -0.228469369833477;
Console.WriteLine(s.ToString("0.#######################"));
Note that s is likely a double, not a single. By using single you're very likely losing digits. To get enough precision to represent all of the digits, use Convert.ToDouble() instead.
To ensure that the number gets parsed properly in your locale, use CultureInfo.InvariantCulture, as other answers have stated.
A decimal will give you 28-29 significant digits of precision, with better precision and without the scientific notation problems.
Further Reading
Custom Numeric Format Strings
Single s = Single.Parse(x, CultureInfo.InvariantCulture);
If you want it to output that exact number, you can't use a float because it doesn't give you the precision you want. Try using a double.
double s = Double.Parse(x, CultureInfo.InvariantCulture);
Well, '.' is treated as a thousand separator (and ',' as decimal one) in your current culture (e.g. Russian Culture - "RU-ru" works like that) and since thousand separator ignored on conversion you have -228469369833477 (or -2,284694E+14).
string x = "-0.228469369833477";
// To ensure that '.' is treated as decimal separator
// lets put culture explicitly - CultureInfo.InvariantCulture
Single s = Convert.ToSingle(x, CultureInfo.InvariantCulture);
Console.WriteLine(s);
However, you have too many digits to represent for a Single and all you can return is -0.2284694 (not -0.228469369833477). If you want exact correspondence you have to use Double instead of Single:
Double s = Convert.ToDouble(x, CultureInfo.InvariantCulture);
// -0.228469369833477
Console.WriteLine(s, CultureInfo.InvariantCulture);
You can use
Console.WriteLine(string.Format("{0:N8}", s));
to output the single to 8 decimal places.
You can also specify the culture while doing the string formatting:
Console.WriteLine(string.Format(CultureInfo.InvariantCulture, "{0:N8}", s));
Here's a working fiddle: https://dotnetfiddle.net/nS9qXh

While converting double 0.10 double.parse() converts to 10.0

I have a simple console application in visual studio for testing some code before going big.
But now i have a problem with parsing some string to double.
When the users input is a String: 0.10 i want to convert this to a double.
So the output should be a double: 0.10.
But when i do this with the following code:
double r_value = 0;
r_value = Math.Round(double.Parse(value), 2);
Or
r_value = double.Parse(value);
The output will be: 10 or 10.0.
How can it be this output changes like this? and converts to 10.0 instead 0.10 as i thought it should be.
I strongly suspect your default culture is one in which . is a grouping separator (usually for thousands). So where an English person might write ten thousand as "10,000" some other cultures would write "10.000". At that point, your output makes sense.
If you want to parse with the invariant culture (which treats . as a decimal separator and , as the grouping separator) do so explicitly:
double r_value = double.Parse(value, CultureInfo.InvariantCulture);

Convert numbers with exponential notation from string to double or decimal

Is there a fast way to convert numbers with exponential notation (examples: "0.5e10" or "-5e20") to decimal or double?
Update: I found Parse a Number from Exponential Notation but the examples won't work for me unless I specified a culture.
Solution:
double test = double.Parse("1.50E-15", CultureInfo.InvariantCulture);
If your culture uses . as the decimal separator, just double.Parse("1.50E-15") should work.
If your culture uses something else (e.g. ,) or you want to make sure your application works the same on every computer, you should use InvariantCulture:
double.Parse("1.50E-15", CultureInfo.InvariantCulture)
The standard double.Parse or decimal.Parse methods do the job here.
Examples:
// AllowExponent is implicit
var number1 = double.Parse("0.5e10");
Debug.Assert(number1 == 5000000000.0);
// AllowExponent must be given explicitly
var number2 = decimal.Parse("0.5e10", NumberStyles.AllowExponent);
Debug.Assert(number2 == 5000000000m);
Also, see the MSDN article Parsing Numeric Strings for more information. As long as the NumberStyles.AllowExponent option is specified to the Parse method (which it is by default for double), parsing such strings will work fine.
NB: As the questioner points out, the exponential notation of "e10" for example does not work in all cultures. Specifying en-US culture however ensures that it works. I suspect CultureInfo.InvariantCulture should also do the trick.
#Noldorin is correct try this code:
string str = "-5e20";
double d = double.Parse(str);
Console.WriteLine(str);
the Math.Round does it well, it will reder the number so that will remove, here is how to use it:
Math.Round(Double.Parse("3,55E-15"),2)

Defining decimal numbers on different operation system, how to understand if point or comma is used by C#

I have written a small program where the program works differently on different operating systems (xp, win7) The problem is the program reads some float numbers such 2,686.
One operating system (win7) convert it to float true, but on xp it goes wrong and print it 2686. How can I understand which symbol the operation system uses for decimal numbers ?
Thanks.
string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
This does not depend on the operating system but at the (default) language settings on each PC.
If you use : double value = double.Parse(text); you are using whatever culture the user has configured. If you know the input to be in a certain format, use:
var ci = CultureInfo.GetCulture("nl-NL"); // dutch
double value = double.Parse(text, ci);
Every function that converts has (1 or more) overloads to take a FormattingProvider (Culture).
parse the floating point numbers using the user current culture with double.Parse(string, System.Globalization.CultureInfo.CurrentCulture);
The decimal separator is decided by the current culture.
If you want to use a specific character as decimal separator, you can create a custom NumberFormatInfo object with any separator you like. If you want to use period as deimcal separator, you can simply use InvariantCulture:
double n = Double.Parse(s, CultureInfo.InvariantCulture);
If you want to use comma, you can choose a culture that has that, for example swedish:
double n = Double.Parse(s, CultureInfo.GetCultureInfo("sv-SE"));

DateTime.TryParse century control C#

The result of the following snippet is "12/06/1930 12:00:00". How do I control the implied century so that "12 Jun 30" becomes 2030 instead?
string dateString = "12 Jun 30"; //from user input
DateTime result;
DateTime.TryParse(dateString, new System.Globalization.CultureInfo("en-GB"),System.Globalization.DateTimeStyles.None,out result);
Console.WriteLine(result.ToString());
Please set aside, for the moment, the fact that a correct solution is to specify the date correctly in the first place.
Note: The result is independant of the system datetime for the pc running the code.
Answer: Thanks Deeksy
for (int i = 0; i <= 9; i++)
{
string dateString = "12 Jun " + ((int)i * 10).ToString();
Console.WriteLine("Parsing " + dateString);
DateTime result;
System.Globalization.CultureInfo cultureInfo = new System.Globalization.CultureInfo("en-GB");
cultureInfo.Calendar.TwoDigitYearMax = 2099;
DateTime.TryParse(dateString, cultureInfo , System.Globalization.DateTimeStyles.None, out result);
Console.WriteLine(result.ToString());
}
It's tricky, because the way two digit years work with TryParse is based on the TwoDigitYearMax property of the Calendar property of the CultureInfo object that you are using. (CultureInfo->Calendar->TwoDigitYearMax)
In order to make two digit years have 20 prepended, you'll need to manually create a CultureInfo object which has a Calendar object with 2099 set as the TwoDigitYearMax property. Unfortunately, this means that any two digit date parsed will have 20 prepended (including 98, 99 etc.) which is probably not what you want.
I suspect that your best option is to use a 3rd party date parsing library instead of the standard tryparse that will use the +50/-50 year rule for 2 digit years. (that a 2 digit year should be translated into a range between 50 years before this year and 50 years greater than this year).
Alternatively, you could override the ToFourDigitYear method on the calendar object (it's virtual) and use that to implement the -50/+50 rule.
I'd write a re-usable function:
public static object ConvertCustomDate(string input)
{
//Create a new culture based on our current one but override the two
//digit year max.
CultureInfo ci = new CultureInfo(CultureInfo.CurrentCulture.LCID);
ci.Calendar.TwoDigitYearMax = 2099;
//Parse the date using our custom culture.
DateTime dt = DateTime.ParseExact(input, "MMM-yy", ci);
return new { Month=dt.ToString("MMMM"), Year=dt.ToString("yyyy") };
}
Here's my list of quasi-date strings
List<string> dates = new List<string>(new []{
"May-10",
"Jun-30",
"Jul-10",
"Apr-08",
"Mar-07"
});
Scan over it like so:
foreach(object obj in dates.Select(d => ConvertCustomDate(d)))
{
Console.WriteLine(obj);
}
Notice that it handles 30 as 2030 now instead of 1930...
You're looking for the Calendar.TwoDigitYearMax Property.
Jon Skeet has posted something on this you will likely find useful.
I had a similar problem and I solved it with a Regex. In your case it would look like that:
private static readonly Regex DateRegex = new Regex(
#"^[0-9][0-9] (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9][0-9]$",
RegexOptions.Compiled | RegexOptions.ExplicitCapture);
private static string Beautify(string date)
{
var match = DateRegex.Match(date);
if (match.Success)
{
// Maybe further checks for correct day
return date.Insert("dd-MMM-".Length, "20");
}
return date;
}
Congratulations, you have a Y2K bug.
The documentation for this behavior starts with the Custom Date and Time Format strings, which includes a description of the yy format specifier. Specifically, we have this excerpt:
In a parsing operation, a two-digit year that is parsed using the "yy" custom format specifier is interpreted based on the Calendar.TwoDigitYearMax property of the format provider's current calendar.
Follow that to the Calendar.TwoDigitYearMax documentation and we find this:
This property allows a 2-digit year to be properly translated to a 4-digit year. For example, if this property is set to 2029, the 100-year range is from 1930 to 2029. Therefore, a 2-digit value of 30 is interpreted as 1930, while a 2-digit value of 29 is interpreted as 2029.
The initial value of this property is derived from the settings in the regional and language options portion of Control Panel.
If you only have two digits for the year you're gonna need to guess at the tipping point between the current and previous or current and next centuries. Microsoft made their guess, but also chose to make it configurable, where different systems may have it configured different ways. This implies it's dangerous to rely on two-digit year values, as we've known since before 1999. Since 1999, no one sane uses two digits for the year anymore.
As a side note, it's been some time since this was first decided; it's probably past time for Microsoft to update that default guess (maybe 2079, or a new approach entirely, perhaps based on an offset from the current year). Unfortunately, it's a statistical certainty there are programs out there which rely on the default not changing, such that it's difficult for Microsoft to update this. It would cause what they call a "breaking change", and they are pretty good about avoiding doing that to people... though there is some discussion on changing this for .Net 8.
This situation is therefore likely to start coming up more often in the near future, and having found my way here because it indeed had come up in another place I felt it worthwhile to add a more-recent answer to this older question. There's nothing really new in this answer, except to confirm the situation hasn't (yet) changed. Maybe a Windows 11 release will have a new default?
result = year.ToString().Length == 1
|| year.ToString().Length == 2 ? "1"
: (Convert.ToInt32(year.ToString()
.Substring(0, (year.ToString().Length - 2))) + 1).ToString();

Categories

Resources