Convert numbers with exponential notation from string to double or decimal - c#

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)

Related

C# double.TryParse with InvariantCulture returns unexpected result

I'm trying to unit test a getprice method using NUnit. I am stuck with parsing the rawprice into double. My cultureinfo is en-US but I set it to de-DE for this test. Double parsing with numberstyles.any and invariantculture returns unexpected result.
The rawprice cultureinfo is unknown, it can be any. Also the server where it will run is also unknown and can be in any language.
For this test, I tried German for the rawprice and machine.
I tried parsing "9,42" but the result is 942.
[Test]
[SetCulture("de-DE")]
public void GetPrice_PriceTextWithCommaDecimal_ReturnsInvariantPrice()
{
var rawPriceText = "9,42";
double.TryParse(rawPriceText, NumberStyles.Any, CultureInfo.InvariantCulture, out double price);
//parsed price result is 942
...
}
It's not clear from your question what you expected. However, as far as what the code is doing, it's doing exactly what you told it to:
Providing NumberStyles.Any tells double.TryParse() to allow any format, except AllowHexSpecifier. This includes the AllowThousands option.
Providing the InvariantCulture causes parsing to use the ',' character as the thousands separator.
Parsing doesn't actually care where a thousands separator appears. I.e. it doesn't actually force the separator to be in the location where it would indicate a thousands-multiple digit.
So, when you ask it to parse "9,42", that text is interpreted using InvariantCulture (i.e. ignoring your current culture of de-DE), the ',' character is treated as a thousands separator (i.e. ignored for the purpose of computing the actual value), and you get the value 942, just like you asked for.
If you don't want that result, you need to use different arguments for the call to double.TryParse(). You would need to explain what you do want if you want advice on what arguments you should use. All we can say given the information currently in your question is what arguments you apparently don't want.
The cultures in ToString and TryParse must match.
It's either
var s = rawPrice.ToString(CultureInfo.InvariantCulture);
//rawPrice becomes 9.42
double.TryParse(s, NumberStyles.Any, CultureInfo.InvariantCulture, out double price);
or
CultureInfo.CurrentCulture = new CultureInfo("de-DE");
var s= rawPrice.ToString(CultureInfo.CurrentCulture);
//rawPrice becomes 9,42
double.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out double price);
You should put your culture into the TryParse mechanism.
e.g.
double.TryParse(rawPriceText, NumberStyles.Any, new CultureInfo("de"), out double price);
For this case you could use CultureInfo.CurrentUICulture instead of creating a new CultureInfo.
You set the culture to de-DE.
But apparently you then decide to use the InvariantCulture instead, which will not recognize the , separator as decimal separator.
Using CurrentCulture instead will give you the expected result.

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

Why does Convert.ToString format doubles in this way? [duplicate]

