views:

2853

answers:

4

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.

+2  A: 

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

Jon Skeet
+4  A: 

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.

Fredrik Mörk
Ah. Didn't realise it was that simple. Stupid question....(I am used to VBA...)
MT
Which I now realise can give the same result using Cstr...I apologise
MT
IMO this isn't a good way, because with very high number, yourNumber.toString() won't return "1000000000000" but "1.0E12". If it's only for display, it's ok, but don't count on it if it is for math in your code.
Clement Herreman
Yep - I was wondering about the exponential problem. Luckily for my current purposes I know that I will not have numbers bigger than say 200 with more than say 6 decimal places...and there is no maths involved (at the moment..)
MT
@Clement H: I needed to go up to 100000000000000 before it switched to exponential mode. This can be overcome by calling d.ToString("0.#"), which will also return the same result as d.ToString() for the lower values (will update my answer; thanks for raising the issue).
Fredrik Mörk
A: 

You could use the Int() function to get the whole number component, then subtract from the original.

A: 

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
Steve