I am integrating a library with my c# code. There is a decimal parameter i am using from the library. Parameter return usual decimal values mostly like: 0.24756400. But sometimes it returns values in Exponential format like: 0E-8.
When i try process the parameter in my code, for example when i parse it like this:
Decimal.Parse(paymentAuth.IyziCommissionFee);)
it gives me exception
Object reference not set to an instance of an object) when the value is in Exponential format.
If i can identify the value format (number or Exponential number) i can manage it.
So how can i identify if the value is in Exponential format? Alternatively, any suggestion to manage such situation?
You don't need to identify if it is an exponent or not
If you want to parse a string that could be an exponential format into a decimal you can use the overload of the Decimal.Parse method that takes a System.Globalization.NumberStyles parameter to do this.
var result = Decimal.Parse(
paymentAuth.IyziCommissionFee,
System.Globalization.NumberStyles.Float
);
This specifies that the incoming string is a float, which you can represent using the exponential format you're talking about.
You can read the MSDN docs about this overload and the NumberStyles type here :
Decimal.Parse(String, NumberStyles)
System.Globalization.NumberStyles
Related
The ToString() of a double value, causes losing of the decimal places
(1521.6666666666667).ToString() ==> "1521.66666666667"
Is there any way to save all the decimal places when converting to string
Also
(1521.6666666666667).ToString("F13"); => "1521.6666666666700"
(1521.6666666666667).ToString("0.0000000000000"); => "1521.6666666666700
Does this have to do with size of the double value
The solution to this is reading the documentation. Seriously It is NOT "ToString" that is loosing it.
Let me quote the float data Type from https://msdn.microsoft.com/en-us/library/b1e65aza.aspx:
Precision: 7 digits.
The numbers are in your source, they are never in the float. Not properly. The value is rounded.
You have to format the string.
(1521.6666666666667).ToString("R");
decimal d = 1521.6666666666667M;
d.ToString();
According to the documentation:
Compared to floating-point types, the decimal type has more precision and a smaller range.
Specifically, decimal has 28-29 significant digits, rather than 15-16 for double.
You can use Decimal instead of Double:
(1521.6666666666667M).ToString(); // note "M"
Another possibility (if you have to use Double) is "R" format:
(1521.6666666666667).ToString("R");
Use The Round-trip ("R") Format Specifier, which will attempts to ensure that a numeric value that is converted to a string is parsed back into the same numeric value. This format is supported only for the Single, Double, and BigInteger types.
But for Double and Single values, the "R" format specifier in some cases fails to successfully round-trip the original value and also offers relatively poor performance. Instead, we recommend that you use the "G17" format specifier for Double values and the "G9" format specifier to successfully round-trip Single values.
From MSDN:
In some cases, Double values formatted with the "R" standard numeric format string do not successfully round-trip if compiled using the /platform:x64 or /platform:anycpu switches and run on 64-bit systems.
Resource: Standard Numeric Format Strings.
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).
I have this line of code:
System.Convert.ChangeType(input, destinationType, CultureString);
If called with a culture of de-DE and input is 4,50 and destinationType is double it returns 4.50.
If I call the same with en-GB it converts it to 450.00.
Is there a way to make it return 4.50 or throw an exception saying you can't convert 4,50 to double.
Thanks
As specified from MSDN on the specific overload you are using:
Returns an object of the specified type whose value is equivalent to the specified object. A parameter supplies culture-specific formatting information.
In other words, it tries to understand how to convert based on the culture's formatting information. So 4,50 means 4.5 in de-DE yet the same number is identified as 4.50 in en-GB (Notice there is a period not a comma).
A comma is used in the en-GB culture to talk about thousands (e.g 4000 can be written 4,000) when 4,50 is parsed, the comma is ignored and therefor the output is 450.
This is just like the date 21st of January 2010 is parsed 01/21/10 (mm/dd/yy) in the US yet it is parsed 21/01/10 (dd/mm/yy) in the UK.
So actually, no exception should be raised since 4,50 CAN be converted to a double, depends where in the world :)
Note: C# has the CultureInfo.InvariantCulture when you want culture-independent conversions.
If you want to throw an exception, don't use ChangeType, use Double.Parse with the NumberStyles just like #ChrisF explained in his answer.
This for instance will throw an exception:
Double.Parse("4,50", NumberStyles.Float);
You should use double.Parse rather than ChangeType.
You can get double.Parse to throw an exception if you don't set the NumberStyles.AllowThousands flag:
NumberStyles.AllowThousands indicates that group separators are allowed. Valid group separator characters are determined by the NumberGroupSeparator or CurrencyGroupSeparator properties of the current NumberFormatInfo object.
MSDN page
In this case you could use:
double result = double.Parse("4,50", numberStyle);
As it says here
A typical value to specify is a combination of Float combined with AllowThousands.
So in your case you want to make sure that this flag is not set. Though it would mean that you couldn't correctly parse "4,500".
By setting the flag you tell the code to simply ignore the thousands separator when parsing the string. This means that according to the algorithm the following string all convert to 450:
450
45,0
4,50
450,
Use Double.Parse(input, style)
The parsing is much stricter and the System.Globalization.NumberStyles style allows you to specify exactly what you do and don't consider to be a number. It will throw a FormatException if it doesn't like what is in the string.
I'm trying to convert a string to double. The incoming string is always going to be a whole number...no decimals. So, for example "90".
double percentToCheck = Convert.ToDouble(String.Format("{0:0.00}", SomeEntity.KeyIDs.SomePercentTrigger));
SomePercentTrigger is the % that I will be converting.
I get a "string is not in the correct format" error so how should I format this string? I've got to format it because if I don't I get the same error with just this during the conversion:
double percentToCheck = Convert.ToDouble(SomeEntity.KeyIDs.SomePercentTrigger);
UPDATED:
SomePercentTrigger is simply a string such as "80"..it'll always be a whole number too.
Update:
Your string is "52.0".
It must be the '.' that causes the FormatException.
You are probably on a machine where '.' is not set as the decimal point (e.g. I live in Germany and use German regional settings. Our decimal point is ',' )
To get around this problem you need to parse the string using CultureInfo.InvariantCulture.
var value = double.Parse(myString, CultureInfo.InvariantCulture);
InvariantCulture should be used for the parts of your application that revolve around data storage. Make sure you use it as well when converting doubles to strings Console.WriteLine(value.ToString(CultureInfo.InvariantCulture));
I suspect that SomeEntity.KeyIDs.SomePercentTrigger has some invalid characters in it (something other than digits, '.' and a optional leading '-'), say for example "80%"
So you're getting a FormatException on this line
double percentToCheck = Convert.ToDouble(String.Format("{0:0.00}", SomeEntity.KeyIDs.SomePercentTrigger));
because {0:0.00} formatting rules are only valid for numeric values.
Also you get the very same exception here:
double percentToCheck = Convert.ToDouble(SomeEntity.KeyIDs.SomePercentTrigger);
because "80%" can not be converted into a double.
You should either
put some logging right in front of the failing statement
or debug that code
and see what the actual content of SomeEntity.KeyIDs.SomePercentTrigger is.
Use double.Parse(string) or alternatively double.TryParse(string, out value)
It doesn't make sense to try to format a string. You would have to parse it to a number first in order to format it. Anyhow, there is no problem in parsing a number without decimals as a double, so the string is probably not containing what you think it does.
If the string contains a number in integer format, parse the string as an integer, and then convert the integer to a double:
double percentToCheck = (double)Int32.Parse(SomeEntity.KeyIDs.SomePercentTrigger);
In my app I parse a value from xml (string) to a double.
The value in the xml happens to have the dot as a fraction seperator whereas the system takes the current system settings and can have a different separator (dev system takes the comma for example).
Is there a way to tell double.TryParse() the dot is the fraction separator?
Should I manually replace the dot with the system's fraction separator? If so, how do I get this?
What you should do, in this situation, is use the XmlConvert class and its members to convert the value like it exists in the XML file to a regular variable. :)
Pass CultureInfo.InvariantCulture into double.TryParse:
double value;
bool success = double.TryParse(text, NumberStyles.Float,
CultureInfo.InvariantCulture,
out value);
(For genuinely standard XML formatting, Frederik's suggestion of using XmlConvert is the best idea though.)