114

I need to parse the string "1.2345E-02" (a number expressed in exponential notation) to a decimal data type, but Decimal.Parse("1.2345E-02") simply throws an error

abatishchev
  • 98,240
  • 88
  • 296
  • 433
Jimbo
  • 22,379
  • 42
  • 117
  • 159

10 Answers10

205

It is a floating point number, you have to tell it that:

decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
57

It works if you specify NumberStyles.Float:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Float);
Console.WriteLine(x); // Prints 0.012345

I'm not entirely sure why this isn't supported by default - the default is to use NumberStyles.Number, which uses the AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowTrailingSign, AllowDecimalPoint, and AllowThousands styles. Possibly it's performance-related; specifying an exponent is relatively rare, I suppose.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I am trying to get this working with double but it seems it won't. Not sure why it couldn't.. ? – JanT Aug 05 '19 at 14:01
  • @JanT: With no more information than "it won't" and "it couldn't" I can't really help more. I suggest you ask a new question with much more detail, showing what you tried and exactly what happened. – Jon Skeet Aug 05 '19 at 18:36
  • I tried to run code like in your answer but instead of decimal used double. But already found workaround. Cheers – JanT Aug 05 '19 at 19:32
  • 1
    @JanT It would be nice if you could share your workaround. I have exactly the same problem and could use the info. Thanks! – Rick Glimmer Sep 07 '19 at 15:20
  • @RickGlimmer: I'm not sure how you know your problem is exactly the same as JanT's, given that they never provided detail of what they were trying to do. Replacing `decimal` with `double` in my code works fine for me, just as I'd expect it to. If you could provide *details* of what you're trying to, the code you're using, and the result, it would be much easier to help. – Jon Skeet Sep 07 '19 at 15:31
  • @Jon Skeet, At the moment of writing i read he used double instead of decimal and it did not work and used a workaround. As you say using a double does work!. Only thing i needed was the NumberStyles.Float. Thanks for the follow up. Appreciated. – Rick Glimmer Sep 09 '19 at 15:42
  • @Rick, can't remember which project this was for but when pasted in .Net fiddler now it indeed does work with double as well. Maybe it was older version or Net, or possibly VB I am not sure. (Note I know this is from 2010 but we have some early 2000s code to work with). – JanT Sep 12 '19 at 15:20
  • Wouldn't it make more sense to use `NumberStyles.AllowExponent` instead of Float? I personally tend to use `NumberStyles.Number | NumberStyles.AllowExponent` – Joe Phillips Jan 06 '21 at 16:59
  • @JoePhillips: Using *just* `NumberStyles.AllowExponent` would make "1.2345E-02" fail, I believe. Using `NumberStyles.Number | NumberStyles.AllowExponent` is useful *if* you want to allow thousands separators and trailing signs, but that's not something I typically need. – Jon Skeet Jan 06 '21 at 17:32
  • @JonSkeet"specifying an exponent is relatively rare, I suppose" Heh, heh. I frequently use data that is the output of systems that use old Fortran code. For me, this is the norm – m_a_s Jun 15 '21 at 12:35
  • @m_a_s: Yes, but you're one person. From what I have observed of not just my own projects but those I've seen all over the place, I still believe it's relatively rare. I believe the vast majority of code that parses floating point numbers never needs to do with an exponent. – Jon Skeet Jun 15 '21 at 12:41
  • @JonSkeet Indeed, I am one person, and so are you. And get this, everything we all post here without any verifiable proof is just anecdotal. :) That being said, from what I have observed in other people's projects, I would not call it rare. Not, common, but certainly not rare. But I am an engineer and work with many scientists and engineers. We use this notation every day. – m_a_s Jun 16 '21 at 11:14
37

In addition to specifying the NumberStyles I would recommend that you use the decimal.TryParse function such as:

decimal result;
if( !decimal.TryParse("1.2345E-02", NumberStyles.Any, CultureInfo.InvariantCulture, out result) )
{
     // do something in case it fails?
}

