Reputation: 8154
I have a float variable and would like to get only the part after the comma, so if I have 3.14. I would like to get 14 as an integer. How can I do that?
Upvotes: 15
Views: 37822
Reputation: 459
using Regular Expressions (REGEX)
string input_decimal_number = "3.14";
var regex = new System.Text.RegularExpressions.Regex("(?<=[\\.])[0-9]+");
if (regex.IsMatch(input_decimal_number))
{
string decimal_places = regex.Match(input_decimal_number).Value;
}
// input : "3.14"
// output : "14"
// input : "2.50"
// output : "50"
you can find more about Regex on http://www.regexr.com/
Math Solution using Math.Truncate
var float_number = 12.345;
var result = float_number - Math.Truncate(float_number);
Using multiplier [which is 10 to the power of N (e.g. 10² or 10³) where N is the number of decimal places]
// multiplier is " 10 to the power of 'N'" where 'N' is the number
// of decimal places
int multiplier = 1000;
double double_value = 12.345;
int double_result = (int)((double_value - (int)double_value) * multiplier);
// output 345
Upvotes: 1
Reputation: 6012
Just in case some wants another cheating way for it:
float x = 5.2f;
int decimalPart = Math.Round((x - Math.Truncate(x))*100)
where 100 is used shift the decimal part.
Upvotes: 0
Reputation: 55445
You can subtract the integer portion from the value itself to retrieve the fractional part.
float x = 3.14
float fractionalPortion = x - Math.Truncate(x);
You can then multiply it to get the fractional part represented as an integer at whatever precision you'd like.
Mapping the fractional portion to an integer has some challenges - many floating point numbers cannot be represented as a base-10 integer, and thus may require more digits to represent than an integer can support.
Also, what of the case of numbers like 3.1 and 3.01? Mapping directly to an integer would both result in 1.
Upvotes: 35
Reputation: 115
I saw a and fast way to convert floats/doubles to integers representative of their digits using a bitmask and the GetBits method... It only works if the results fit into a 32 bit integer, but it's still really slick... I can't take credit for it, but have a look:
http://stsdb.com/showthread.php?t=58&p=285&viewfull=1#post285
Upvotes: -1
Reputation: 155872
This will result in some odd unpredictable values.
Floating point numbers are not stored as a decimal - the exponent part is a power of 2, not 10.
This means that some numbers (for instance 1.1) can't be accurately expressed as a float (1.1 ends up something like 1.099999999998)
The problem is that for some numbers the starting number may not be one of these while the decimal part on its own might be.
So your number is x.y
You get the integer part x
You do x.y - x to get 0.y
Sometimes x.y can be expressed as a float and 0.y can't, so rather than get y you'll get some big value with lots of 0s or 9s in it.
@David's 'cheating' way is actually the best way - least prone to this issue anyway.
However I'd look at why you need to do this - floats are great for very fast maths, but a bit rubbish for accuracy. If accuracy is important use a decimal
type instead - that type guarantees that the precise value is stored, but at the cost of slower maths.
Upvotes: 0
Reputation: 11998
Here's another version that also tells how many digits are part of the fractional make-up, which I needed.
public static int GetFractionalPartAsInt(decimal n, out int numOfFractionalDigits)
{
n -= Math.Truncate(n);
n = Math.Abs(n);
int numOfFractionalDigitsValue = 0;
// When n != Math.Truncate(n), we have seen all fractional decimals.
while (n != Math.Truncate(n))
{
n *= 10;
numOfFractionalDigitsValue++;
}
numOfFractionalDigits = numOfFractionalDigitsValue;
return (int)n;
}
It's similar in idea to David's answer (his non-cheating version). However, I used the decimal type instead of double, which slows things down, but improves accuracy. If I convert David's (again, non-cheating version) answer to use a decimal type (in which case his "precision" variable can be changed to the constant zero), my answer runs about 25% faster. Note that I also changed his code to provide the number of fractional digits in my testing.
Upvotes: 2
Reputation: 11998
Try
float n = 3.14f;
int fractionalPart = new System.Version(n.ToString()).Minor;
David's "cheating version" answer doesn't seem to be very popular at the moment, but after looking into this for the better part of the day, I found the System.Version class. It has a constructor which takes a string. Using Reflector, I saw that it works by splitting the string into an array. I ran a test getting the fractional part of the arbitrary number 1234567891.1234567891m. With 1,000,000 iterations, it was 50% faster than the other answer I posted in spite of the fact that I first had to convert the decimal number to a string for the sake of the Version constructor. So David is getting a bad break when using a string conversion concept seems to be a bright way to go. Microsoft did.
Upvotes: 8
Reputation: 3227
The cheating way to do it is:
private Int32 FractionalPart(double n)
{
string s = n.ToString("#.#########", System.Globalization.CultureInfo.InvariantCulture);
return Int32.Parse(s.Substring(s.IndexOf(".") + 1));
}
edit2: OK OK OK OK. Here is the most paranoid never fail version I can come up with. This will return the first 9 digits (or less, if there aren't that many) of the decimal portion of the floating point number. This is guaranteed to not overflow an Int32. We use the invariant culture so we know that we can use a period as the decimal separator.
Upvotes: 5
Reputation: 13917
To suggest something different than the others, an extension method (with a method similar to David's):
public static int GetDecimalAsInt(this float num)
{
string s = n.ToString();
int separator = s.IndexOf(System.Globalization.CultureInfo.CurrentUICulture.NumberFormat.NumberDecimalSeparator);
return int.Parse(s.Substring(separator + 1));
}
// Usage:
float pi = 3.14;
int digits = pi.GetDecimalAsInt();
Edit: I didn't use the "best" answer, because it omitted the hardest part, which is converting an arbitrary decimal number, and did not work for negative numbers. I added the correction requested in David's answer.
Upvotes: 0
Reputation: 54615
Actually all solutions until now are wrong as they don't consider that using Math.Floor()
will do the wrong thing if the value is negative (e.g. Math.Floor(-2.8) -> -3)
double number = -1234.56789;
decimal numberM = Convert.ToDecimal(number);
decimal fraction = Math.Abs(numberM - Math.Truncate(numberM));
int mantissa = Convert.ToInt32((double)fraction * Math.Pow(10, fraction.ToString().Length - 2));
Upvotes: 1
Reputation: 3227
Here's the "noncheating" answer:
double n = 3.14;
const double precision = 0.000001;
// we don't handle negative numbers very well
if (n < 0)
n = 0 - n;
// remove the integer part of n
n -= Math.Floor(n);
int result = 0;
while (n > precision)
{
// move 1/10th digit of n into 1's place
n *= 10;
// get that digit
int digit = (int)Math.Floor(n);
// shift result left and add digit to it
result = result * 10 + digit;
// remove 1's digit from n
n -= digit;
}
// answer is in result;
We use precision instead of 0 to make up for the fact that floating point numbers don't work very well with decimal numbers. You can adjust it to suit your application. This is why I think the "cheating" string way is actually better.
Upvotes: 2
Reputation: 54615
float x = 3.14
int fractionalPortionAsInt = (int) (100 * (x - Math.Floor(x)));
Upvotes: 0