106

What is the best way to return the whole number part of a decimal (in c#)? (This has to work for very large numbers that may not fit into an int).

GetIntPart(343564564.4342) >> 343564564
GetIntPart(-323489.32) >> -323489
GetIntPart(324) >> 324

The purpose of this is: I am inserting into a decimal (30,4) field in the db, and want to ensure that I do not try to insert a number than is too long for the field. Determining the length of the whole number part of the decimal is part of this operation.

2
  • You can't get the int part; you can get the whole number part and ditch the fractional part. The whole number part of a Decimal can easily overflow an int and either throw or wrap around, silently killing your code. Commented Jan 26, 2009 at 13:25
  • 1
    Well, that is why this question is not as simple as it seems. I need this to work for very large numbers as reliably as it does for small numbers. However, "whole number" is more accurate than "int" - I will rephrase above. Commented Jan 26, 2009 at 13:32

8 Answers 8

249

By the way guys, (int)Decimal.MaxValue will overflow. You can't get the "int" part of a decimal because the decimal is too friggen big to put in the int box. Just checked... its even too big for a long (Int64).

If you want the bit of a Decimal value to the LEFT of the dot, you need to do this:

Math.Truncate(number)

and return the value as... A DECIMAL or a DOUBLE.

edit: Truncate is definitely the correct function!

7 Comments

So the result is decimal or double that will never have anything after the point but there is not built in object to store the result as an "int" (without decimal places) that seems a bit lame?
@CodeBlend: There isn't much call for designing frameworks around a desire to lose precision.
@CodeBlend: You would still lose precision because you are chopping off the decimal values of a number. Not sure what you're getting at.
Not sure this will work or not. Because Math.Truncate(-5.99999999999999999) returns -6.0 for me...!!
@Bharat Mori: It seems that -5.99999999999999999 is rounded to -6.0 before the truncate. Try with the suffix "m" and it'll work. Math.Truncate(-5.99999999999999999m) gives -5.
|
28

I think System.Math.Truncate is what you're looking for.

Comments

5

Depends on what you're doing.

For instance:

//bankers' rounding - midpoint goes to nearest even
GetIntPart(2.5) >> 2
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -6

or

//arithmetic rounding - midpoint goes away from zero
GetIntPart(2.5) >> 3
GetIntPart(5.5) >> 6
GetIntPart(-6.5) >> -7

The default is always the former, which can be a surprise but makes very good sense.

Your explicit cast will do:

int intPart = (int)343564564.5
// intPart will be 343564564

int intPart = (int)343564565.5
// intPart will be 343564566

From the way you've worded the question it sounds like this isn't what you want - you want to floor it every time.

I would do:

Math.Floor(Math.Abs(number));

Also check the size of your decimal - they can be quite big, so you may need to use a long.

4 Comments

(long)Decimal.MaxValue overflows.
Fair point - I guess that's why Math.Truncate(decimal) returns decimal.
In C#, casting to int doesn't round, so (int)0.6f will be 0, and (int)343564565.5 will end in 5, not 6. Try here: repl.it/repls/LuxuriousCheerfulDistributeddatabase
For a reason you can't use Math.Truncate, you might want to go with Math.Floor and Math.Abs but for negative values you need to change sign like Math.Floor(Math.Abs(number)) * (number > 0 ? 1 : -1). Try dotnetfiddle example
1

I hope help you.

/// <summary>
/// Get the integer part of any decimal number passed trough a string 
/// </summary>
/// <param name="decimalNumber">String passed</param>
/// <returns>teh integer part , 0 in case of error</returns>
private int GetIntPart(String decimalNumber)
{
    if(!Decimal.TryParse(decimalNumber, NumberStyles.Any , new CultureInfo("en-US"), out decimal dn))
    {
        MessageBox.Show("String " + decimalNumber + " is not in corret format", "GetIntPart", MessageBoxButtons.OK, MessageBoxIcon.Error);
        return default(int);
    } 

    return Convert.ToInt32(Decimal.Truncate(dn));
}

Comments

0

You just need to cast it, as such:

int intPart = (int)343564564.4342

If you still want to use it as a decimal in later calculations, then Math.Truncate (or possibly Math.Floor if you want a certain behaviour for negative numbers) is the function you want.

6 Comments

This is wrong wrong wrong. If the result is greater than what an Int32 can hold, it will either throw an exception or (even worse!!!) silently overflow and wrap back around, giving you a completely incorrect result without you even knowing about it.
No, it's not wrong. It many not be valid for very large decimals/floating point values, but it is perfectly fine for most situations. Numbers are very often constrained to be low enough when coding, so this need not be a problem. Also, I provided a Math.Truncate solution that works for all values.
I see why you're pissed at me. The fact is that your answer is wrong. You're telling him to take a chance on it not breaking because, hey, lots of numbers are small. Its a foolish risk to take. You should edit your answer and remove everything but Math.Truncate as its the only correct part.
You know what they say about ASSUME. Also, your assumption is particularly awful. Is that inflammatory? I guess you could say that. You can also say that telling somebody to do something foolish that will cause them problems down the road is inflammatory as well, if not flat out unethical.
Indeed that would be wrong if I intended to give a misleading answer. As it were, I was simply trying to help. If I am guilty of slightly misunderstanding or not fully appreciating the question, that's fair enough - it's no crime. So why are we arguing now? We all agree Truncate is the right answer.
|
0

Very easy way to separate value and its fractional part value.

double  d = 3.5;
int i = (int)d;
string s = d.ToString();
s = s.Replace(i + ".", "");

s is fractional part = 5 and
i is value as integer = 3

1 Comment

See the top answer above. This doesn't work because (int)Decimal.MaxValue will overflow.
0
   Public Function getWholeNumber(number As Decimal) As Integer
    Dim round = Math.Round(number, 0)
    If round > number Then
        Return round - 1
    Else
        Return round
    End If
End Function

2 Comments

The accepted answer—posted more than eight years ago—explains why this answer is wrong. The range of decimal is far greater than that of int. Also, this is not a VB question.
@JoeFarrell - if you feel the answer is wrong, you could consider downvoting it in addition to just leaving a comment to the effect. Don't, however, flag it (not that I'm saying you have). It's an attempt to answer the question. It may be in the wrong language, it may be wrong even in VB, but it is an attempt. See, for example, "When an answer answers the wrong question, is it Not An Answer?".
-1

