103

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.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Yaakov Ellis
  • 40,752
  • 27
  • 129
  • 174
  • 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. –  Jan 26 '09 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. – Yaakov Ellis Jan 26 '09 at 13:32

8 Answers8

240

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!

  • 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? – Paul C May 11 '14 at 21:48
  • @CodeBlend: There isn't much call for designing frameworks around a desire to lose precision. –  May 12 '14 at 13:01
  • @CodeBlend: You would still lose precision because you are chopping off the decimal values of a number. Not sure what you're getting at. –  May 12 '14 at 15:02
  • Not sure this will work or not. Because Math.Truncate(-5.99999999999999999) returns -6.0 for me...!! – Bharat Mori Oct 19 '17 at 18:56
  • @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. – Henry Feb 23 '18 at 10:30
  • @Coops: try (int)Math.Truncate(number) – Simon Sultana Nov 30 '20 at 19:25
  • @Simon this was 10 years ago :) ... wow a whole decade since I wrote that comment, blimey – Paul C Dec 08 '20 at 11:57
27

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

Mark Carpenter
  • 17,445
  • 22
  • 96
  • 149
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.

Keith
  • 150,284
  • 78
  • 298
  • 434
  • (long)Decimal.MaxValue overflows. –  Jan 26 '09 at 14:12
  • Fair point - I guess that's why Math.Truncate(decimal) returns decimal. – Keith Jan 26 '09 at 22:44
  • 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: https://repl.it/repls/LuxuriousCheerfulDistributeddatabase – sschmidTU Feb 27 '20 at 15:11
  • 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](https://dotnetfiddle.net/eC7ZYa) – Filip Golewski Jan 15 '21 at 01:31
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));
}
adiga
  • 34,372
  • 9
  • 61
  • 83
luka
  • 605
  • 8
  • 15
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

Manos Nikolaidis
  • 21,608
  • 12
  • 74
  • 82
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
  • 1
    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. – Joe Farrell May 09 '17 at 15:27
  • @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?](https://meta.stackexchange.com/a/185162/284827)". – Wai Ha Lee May 09 '17 at 21:15
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.

Noldorin
  • 144,213
  • 56
  • 264
  • 302
  • 5
    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. –  Jan 26 '09 at 13:22
  • 2
    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 Jan 26 '09 at 13:34
  • 2
    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. –  Jan 26 '09 at 18:38
  • 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 Jan 27 '09 at 17:33
  • 1
    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. –  Jan 28 '09 at 15:08
  • 1
    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 Jan 29 '09 at 12:30
-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!

Rusty Nail
  • 2,692
  • 3
  • 34
  • 55