Best way to get whole number part of a Decimal number
Asked Answered
E

8

104

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.

Esma answered 26/1, 2009 at 12:59 Comment(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.Bruise
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.Esma
B
242

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!

Bruise answered 26/1, 2009 at 13:3 Comment(7)
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?Dachi
@CodeBlend: There isn't much call for designing frameworks around a desire to lose precision.Bruise
@CodeBlend: You would still lose precision because you are chopping off the decimal values of a number. Not sure what you're getting at.Bruise
Not sure this will work or not. Because Math.Truncate(-5.99999999999999999) returns -6.0 for me...!!Beckham
@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.Ishmul
@Coops: try (int)Math.Truncate(number)Glasswork
@Simon this was 10 years ago :) ... wow a whole decade since I wrote that comment, blimeyDachi
D
28

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

Danndanna answered 26/1, 2009 at 13:32 Comment(0)
G
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.

Gisele answered 26/1, 2009 at 13:26 Comment(4)
(long)Decimal.MaxValue overflows.Bruise
Fair point - I guess that's why Math.Truncate(decimal) returns decimal.Gisele
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/LuxuriousCheerfulDistributeddatabaseCubicle
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 exampleNigelniger
O
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));
}
Orchid answered 24/6, 2019 at 7:44 Comment(0)
W
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.

Wilt answered 26/1, 2009 at 13:3 Comment(6)
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.Bruise
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.Wilt
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.Bruise
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.Wilt
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.Bruise
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.Wilt
P
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

Precritical answered 17/10, 2015 at 12:37 Comment(1)
See the top answer above. This doesn't work because (int)Decimal.MaxValue will overflow.Esma
M
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
Morgun answered 9/5, 2017 at 14:49 Comment(2)
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.Handstand
@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?".Tollgate
B
-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!

Blacksnake answered 22/2, 2023 at 3:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.