Decimal parse of exponential 0 value (0+E3) - c#

Our middle tier sends us serialized objects and sometimes a 0, due to some math operations in java on the server, come through as 0E+3. When deserializing the object we get an XmlException --> System.OverflowException because the value is too large or small for a decimal.
Why can't decimal.Parse handle this conversion?
Is there a way to protect our client from these numbers coming in this way?

You could try:
decimal.Parse(numberText, System.Globalization.NumberStyles.Any)
EDIT:
This doesn't work for 0E+3 unfortunately
Works:
Console.WriteLine(decimal.Parse("0", System.Globalization.NumberStyles.Any));
Console.WriteLine(decimal.Parse("123.45", System.Globalization.NumberStyles.Any));
Console.WriteLine(decimal.Parse("1.35E+6", System.Globalization.NumberStyles.Any));
Console.WriteLine(decimal.Parse("1.54E-5", System.Globalization.NumberStyles.Any));
Doesn't work:
Console.WriteLine(decimal.Parse("0E+3", System.Globalization.NumberStyles.Any));
Is the problem number always 0E+3?
If so, you could write a helper method to handle this:
decimal ParseDecimal(string number)
{
if (number.Equals("0E+3", StringComparison.OrdinalIgnoreCase))
{
return 0;
}
return decimal.Parse(number, System.Globalization.NumberStyles.Any);
}

