.NET's ToString() Number Truncating - c#

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

Related

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

Always leave two decimal digits after the dot [duplicate]

This question already has answers here:
How do I display a decimal value to 2 decimal places?
(19 answers)
Closed 8 years ago.
UPDATE
It's so simple...
When I try to convert the value $ 1.50 from a textbox to a decimal variable, like this:
decimal value = Convert.ToDecimal(textbox1.text.SubString(1));
OR
decimal value = Decimal.Parse(textbox1.text.SubString(1));
I get this result: 1.5.
I know that 1.5 and 1,50 worth the same. But I want to know if it's possible to have two digits after the dot on a decimal variable.
I want to have this as result: 1.50 instead of 1.5 even if these two values worth the same...
I want to have this as result: 1.50 instead of 1.5 even if these two values worth the same..
You have 1.50 or 1.500 or 1.5000. all depending on how you decide to format it / print it.
Your decimal value is stored in floating point format. How many decimal points you see is about output, not storage (at least until you reach the limit of the precision of the particular binary format, and 2 decimal places is nowhere close). A C# Decimal stores up to 29 significant digits.
See this reference. It gives an example of a currency format. It prints something like:
My amount = $1.50
But, you aren't storing a $ sign..., so where does it come from? The same place the "1.50" comes from, it is in your format specifier.
http://msdn.microsoft.com/en-us/library/364x0z75.aspx
Console.WriteLine("My amount = {0:C}", x);
var s = String.Format("My amount = {0:C}", x);
It is no different than saying, how do I store 1/3 (a repeating decimal)?
Well, it isn't 0.33, but if I only look at the first 2 digits, then it is 0.33. The closer i look (the more decimal places I ask for in the format), the more I get.
0.33333333333333... but that doesn't equal 0.330
You're confusing storage of the numeric value with rendering it as a string (display).
decimal a=1.5;
decimal b=1.50;
decimal c=1.500;
In memory: the zeros are kept to keep track of how much precision is desired. See the link in the comment by Chris Dunaway below.
However, note these tests:
(a==b) = true
(b==c)=true
Parsing ignores the trailing zeros, so your example one creates them, then they're ignored, as they're mathmatically irrelevant.
Now how you convert to string is a different story:
a.ToString("N4") returns the string "1.5000" (b. and c. the same)
a.ToString("N2") returns the string "1.50"
As the link in the comment explains, if you just to a.ToString, trailing zeros are retained.
If you store it in a database column as type 'decimal', it might be a different story - I haven't researched the results. These are the rules that .Net uses and while the databases might use different rules, these behaviours often follow official standards, so if you do your research you might find that the database behaves the same way!
The important thing to remember is that there is a difference between the way numbers are stored in memory and the way they are represented as strings. Floating point numbers may not retain trailing zeros this way, it's up to the rules of the in-memory storage of the type (usually set by standards bodies in very specific, detailed ways).

How do I format a number in C# with commas and decimals?

I have a number with a variable number of digits after the decimal point. I want to format the number with commas and all decimal numbers.
For example: 42,023,212.0092343234
If I use ToString("N") I get only 2 decimals, ToString("f") gives me all decimals no commas. How do I get both?
Not sure (and unable to test right now) but would something like this work?
"#,##0.################"
string.Format("{0:#,##0.############}", value);
will give you up to 12 decimal places.
There is not a custom format specifier for "all following digits", so something like this will be closest to what you want.
Note too that you're limited by the precision of your variable. A double only has 15-16 digits of precision, so as your left-hand side gets bigger the number of decimal places will fall off.
UPDATE: Looking at the MSDN documentation on the System.Double type, I see this:
By default, a Double value contains 15
decimal digits of precision, although
a maximum of 17 digits is maintained
internally.
So I think pdr's on to something, actually. Just do this:
// As long as you've got at least 15 #s after the decimal point,
// you should be good.
value.ToString("#,#.###############");
Here's an idea:
static string Format(double value)
{
double wholePart = Math.Truncate(value);
double decimalPart = Math.Abs(value - wholePart);
return wholePart.ToString("N0") + decimalPart.ToString().TrimStart('0');
}
Example:
Console.WriteLine(Format(42023212.0092343234));
Output:
42,023,212.00923432409763336
Ha, well, as you can see, this gives imperfect results, due (I think) to floating point math issues. Oh well; it's an option, anyway.
Try ToString("N2")
Let's try this
[DisplayFormat(DataFormatString = "{0:0,0.00}")]
Here is the way somewhat to reach to your expectation...
decimal d = 42023212.0092343234M;
NumberFormatInfo nfi = (NumberFormatInfo) CultureInfo.InvariantCulture.NumberFormat.Clone();
nfi.NumberDecimalDigits= (d - Decimal.Truncate(d)).ToString().Length-2;
Console.WriteLine(d.ToString("N",nfi));
For more detail about NumberFormatInfo.. look at MSDN ..
http://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.aspx

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.

decimal to double

I have the following test code:
decimal test1 = 0.0500000000000000045656554454M;
double test2 = (double)test1;
This results in test2 showing as 0.05 when debugging. Why is it being rounded to 2 decimal places?
Thanks
The value from that conversion is actually 0.050000000000000009714451465470119728706777095794677734375, as shown by DoubleConverter. That's the exact value of the nearest double to the decimal you converted.
When you use the debugger or normal string formatting, you aren't usually shown the exact result.
The reason is that double can contain no more than 15-16 significant digits.
see double (C# Reference)
You should take a look at this article about floating-point arithmetic and .NET. The rounding occurs due to a combination of how the number gets converted to a double-precision floating point value and how it is formatted when printed, since .NET defaults to 15 decimals for doubles, and your original number contains decimal past the 15th.
You could try test2.ToString("0.000000000000000000000000") to see if you might squeeze out any more information from the number, but I doubt it will.
There are two reasons I can think of:
Due to the different representation of decimal and double. See this article for more information about floating point representation. It is possible that there are not enough bits for the whole number representation in the double.
Due to the way numbers are printed. It is possible that in your printing options, there are less than 18 numbers after the decimal point specified - in which case, you'll get the rounded result.
I would check for tweaking the printing options first to make sure that the problem isn't there first.
.. But know that the only solution for the first problem is stop using double :-)

Categories