views:

6090

answers:

5

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.

+12  A: 

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!


Noldorin is annoyed that I changed my answer. Let me be clear here--it was Jon's comment to this question that prompted me to change my answer. I gave him credit in the comments for doing so. I have also upvoted every answer in this question that was correct. I did not select the answer, Yaakov did. I did not vote up my question, SO members did.

Here's a friendly guide to getting rep from answers.

1) Answer quickly. Fastest gun rules. You'll see high rep people here post an initial answer, only to come back and modify it if needed. If you don't like that, you don't like SO.

2) The more content you provide the more upvotes you get. While anyone posting a correct answer -- Math.Truncate -- should get upvotes, how do you pick one to be the answer? Often its chosen by upvote total (see 1). But if you provide more information than just the answer, you tend to get more upvotes. Note how I was clear about why the question was flawed--you get overflows when casting a Decimal to an int. That's an incredibly important piece of information that every developer needs to know--an unchecked build would result in hard to track down bugs that this overflow would cause. Its that extra information that helps, And people tend to upvote answers that contain that extra info.

3) If your answer is wrong, fix it. Wrong answers help nobody. The fact is that when I changed my answer, I was already the highest voted answer in here. I could have just left it; it was an acceptable answer, but not the best answer. So after I read Jon's comment I did some reading on the Truncate function. It did, of course, everything that needed to be done here. So I responded to his comment, saying he was right, and updated my answer, marking it as edited. If I'm a scumbag for changing a wrong answer to a right answer and giving credit where credit is due, then I'm a scumbag. But I'm not going to let an incorrect answer stand if I can help it.

Will
"Returns the largest whole number less than or equal to the specified number". So in the case of a negative number, this would be one off (for the second example above, would return -323490, not -323489).
Yaakov Ellis
You actually always want Math.Truncate. Math.Ceiling on a negative number will give you -2 for -1.9.
Jon Grant
Well, I'm not sure about the -2 for -1.9 (the behavior of floor/ceiling for negatives escapes me), but you're 100% right on the Truncate function. Updated.
Will
Math.Truncate was suggested by several of us previously. Also, the down votes were hardly appropiate. I find it rather ill-mannered that you have gone back and edited your post to claim the votes for yourself. Your originally posted solution was arguably less correct than some others.
Noldorin
Its absolutely true, I did post a solution that wasn't 100% correct. I did also explain WHY other solutions were incorrect, which is the reason why I got more votes. Should I have left an incorrect answer go uncorrected? Your suggestion is foolish.
Will
Reputation is not supposed to be a measure of how much knowledge you have, or how smart you are. It's a measure of how much value you provide to the site. If someone edits their answer to make it better, they should get reputation for it.
Matthew Crumley
If people want to give you credit for it, let it be. I would have had no quibble whatsoever if you had not both flamed my post and then used my/another's suggestion as your edited answer. (This is also why some websites only allow posts/deletes to make it clear who answered right first.)
Noldorin
I take your points Will - but I don't think you're really been fair. @Pwninstein's answer was actually correct before yours - he deserves the rep and the answer and this one should be the highest voted non-answer. Given your actual fasted-first answer was not wrong but not best that seems fair.
Keith
Hey, look, I never said anybody didn't DESERVE to get points or be marked the answer (except wrong answers). I didn't vote my own answer up and I didn't mark it as the answer to the question. Don't blame me because I'm beautiful. Somebody else did it to me.
Will
A: 

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.

Noldorin
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.
Will
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.
Noldorin
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.
Will
I simply made an assumption that the OP would be dealing with numbers smaller than the maximum value of an int. I admit this was a wrong assumption, having seen the edited question, though it was not apparent at the time. Regardless, your initial inflammatory comment was hardly necessary.
Noldorin
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.
Will
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.
Noldorin
A: 
int intPart = (int)343564564.4342;
Sani Huttunen
Am I missing something? Why was this voted down?
Malfist
Like @Will suggested, try (int)Decimal.MaxValue
Keith
+1  A: 

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.

Keith
(long)Decimal.MaxValue overflows.
Will
Fair point - I guess that's why Math.Truncate(decimal) returns decimal.
Keith
+9  A: 

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

Pwninstein