Rounding to at least 2 to 4 decimal places - c#

How can I round a decimal to at least 2 decimal places and have it kept as a decimal?
I know I can do this, but it has a code smell.
var myResult = Decimal.Parse(myDecimal.ToString("0.00##"));
These are the expected results.
0.028 -> 0.028
0.02999 -> 0.03

You can use
Math.Round(myResult, 4);

a decimal doesnt (or, perhaps shouldn't) have a "number of decimal places" until you format it for display.

decimal.Round(Decimal myDecimal, int digits#);
EX:
decimal.Round(100.555555, 2); // result = 100.56
Or
Math.Round(Decimal myDecimal, int digits#);
EX:
Math.Round(100.555555, 2); // result = 100.56

Check out the Math.Round(decimal, Int32) method:
Math.Round(myDecimal, 4);

try to use f format specifier
var myResult = Decimal.Parse(myDecimal.ToString("f"));

Related

String to Decimal with 2 decimal places always

I have a string that is to be converted to decimal. The string could be entered with no decimal places e.g. "123" or 2 decimal places, e.g. "123.45" or somewhat awkwardly, 1 decimal place "123.3". I want the number displayed (the Property invoice.Amount which is type decimal) with 2 decimal places. The code below does that. I think it could be written better though. How?
decimal newDecimal;
bool isDecimal = Decimal.TryParse(InvoiceDialog.InvoiceAmount, out newDecimal);
string twoDecimalPlaces = newDecimal.ToString("########.00");
invoice.Amount = Convert.ToDecimal(twoDecimalPlaces);
In part, I don't understand, for the string formatting "########.00", what # does and what 0 does. E.g. how would it be different if it were "########.##"?
# is an optional digit when 0 is a mandatory digit
For instance
decimal d = 12.3M;
// d with exactly 2 digits after decimal point
Console.WriteLine(d.ToString("########.00"));
// d with at most 2 digits after decimal point
Console.WriteLine(d.ToString("########.##"));
Outcome:
12.30 // exactly 2 digits after decimal point: fractional part padded by 0
12.3 // at most 2 digits after decimal point: one digit - 3 - is enough
Basically, # means optional, where as 0 is mandatory.
As for better explanation, if you put # then if number is available to fullfil the placeholder it'll be added if not it'll be ignored.
Putting 0 however is different as it'll always put a value in for you.
You can combine the two together.
String.Format("{0:0.##}", 222.222222); // 222.22
String.Format("{0:0.##}", 222.2); // 222.2
String.Format("{0:0.0#}", 222.2) // 222.2
The "#" is optional while the "0" will show either the number or 0.
For example,
var x = 5.67;
x.ToString("##.###"); // 5.67
x.ToString("00.000"); // 05.670
x.ToString("##.##0"); // 5.670
If you just care about how many decimal places you have, I would recommend using
x.ToString("f2"); // 5.67
to get 2 decimal spots.
More information can be found at http://www.independent-software.com/net-string-formatting-in-csharp-cheat-sheet.html/.
You don't need to convert the decimal to string to do the formatting for 2 decimal places. You can use the decimal.Round method directly. You can read about it here.
So your code can be converted to
decimal newDecimal;
Decimal.TryParse(s, out newDecimal);
newDecimal = decimal.Round(newDecimal, 2, MidpointRounding.AwayFromZero);
The above code also be simplified with C# 7.0 declaration expression as
Decimal.TryParse(s, out decimal newDecimal);
newDecimal = decimal.Round(newDecimal, 2, MidpointRounding.AwayFromZero);
Now newDecimal will have have a value with 2 precision.
You can check this live fiddle.

decimal rounding to 2 precision such that X is converted to X.00 C# [duplicate]

This question already has answers here:
How do I display a decimal value to 2 decimal places?
(19 answers)
Closed 7 years ago.
First of all this is not a duplicate question my need is to have 2 precision decimal always
e.g.
2 should be converted as 2.00
0 should be converted as 0.00
0.5 should be converted as 0.50
output number has to be decimal
Things i had tried
decimal val = 0.5000M
decimal d = Math.Round(val, 2);//gives 0.5 i need 0.50
NOTE: I am not looking to convert decimal to string as i need to send it as a soap request which accepts decimal value only, so i dont have flexibility to convert it to string.
Update
below code as answered by Jakub Lortz works fine though it may look complex
solution 1 by Jakub Lortz
decimal twoPoint00 = new Decimal(200, 0, 0, false, 2);
decimal twoPoint0 = new Decimal(20, 0, 0, false, 1);
Console.WriteLine(twoPoint00) // prints 2.00
Console.WriteLine(twoPoint0) // prints 2.0
solution 2 by Bogdan
he had given very simple solution which will also work
decimal val = 0.5000M;
string result = string.Format("{0:f2}", val);
decimal d;
Decimal.TryParse(result, out d);
There is a constructor of Decimal that allows you to specify the scale:
public Decimal(
int lo,
int mid,
int hi,
bool isNegative,
byte scale
)
For example:
decimal twoPoint00 = new Decimal(200, 0, 0, false, 2);
decimal twoPoint0 = new Decimal(20, 0, 0, false, 1);
Console.WriteLine(twoPoint00) // prints 2.00
Console.WriteLine(twoPoint0) // prints 2.0
This constructor is used by the C# compiler to create decimals from literals, so you can easily check it in the compiled IL.
Edit
To convert a decimal value to a representation with a set precision, you would first have to use Decimal.GetBits method to get its internal representation. Then modify the values (maybe using BigInteger to work with the whole 96-bits value as a whole?) and create a new decimal.
Seems like a lot of job, with a lot of possible bugs. I'd start by checking the solution proposed in Bogdan's answer - ToString() + Parse(). It seems to work correctly and is very simple.
I guess you want to convert the decimal into a string. Try it like that:
string result = d.ToString("#.00");
decimal val = 0.5000M;
string result = string.Format("{0:f2}", val);
decimal d;
Decimal.TryParse(result, out d);
#Jakub Lortz - Thank you for the suggestions:
decimal val = 0.5000M;
string formattedVal = val.ToString("F2");
decimal result = Decimal.Parse(formattedVal);

change numeric base of negative numbers

How to convert a negative decimal number to a hexadecimal one?
I know how to convert positive numbers from one base to another.
The widows calculator returns a huge number something like FFFFFFFFFFFFCFC7 in hex for -12345 in dec.The value that I need to process further more is CFC7, but I don't know how to get it using C#.
Not exactly sure if that is what you need:
int i = -12345;
string test = i.ToString("X"); // test will hold: "FFFFCFC7"
int HexI = Convert.ToInt32(test, 16); // HexI will hold: -12345
Try this:
int decimalValue = -12345;
string hexVal = String.Format("{0:x2}", decimalValue);

Determine the decimal precision of an input number

We have an interesting problem were we need to determine the decimal precision of a users input (textbox). Essentially we need to know the number of decimal places entered and then return a precision number, this is best illustrated with examples:
4500 entered will yield a result 1
4500.1 entered will yield a result 0.1
4500.00 entered will yield a result 0.01
4500.450 entered will yield a result 0.001
We are thinking to work with the string, finding the decimal separator and then calculating the result. Just wondering if there is an easier solution to this.
I think you should just do what you suggested - use the position of the decimal point. Obvious drawback might be that you have to think about internationalization yourself.
var decimalSeparator = NumberFormatInfo.CurrentInfo.CurrencyDecimalSeparator;
var position = input.IndexOf(decimalSeparator);
var precision = (position == -1) ? 0 : input.Length - position - 1;
// This may be quite unprecise.
var result = Math.Pow(0.1, precision);
There is another thing you could try - the Decimal type stores an internal precision value. Therefore you could use Decimal.TryParse() and inspect the returned value. Maybe the parsing algorithm maintains the precision of the input.
Finally I would suggest not to try something using floating point numbers. Just parsing the input will remove any information about trailing zeros. So you have to add an artifical non-zero digit to preserve them or do similar tricks. You might run into precision issues. Finally finding the precision based on a floating point number is not simple, too. I see some ugly math or a loop multiplying with ten every iteration until there is no longer any fractional part. And the loop comes with new precision issues...
UPDATE
Parsing into a decimal works. Se Decimal.GetBits() for details.
var input = "123.4560";
var number = Decimal.Parse(input);
// Will be 4.
var precision = (Decimal.GetBits(number)[3] >> 16) & 0x000000FF;
From here using Math.Pow(0.1, precision) is straight forward.
UPDATE 2
Using decimal.GetBits() will allocate an int[] array. If you want to avoid the allocation you can use the following helper method which uses an explicit layout struct to get the scale directly out of the decimal value:
static int GetScale(decimal d)
{
return new DecimalScale(d).Scale;
}
[StructLayout(LayoutKind.Explicit)]
struct DecimalScale
{
public DecimalScale(decimal value)
{
this = default;
this.d = value;
}
[FieldOffset(0)]
decimal d;
[FieldOffset(0)]
int flags;
public int Scale => (flags >> 16) & 0xff;
}
Just wondering if there is an easier
solution to this.
No.
Use string:
string[] res = inputstring.Split('.');
int precision = res[1].Length;
Since your last examples indicate that trailing zeroes are significant, I would rule out any numerical solution and go for the string operations.
No, there is no easier solution, you have to examine the string. If you convert "4500" and "4500.00" to numbers, they both become the value 4500 so you can't tell how many non-value digits there were behind the decimal separator.
As an interesting aside, the Decimal tries to maintain the precision entered by the user. For example,
Console.WriteLine(5.0m);
Console.WriteLine(5.00m);
Console.WriteLine(Decimal.Parse("5.0"));
Console.WriteLine(Decimal.Parse("5.00"));
Has output of:
5.0
5.00
5.0
5.00
If your motivation in tracking the precision of the input is purely for input and output reasons, this may be sufficient to address your problem.
Working with the string is easy enough.
If there is no "." in the string, return 1.
Else return "0.", followed by n-1 "0", followed by one "1", where n is the length of the string after the decimal point.
Here's a possible solution using strings;
static double GetPrecision(string s)
{
string[] splitNumber = s.Split('.');
if (splitNumber.Length > 1)
{
return 1 / Math.Pow(10, splitNumber[1].Length);
}
else
{
return 1;
}
}
There is a question here; Calculate System.Decimal Precision and Scale which looks like it might be of interest if you wish to delve into this some more.

Best way to get whole number part of a Decimal number

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.
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!
I think System.Math.Truncate is what you're looking for.
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.
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.
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));
}
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
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
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!

Categories