As an alternative to NumberStyles.Any you could use a specific set if you're certain of your formats. e.g:

NumberStyles.AllowExponent | NumberStyles.Float
Sverrir Sigmundarson
  • 2,453
  • 31
  • 27
  • 1
    But its not necessary to use Float with AllowExponent because Float = AllowLeadingWhite | AllowTrailingWhite | AllowLeadingSign | AllowDecimalPoint | AllowExponent – Lukáš Kmoch Mar 31 '17 at 08:39
  • @LukášKmoch Indeed you're right. Force of habit as the others (apart from Any) do not include it. Shouldn't hurt to perform the extra OR though. – Sverrir Sigmundarson Mar 31 '17 at 15:57
15
decimal d = Decimal.Parse("1.2345E-02", System.Globalization.NumberStyles.Float);
Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
13

Be cautious about the selected answer: there is a subtility specifying System.Globalization.NumberStyles.Float in Decimal.Parse which could lead to a System.FormatException because your system might be awaiting a number formated with ',' instead of '.'

For instance, in french notation, "1.2345E-02" is invalid, you have to convert it to "1,2345E-02" first.

In conclusion, use something along the lines of:

Decimal.Parse(valueString.Replace('.',','), System.Globalization.NumberStyles.Float);
KwentRell
  • 416
  • 1
  • 4
  • 17
10

The default NumberStyle for decimal.Parse(String) is NumberStyles.Number, so if you just want to add the functionality to allow exponents, then you can do a bitwise OR to include NumberStyles.AllowExponent.

decimal d = decimal
    .Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Joe Phillips
  • 49,743
  • 32
  • 103
  • 159
5

I've found that passing in NumberStyles.Float, in some cases, changes the rules by which the string is processed and results in a different output from NumberStyles.Number (the default rules used by decimal.Parse).

For example, the following code will generate a FormatException in my machine:

CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5", NumberStyles.Float, culture); // FormatException thrown here

I'd recommend using the input NumberStyles.Number | NumberStyles.AllowExponent, as this will allow exponential numbers and will still process the string under the decimal rules.

CultureInfo culture = new CultureInfo("");
culture.NumberFormat.NumberDecimalDigits = 2;
culture.NumberFormat.NumberDecimalSeparator = ".";
culture.NumberFormat.NumberGroupSeparator = ",";
Decimal.Parse("1,234.5",NumberStyles.Number | NumberStyles.AllowExponent, culture); // Does not generate a FormatException

To answer the poster's question, the right answer should instead be:

decimal x = decimal.Parse("1.2345E-02", NumberStyles.Number | NumberStyles.AllowExponent);
Console.WriteLine(x);
bastos.sergio
  • 6,684
  • 4
  • 26
  • 36
2

Warning about using NumberStyles.Any:

"6.33E+03" converts to 6330 as expected. In German, decimal points are represented by commas, but 6,33E+03 converts to 633000! This is a problem for my customers, as the culture that generates the data is not known and may be different than the culture that is operating on the data. In my case, I always have scientific notation, so I can always replace comma to decimal point before parsing, but if you are working with arbitrary numbers, like pretty-formatted numbers like 1,234,567 then that approach doesn't work.

0

You don't need to replace the dots (respectively the commas) just specify the input IFormatProvider:

float d = Single.Parse("1.27315", System.Globalization.NumberStyles.Float, new CultureInfo("en-US"));
float d = Single.Parse("1,27315", System.Globalization.NumberStyles.Float, new CultureInfo("de-DE"));
mortal
  • 225
  • 2
  • 7
0

If you want to check and convert the exponent value use this

string val = "1.2345E-02";
double dummy;
bool hasExponential = (val.Contains("E") || val.Contains("e")) && double.TryParse(val, out dummy);
if (hasExponential)
{
    decimal d = decimal.Parse(val, NumberStyles.Float);
}

Hope this helps someone.

rAm
  • 199
  • 2
  • 19