Java is probably doing this calculation as a double (which means you also don't need the extra precision of a Decimal) if they come out this way... consider using double instead of decimal.
If you have to, just trim out the E[+-]?([0-9]+)$ manually with a regex and do the multiplication yourself. Or match ^0E as a special case (it seems NumberStyles.Any can't handle it) and just return 0.

Change it to a float or double and it will parse it correctly. Although be careful, the precision will be much lower (7 digits for float or 15-16 digits for double vs 28-29 for decimal).

Related

?? Operator (C#) for double returns incorrect result

Using C#, any idea why the following method returns 57.999999999999993 (instead of 58)?
double Test_Null_Coalescing_Operator()
{
double? x = 0.58;
return ((x ?? 0) * 100);
}
//returns 57.999999999999993 (instead of 58)
Assuming double is IEEE 754 64-bit binary floating point, 0.58 is not exactly representable. The closest is 0.57999999999999996003197111349436454474925994873046875. After multiplying by 100, the rounding error on rounding up to 58 would be 3.99680288865056354552507400512695312500E-15, which is slightly bigger than the rounding error on rounding down to 57.99999999999999289457264239899814128875732421875, 3.10862446895043831318616867065429687500E-15
If you are representing physical quantities such as length, the measurement error will completely dwarf the rounding error, less than one part in 1015.
There are some special cases, such as some financial calculations, for which exact representation of short terminating decimal fractions is important. For those, you should generally use a decimal type, not double.
Rounding error. 0.58 not exists as a double.
#Felipe Deveza already mentioned about the reason. If you want to receive exactly 0.58, you can use Math.Round()
The answers and the linked duplicate explain the reason, I just want to highlight a rule of thumb. Whenever the decimally written representation of the number is relevant use the decimal type instead. The float and double types are fast as they are directly supported by the CPU but use them only if their decimal representation is not important (eg. rendering, multimedia processing, etc.).
In many languages the decimal (or a similar decimal floating-point type for the same purpose) is called money suggesting that this is what you should use for financial calculations. And actually that's where the m postfix of the decimal comes from in C# as well (var x = 0.58m).

Why does parsing a value as a double return a different result than parsing it as a decimal then casting to a double?

Trying to parse the value -36.845167 from a string:
double result;
double.TryParse("-36.845167", out result);
result is -36.845167000000004
decimal value;
decimal.TryParse("-36.845167", out value);
double result = (double)value;
result is -36.845167
Why is this?
The two doubles bracketing -36.845167 are -36.84516700000000355430529452860355377197265625 and -36.84516699999999644887793692760169506072998046875
They differ from the exact value by 3.55112206307239830493927001953125E-15 and
3.55430529452860355377197265625E-15 respectively.
The first one is very slightly closer, so it is the correct IEEE 754 round-to-nearest result. I do not know what the standard requires for casting a C# decimal to double, but, assuming you used the same output method in both cases, it may not have done round-to-nearest.
This is because double has limited precision, while decimal stores decimal digits. Read more here: Difference between decimal, float and double in .NET?
Basically, decimal is better at storing decimal representation of the number.
Edit: answering your original question more explicitly: Both of your results are kinda incorrect since -36.845167 cannot be represented as double. Check out the output of this expression:
result.ToString("G20")
on both of your results and you will see that both of them are not equal to -36.845167: one of them is -36.845166999999996 and other is -36.845167000000004.
So, both of them are 4e-15 off your original number. What you really see in the debugger (or upon outputting to console) is just the rounding during the conversion to string.

Rounding decimal number upto two decimal places

I am trying to round decimal number upto two decimal places which is working perfectly.
I am doing as below :
Math.Round(Amount, 2)
So, if I have Amount as 40000.4567, I am getting 40000.46which is exactly what I want.
Now problem is I have decimal number like 40000.0000, when I round it, the result is 40000, and what I really want is 40000.00. So round will always neglect trailing zeros.
To solve this problem, I have the option of converting it to string and use format , but I don't want to do that as that will be inefficient and I believe there must be some way to do it better.
I also tried something like
Decimal.Round(Amount, 2)
Now one way can be to check whether number contains anything in fractional part and use round function accordingly , but that is really bad way to do it.
I can't use truncate as well due to obvious reasons of this being related to amount.
What is the way around?
It is rounding correctly but you fail to understand that the value is not the format. There is no difference between the two values, 40000 and 40000.00, and you'll have a similar issue with something like 3.1.
Simply use formatting to output whatever number you have to two decimal places, such as with:
Console.WriteLine(String.Format("{0:0.00}", value));
or:
Console.WriteLine(value.ToString("0.00"));
You are mixing two things - rounding and output formatting. In order to output a number in a format you want you can use function string.Format with required format, for example:
decimal number = 1234.567m;
string.Format("{0:#.00}", number);
You can read more about custom numeric format strings in MSDN
I think what you're looking for is displaying two decimals, even if they are zero. You can use string.Format for this (I've also combined it with Round):
Console.WriteLine(string.Format("{0:0.00}", Math.Round(Amount, 2));
for rounding decimal number you can use
decimal number=200.5555m;
number= Math.Round(number, 2);
string numString= string.Format("{0:0.00}", number);

.NET's ToString() Number Truncating

So, WPF calls ToString() on objects when generating TextColumns in DataGrid and then i found out strange thing about ToString() method:
Check this out :
object a = 0.3780000001;//Something like this
Console.WriteLine(a.ToString());//Gets truncated in some cases
First, I thought it was just rounding, but few times I was able to reproduce such behavior on
doubles with < 15 digits after dot. Am I missing something?
To the computer, 0.378 and 0.378000...0001 are the same number. See this question: Why is floating point arithmetic in C# imprecise?
As defined on the MSDN page for System.Double, the double type only contains a maximum of fifteen digits of precision. Even though it maintains 17 internally, your figure contains 18 significant digits; this is outside the range of System.Double.
Use decimal instead of float for a more precise type.
By default, Double.ToString() truncates to 15 digits after the dot, but if you really want to use the double data type and you need those 2 extra digits, you can use th "G17" formatting string:
double x = 3.1415926535897932;
string pi = x.ToString("G17");
This will give you a string with the full 17 digits.
I wouldn't assume (so fast) that you found a bug in something as crucial as C#'s ToString implementation.
The behaviour you're experiencing is caused by the fact that a float is imprecisely stored in computer memory (also see this question).
maybe the number format's accuracy range doesn't contain that number? (ie, float only has accuracy to a few significant figures)
If you're data-binding the value, you can supply a ValueConverter which formats the number any way you want.
http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx
Set a to be an Decimal and it will print it correctly!
decimal a = 0.378000000000000001m;
Console.WriteLine(a.ToString());
You could have a common decimal format setting to use all the time.
eg
object a = 0.378000000000000001;
Console.WriteLine(a.ToString(Settings.DecimalFormat));

Get the decimal part of a number and the number of places after the decimal point (C#)

Does anyone know of an elegant way to get the decimal part of a number only? In particular I am looking to get the exact number of places after the decimal point so that the number can be formatted appropriately. I was wondering if there is away to do this without any kind of string extraction using the culture specific decimal separator....
For example
98.0 would be formatted as 98
98.20 would be formatted as 98.2
98.2765 would be formatted as 98.2765 etc.
It it's only for formatting purposes, just calling ToString will do the trick, I guess?
double d = (double)5 / 4;
Console.WriteLine(d.ToString()); // prints 1.75
d = (double)7 / 2;
Console.WriteLine(d.ToString()); // prints 3.5
d = 7;
Console.WriteLine(d.ToString()); // prints 7
That will, of course, format the number according to the current culture (meaning that the decimal sign, thousand separators and such will vary).
Update
As Clement H points out in the comments; if we are dealing with great numbers, at some point d.ToString() will return a string with scientific formatting instead (such as "1E+16" instead of "10000000000000000"). One way to overcome this probem, and force the full number to be printed, is to use d.ToString("0.#"), which will also result in the same output for lower numbers as the code sample above produces.
You can get all of the relevant information from the Decimal.GetBits method assuming you really mean System.Decimal. (If you're talking about decimal formatting of a float/double, please clarify the question.)
Basically GetBits will return you 4 integers in an array.
You can use the scaling factor (the fourth integer, after masking out the sign) to indicate the number of decimal places, but you should be aware that it's not necessarily the number of significant decimal places. In particular, the decimal representations of 1 and 1.0 are different (the former is 1/1, the latter is 10/10).
Unfortunately, manipulating the 96 bit integer is going to require some fiddly arithmetic unless you can use .NET 4.0 and BigInteger.
To be honest, you'll get a simpler solution by using the built in formatting with CultureInfo.InvariantCulture and then finding everything to the right of "."
Just to expand on the point about getbits, this expression gets the scaling factor from a decimal called foo:
(decimal.GetBits(foo)[3] & 16711680)>>16
You could use the Int() function to get the whole number component, then subtract from the original.

Categories