This question already has answers here:
Double to string conversion without scientific notation
(18 answers)
Double ToString - No Scientific Notation [duplicate]
(1 answer)
Closed 9 years ago.
Consider the following code:
var rateUsed = 0.00000001;
var rateUsedConvertToString = Convert.ToString(rateUsed);
var rateUsedToString = rateUsed.ToString();
Instead of my strings being "0.00000001", they are both "1E-08". I don't have control over the initial type of rateUsed, it is a double, and I want the exact string representation of the double.
Why does this happen, and how would I get 0.00000001 as a string, if this started off as a double value?
If you want a specific format, then you need to tell it what you want via the parameter. The available standard formats are here, or you can use custom formats. Pass your chosen format to either ToString(format) or Convert.ToString(value, format).
Note; 1E-8 is exactly 0.00000001 - that is simply using exponential notation, i.e. this is 1×10-8
The default format is "general" which is described as:
Result: The most compact of either fixed-point or scientific notation
So yes, sometimes it will use scientific (aka exponential) notation - specifically, it will do so whenever that is shorter than the fixed-point notation. Maybe try using .ToString("F")
You may want to start off looking at When does Double.ToString() return a value in scientific notation?
With that said, as #MarcGravell inferred, 1E-08=0.00000001, it's just been displayed in scientific notation. If you're looking for something to output as a decimal number (typical) you may want to look in to formatting it differently. Such as:
var rateUsed = 0.00000001;
var rateUsedToStringFormatted = rateUsed.ToString("0.########"); // 0.00000001
Another option is to create a custom IFormatProvider/ICustomFormatter which would perform this conversion consistently. Then, instead of using .ToString("0.########") everywhere, you could supply .ToString(MyDoubleFormatter) for a more consistent output (and, should you change it at a later date, you're doing so in one location).
You probably want to use the fixed-point ("F") format specifier with a different overload of ToString, one which accepts the format specifier string:
int num = 175;
Console.WriteLine(num.ToString("F", CultureInfo.InvariantCulture)); // 175.00
Console.WriteLine(num.ToString("F3", CultureInfo.InvariantCulture)); // 175.000
Alternatively, you can use a custom format specifier:
Console.WriteLine(num.ToString("00000.00", CultureInfo.InvariantCulture)); // 00175.00
Additionally, as shown in these examples, whenever you are converting values to their text representations, consider using CultureInfo.InvariantCulture for data which should be stored independently of the current thread's culture (like when writing data to a file, for example).

Converting double to string 1

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.

Why double.TryParse("0.0000", out doubleValue) returns false ?

I am trying to parse string "0.0000" with double.TryParse() but I have no idea why would it return false in this particular example. When I pass integer-like strings e.g. "5" it parses correctly to value of 5 .
Any ideas why it is happening ?
it takes the localization settings at runtime into account... perhaps you are running this on a system where . is not the decimal point but , instead...
In your specific case I assume you want a fixed culture regardless of the system you are running on with . as the decimal point:
double.TryParse("0.0000", NumberStyles.Number, CultureInfo.CreateSpecificCulture ("en-US"), out temp)
OR
double.TryParse("0.0000", NumberStyles.Number,CultureInfo.InvariantCulture, out temp)
Some MSDN reference links:
Double.TryParse(String, NumberStyles, IFormatProvider, Double)
CultureInfo.CreateSpecificCulture(String)
IFormatProvider Interface
CultureInfo.InvariantCulture Property
TryParse uses the current culture by default. And if your current culture uses a decimal seperator different from ., it can't parse 0.0000 as you intend. So you need to pass in CultureInfo.InvariantCulture.
var numberStyle = NumberStyles.AllowLeadingWhite |
NumberStyles.AllowTrailingWhite |
NumberStyles.AllowLeadingSign |
NumberStyles.AllowDecimalPoint |
NumberStyles.AllowThousands |
NumberStyles.AllowExponent;//Choose what you need
double.TryParse( "0.0000", numberStyle, CultureInfo.InvariantCulture, out myVar)
Almost certainly the problem is that Thread.CurrentCulture does not use dot as the decimal separator.
If you know that the number will be always formatted with dot as the decimal separator, use this code that utilizes the other overload of double.TryParse:
style = NumberStyles.Float | NumberStyles.AllowThousands;
culture = CultureInfo.InvariantCulture;
float num;
if (double.TryParse("0.0000", style, culture, out num)) {
// whatever
}
It will return false if the current culture specifies a decimal point separator that is different than the . character.
When parsing strings representation you need to be aware in what culture they are represented otherwise you'll get unexpected behavior.
In this case you're getting false, but it could even be worse, for example in the following example if you were expecting to get the number one you would instead get one thousand:
Thread.CurrentThread.CurrentCulture = new CultureInfo("pt-PT");
double d;
Console.WriteLine(double.TryParse("1.000", out d));
Console.WriteLine(d);
This is because in the pt-PT culture the . character is used as NumberGroupSeparator and the , character is used as NumberDecimalSeparator.
If the input you're parsing comes from the user then always parse it using the culture the user is associated. Getting the culture the user is associated is something dependent on the context, for example in a Windows Forms application you would use Thread.CurrentThread.CurrentCulture when on the UI thread to get it. In a ASP.NET application this may be different.
To change the culture to something that has "." as decimal separator use:
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-GB");
When this method returns, contains the double-precision floating-point
number equivalent to the s parameter, if the conversion succeeded, or
zero if the conversion failed.
From the MSDN page for this method.
http://msdn.microsoft.com/en-us/library/994c0zb1.aspx
Zero goes in, zero comes out.
Changing the CultureInfo with TryParse did nothing for me. I had to change the number formats under Control Panel (Change, date, time, or number formats) and changed the Decimal symbol. Than it worked again.
The most stupid thing about this is that it only accept "," as decimal separator in my culture, but the result is with a ".". Someone, somewhere, wasn't very lucky thinking that day...
So I'll try this:
if ((double.TryParse(sVat, out vat)) == false)
if (double.TryParse(sVat.Replace(",", "."), out vat) == false)
double.TryParse(sVat.Replace(".", ","), out vat);
It works for me:
double temp = 0;
Console.WriteLine(double.TryParse("0.0000", out temp));
Console.ReadLine();
writes True.

Categories

Resources