Forgetting the meaning of the term: "Whole Number" seems common in the answers, and in the Question.

Getting the whole number from the number: 4 is simple:

1 x 4 = 4 <- A Whole Number! The first Whole Number!
2 x 4 = 8 <- A Whole Number!
3 x 4 = 12 <- A Whole Number!

Rounding a Number, to get a Whole Number is a cheats method of getting the Whole Numbers! Rounding it removing the Non-Whole Number part of the Number!

1.3 x 4 = 5.2 <- NOT a Whole Number!
1 x 343564564.4342 <- NOT a Whole Number!

Its important to understand what a Whole Number is!

4 / 1 = 4 <- A Whole Number!
4 / 2 = 2 <- A Whole Number!
4 / 3 = 1.333 recurring  <- NOT A Whole Number!

Please ask, and answer the questions with a bit more Accuracy Peeps...

double A = Math.Abs(343564564.4342);
double B = Math.Floor(343564564.4342);
double C = Math.Ceiling(343564564.4342);
double D = Math.Truncate(343564564.4342);

Returns:

A = 343564564.4342
B = 343564564
C = 343564565
D = 343564564

or:

double E = Math.Round(343564564.4342, 0);
E = 343564564

Is a Mathematical Function, thus changing the Number, and not working with Whole Numbers. Your Rounding Non-Whole Numbers!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.