How to convert a string containing an exponential number to decimal and back to string

Eminem picture Eminem · Jul 26, 2012 · Viewed 19.7k times · Source

I'm converting code between delphi and c#.
Values are stored as strings in a text file from the delphi app. An example of the stored value is : '4.42615029219009E-5'

Now in my c# app I need to read in that string value and then later have the capability to write out the value again. Initially I used code similar to:

string stringField = "4.42615029219009E-5";
double someMoneyVar = Convert.ToDouble(stringField)

later if I need to recreate the text file with the value of someMoneyVar then using a simple:

string.Format("{0}", someMoneyVar)

would output:

4.42615029219009E-05 // note the 0

Lastly, I read that it is better to store money as decimals in c#. I've tried to convert the string value to a decimal using decimal.Parse(someMoneyVar, NumberStyles.Any) , however the formatting is lost.

I need the data to be output exactly as it was input.

Note, the value of someMoneyVar may not always contain an exponential part. e.g. 0.0428860331919443. If there is no exponential part to the value of someMoneyVar then the value is written correctly to the text file.

Update:
Digging into delphi's FloatToStr function and help files (which is what stores the value in the text file) i came with the following:

The resulting string uses fixed point format if the number of digits to the left of the decimal point in the value is less than or equal to the specified precision, and if the value is greater than or equal to 0.00001 (Edit: this should be 0.0001. There is an error in the delphi documentation). Otherwise the resulting string uses scientific format, and the Digits parameter specifies the minimum number of digits in the exponent (between 0 and 4).
...
If the section for positive values is empty, or if the entire format string is empty, the value is formatted using general floating-point formatting with 15 significant digits, corresponding to a call to FloatToStrF with the ffGeneral format. General floating-point formatting is also used if the value has more than 18 digits to the left of the decimal point and the format string does not specify scientific notation.

So bearing in mind that the FloatToStr function does a call to FloatToStrF uses 15 significant (precision) digits and a 0 as the minumum number of digits hence we end up with

4.42615029219009E-5

if the digits was 2 then the number would be displayed as

4.42615029219009E-05

According to the MSDN http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#GFormatString
using the general format specifier, the precision of double is 15 and decimal is 29

Fixed-point notation is used if the exponent that would result from expressing the number in scientific notation is greater than -5 and less than the precision specifier; otherwise, scientific notation is used. The result contains a decimal point if required, and trailing zeros after the decimal point are omitted. If the precision specifier is present and the number of significant digits in the result exceeds the specified precision, the excess trailing digits are removed by rounding.

However, if the number is a Decimal and the precision specifier is omitted, fixed-point notation is always used and trailing zeros are preserved.

If scientific notation is used, the exponent in the result is prefixed with "E" if the format specifier is "G", or "e" if the format specifier is "g". The exponent contains a minimum of two digits. This differs from the format for scientific notation that is produced by the exponential format specifier, which includes a minimum of three digits in the exponent.

The result string is affected by the formatting information of the current NumberFormatInfo object. The following table lists the NumberFormatInfo properties that control the formatting of the result string.

One can easily set the precision e.g. mydecimal.toString("G15") however i still haven't found a way to set the number of digits after the 'E' sign as easily as in the delphi FloatToStrF function

Answer

Alex picture Alex · Jul 26, 2012

To convert strings to numbers, as you already figured out, you just use a double. I'd try a different conversion though:

double myNum = double.Parse("<yournumber>", NumberStyles.AllowExponent | NumberStyles.Float, CultureInfo.InvariantCulture);

AllowExponent and Float should keep the notation, and InvariantCulture takes care of the decimal divider (which might not be a dot depending on the locale).

You can output scientific notation numbers via string.Format(), like this:

double num = 1234.5678; // 1.2345678e+03
string.Format("{0:e}", num); // should output "1.2345678E+03"

If you have to distinguish between numbers with and without the "E+xx" part, you'll have to search for it before converting the string to double, and a full snippet (WARNING: not tested!) could look like:

string myString = ReadNumberFromFile(); // Just a placeholder method
double myNum = double.Parse(myString, NumberStyles.AllowExponent | NumberStyles.Float, CultureInfo.InvariantCulture);
string output = string.Empty; //this will be the "converted-back number" container
if (myString.IndexOf("e", StringComparison.OrdinalIgnoreCase) >= 0)
{
    //Number contains the exponent
    output = string.Format("{0:e}", num); // exponential notation 'xxxExx' casing of 'e' changes the casing of the 'e' in the string
}
else
{
    //TODO: Number does NOT contain the exponent
    output = string.Format("{0:f}", num); // fixed-point notation in the form 'xxxx.xxx'
}

The point here is that, as far as number go, being with or without an exponent doesn't make any difference whatsoever, it's just a matter of representation (and it makes little sense to distinguish between them: it's really the same thing).