Why does converting this exponent throw a FormatException? - c#

Why would this exponent throw a FormatException when converted to a decimal using Decimal.Parse.
String stringValue = "8.83080183680678E-05";
Decimal decimalValue = Decimal.Parse(badValue, NumberStyles.AllowExponent);
When the code executes it throws a FormatException
"Input string was not in a correct format."
The code seems to adhere to the MSDN spec: [ws][$][sign][digits,]digits[.fractional-digits][e[sign]digits][ws]

You need to specify that the number format also allows for decimals.
Decimal.Parse(badValue, NumberStyles.AllowExponent | NumberStyles.AllowDecimalPoint);
...which is explained in the documentation for AllowExponent:
Indicates that the numeric string can be in exponential notation. The AllowExponent flag allows the parsed string to contain an exponent that begins with the "E" or "e" character and that is followed by an optional positive or negative sign and an integer. In other words, it successfully parses strings in the form nnnExx, nnnE+xx, and nnnE-xx. It does not allow a decimal separator or sign in the significand or mantissa; to allow these elements in the string to be parsed, use the AllowDecimalPoint and AllowLeadingSign flags, or use a composite style that includes these individual flags.
NumberStyles.Float is probably a better choice in this case.

NumberStyles.AllowExponent doesn't include AllowDecimalPoint. You might've wanted to use NumberStyles.Float, which includes "AllowLeadingWhite, AllowTrailingWhite, AllowLeadingSign, AllowDecimalPoint, and AllowExponent".

Related

C# - is there any difference between x.ToString("D") and x.ToString(), where x is type int?

My personal preference is x.ToString(), since it has slightly fewer letters. Is there any advantage to either one?
The main point of .ToString("D") is that it allows you to specify the preceding number of digits.
e.g,
var i = 123;
var stringed = i.ToString("D5");//stringed = 00123
Take a look at what the "D" actually means here:
https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings
"D" or "d" Decimal Result: Integer digits with optional negative sign.
Supported by: Integral types only.
Precision specifier: Minimum number of digits.
Default precision specifier: Minimum number of digits required.
More information: The Decimal("D") Format Specifier.
1234 ("D") -> 1234
-1234 ("D6") -> -001234
So, depending on the format of the output you're looking for, that's what the different format (or precision) specifiers can help dictate your output.
From the Microsoft documentation:
To format an Int32 value as an integral string with no leading zeros, you can call the parameterless ToString() method. By using the "D" format specifier, you can also include a specified number of leading zeros in the string representation.
It would appear that "D" without digits is what Int32.ToString() uses by default.
There is then, no difference in output between the two.
Look at this article
The "D" (or decimal) format specifier converts a number to a string of
decimal digits (0-9), prefixed by a minus sign if the number is
negative. This format is supported only for integral types.
It shows the same result for the case "D".
But it will pad with zeros to the left of your int if you "Dx" (x is a number)
ToString() is enough for you to convert to string

String with suffix fails parsing

When ever one passes string with suffix parsing to decimal fails.
decimal testValue;
decimal.TryParse("5M", NumberStyles.Number, CultureInfo.CurrentCulture, out testValue)
Following parse will return false.
Why does TryParse fail when you pass in a string with a suffix?
Because Decimal.TryParse does not support it.
Depending on the value of style, the s parameter may include the following elements:
[ws][$][sign][digits,]digits[.fractional-digits][e[sign]digits][ws]
Elements in square brackets ([ and ]) are optional. The following table describes each element.
ws: Optional white space. White space can appear at the beginning of s if style includes the NumberStyles.AllowLeadingWhite flag. It can appear at the end of s if style includes the NumberStyles.AllowTrailingWhite flag.
$: A culture-specific currency symbol. Its position in the string is defined by the NumberFormatInfo.CurrencyNegativePattern or NumberFormatInfo.CurrencyPositivePattern properties of the NumberFormatInfo object returned by the IFormatProvider.GetFormat method of the provider parameter. The currency symbol can appear in s if style includes the NumberStyles.AllowCurrencySymbol flag.
sign: An optional sign.
digits: A sequence of digits ranging from 0 to 9.
.: A culture-specific decimal point symbol.
fractional-digits: A sequence of digits ranging from 0 to 9.
Because there is no way to parse your string without removing M part. And none of NumberStyles have such a functionality.
I can suggest to Replace your M with empty string but that would be only solve for your case, it won't be a general solution.
decimal testValue;
decimal.TryParse("5M".Replace("M", ""), NumberStyles.Number,
CultureInfo.CurrentCulture, out testValue);
A real-type-suffix specifies number types. It teaches to C# compiler what a numeric literal type considered as. In a string, it means nothing. It is just an another character.

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

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
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).

How do I format a number as a string, so that zero is replaced by the empty string

I need for this to work in a single format statement and to work for both ints and decimals:
For example:
int myInt=0;
decimal myDecimal=0.0m;
// ... Some other code
string formattedResult1=String.Format("{0}",myInt);
string formattedResult2=String.Format("{0}",myDecimal);
The expected results are:
"" (i.e., string.Empty) if the item to be formatted is zero
and a numeric value (e.g., "123.456" for the decimal version) if it isn't.
I need for this to occur exclusively as a result of the format specification in the format string.
This should do:
string formattedResult1 = string.Format("{0:0.######;-0.######;\"\"}", myInt);
The colon introduces a numeric format string. The numeric format string is divided into 3 parts with semicolons: part 1 is for positive numbers, part 2 for negative numbers, and part 3 for zeros. To define a blank string you need to delimit it with double quotes otherwise it doesn't like it.
See MSDN for the full syntax.
based from the accepted answer above i have done the same thing in microsoft "report builder"
this worked for me (shows 2 decimal places, blank for zero) :
,##0.00;-#,##0.00;""

How To Convert a Decimal From 123.45 into 0000000012345 using C#

I have a requirement in doing some conversion work to send over a decimal field into a zero filled string.
I need to turn 1234.56 into 000000000123456
I know I can multiply by 100 to get rid of the decimal (not my favorite thing to do), but then how can i format it to match the requirement?
I'm assuming there's some kind of built in Format method, i just can't find it.
Thanks.
I'd try this: How to: Pad a Number with Leading Zeros
You can pad an integer with leading zeros by using the "D" standard
numeric format string together with a precision specifier. You can pad
both integer and floating-point numbers with leading zeros by using a
custom numeric format string. This topic shows how to use both methods
to pad a number with leading zeros.
This will do it:
string.Format( "{0:D15}", 123456 );
You should consult the documentation for string.Format.
Based on the documentation from http://msdn.microsoft.com/en-us/library/0c899ak8.aspx You could do it by using the following format:
Decimal value = new Decimal(1234.56);
Console.WriteLine("I need to turn {0} into {1}", value, value.ToString("000000000000000"));
Regards,
herber

Categories