How do you round up to the nearest even cent?.
So, for the following decimals,
I want to round and display dollar amount:
1230.3092 => $1230.30
221.9672 => $221.96
12345.6808 => 12345.68
I've tried this
Math.Round(value, 2, MidpointRounding.ToEven)
decimal.Round(value, 2, MidpointRounding.ToEven)
but some reason it rounds up.
You want this:
(0.02m / 1.00m) * decimal.Round(value * (1.00m / 0.02m))
value * (1.00m / 0.02m) is the amount of money in terms of a "2-cents" unit. Round in that space to an integer, and then convert back to dollars.
MidpointRounding should be used to determine how you want, for example, 100.01m to round, since it is halfway between 100.00m and 100.02m.
You're trying to follow nonstandard rules for rounding, so the built-in functions won't do what you are looking for. Either overload the methods or create your own - it looks like you just need to truncate to two decimals, then add one if the result is odd (or floor then add one).
Related
When using decimal, why the behaviour of rounding is always the same?
No matter if I use MidpointRounding.AwayFromZero or not it always gives 1.04. In the first case, shouldn't the output be 1.03?
Console.WriteLine(decimal.Round(1.035m, 2));
Console.WriteLine(decimal.Round(1.035m, 2, MidpointRounding.AwayFromZero));
https://github.com/dotnet/corefx/blob/664d98b3dc83a56e1e6454591c585cc6a8e19b78/src/Common/src/CoreLib/System/Decimal.cs#L612
https://github.com/dotnet/corefx/blob/61d792e202d039c304c4f04ad816a57688f32fd4/src/Common/src/CoreLib/System/Decimal.DecCalc.cs#L2429-L2444
No:
This method [Round(decimal d, int decimals)] is equivalent to calling the Round(Decimal, Int32, MidpointRounding) method with a mode argument of MidpointRounding.ToEven.
When d is exactly halfway between two rounded values, the result is the rounded value that has an even digit in the far right decimal position. For example, when rounded to two decimals, the value 2.345 becomes 2.34 and the value 2.355 becomes 2.36.
So when rounding 1.035 to even, it becomes 1.04 because 4 is even and 3 is not.
The default rounding method is MidpointRounding.ToEven, so when choosing whether to round to either 1.03 or 1.04, it chooses the one with the even number at the end, 1.04.
As the MSDN said:
public static decimal Round(
decimal d,
int decimals
)
decimals : A value from 0 to 28 that specifies the number of decimal places to
round to.
You want to round at 2 places, it must 1.04
This is seems expected behavior to me when rounding up a decimal.
Ex:
1.035 => 1.040 produce with two decimal place 1.04
1.033 => 1.030 produce with two decimal place 1.03
Isn't the default rounding to round up? in this case the 5 gets rounded up and carried over...
By default, the Round method uses the rounding to nearest convention. The following table lists the overloads of the Round method and the rounding convention that each uses.
https://learn.microsoft.com/en-us/dotnet/api/system.math.round?view=netframework-4.7.2
Most probably, it's a duplicate, and I don't understand some basics, and thus deserve a downvote, but it just drives me crazy.
I'm using C# and .NET Core on Mac OS.
I have a float 9.74999 and I want to round it to one digit after the dot and get 9.8 (like it should work according to what I remember from primary school: 9.749 -> 9.75 -> 9.8 -> 10).
I tried this:
float rounded = (float)Math.Round(9.74999f, 1, MidpointRounding.AwayFromZero);
// rounded = 9.7
Why it's not 9.8? So, it just takes the digit of interest (7) and the following one (4) and doesn't care about the rest (999)?
And this construction actually gives me what I want:
float rounded = (float)Math.Round(
(float)Math.Round(9.74999f, 2, MidpointRounding.AwayFromZero),
1,
MidpointRounding.AwayFromZero
);
// rounded = 9.8
So, the only way I can get 9.8 out of 9.74999 is by performing two Round operations:
First Round with 2 decimals;
Second Round with the result of the first one and 1 decimal.
Is this a proper way to do it?
Update
I see now that at school we were given a concept of double (triple, etc) rounding (https://en.wikipedia.org/wiki/Rounding#Double_rounding), which accumulates error on each step, and that's not the rounding that is used by Math.Round, so that's why I am not getting what I expect to get (9.749 -> 9.75 -> 9.8).
But I do need to perform exactly such a "consequential" rounding, going from right to left, digit by digit. So, I guess, there is no standard function for that, and I need to implement it myself.
In Math, 9.74999 rounds to 9.7. The code is using math.
Edit with less snark: 9.75 and greater will around to 9.8. Anything less than 9.75 (and greater than or equal to 9.65) will round to 9.7. I think you're confusing yourself and thinking that the 999 will round the .74 to a .75, but that's not the case.
In testing as to why my program is not working as intended, I tried typing the calculations that seem to be failing into the immediate window.
Math.Floor(1.0f)
1.0 - correct
However:
200f * 0.005f
1.0
Math.Floor(200f * 0.005f)
0.0 - incorrect
Furthermore:
(float)(200f * 0.005f)
1.0
Math.Floor((float)(200f * 0.005f))
0.0 - incorrect
Probably some float loss is occuring, 0.99963 ≠ 1.00127 for example.
I wouldn't mind storing less pricise values, but in a non lossy way, for example if there were a numeric type that stored values as integers do, but to only three decimal places, if it could be made performant.
I think probably there is a better way of calculating (n * 0.005f) in regards to such errors.
edit:
TY, a solution:
Math.Floor(200m * 0.005m)
Also, as I understand it, this would work if I didn't mind changing the 1/200 into 1/256:
Math.Floor(200f * 0.00390625f)
The solution I'm using. It's the closest I can get in my program and seems to work ok:
float x = ...;
UInt16 n = 200;
decimal d = 1m / n;
... = Math.Floor((decimal)x * d)
Floats represent numbers as fractions with powers of two in the denominator. That is, you can exactly represent 1/2, or 3/4, or 19/256. Since .005 is 1/200, and 200 is not a power of two, instead what you get for 0.005f is the closest fraction that has a power of two on the bottom that can fit into a 32 bit float.
Decimals represent numbers as fractions with powers of ten in the denominator. Like floats, they introduce errors when you try to represent numbers that do not fit that pattern. 1m/333m for example, will give you the closest number to 1/333 that has a power of ten as the denominator and 29 or fewer significant digits. Since 0.005 is 5/1000, and that is a power of ten, 0.005m will give you an exact representation. The price you pay is that decimals are much larger and slower than floats.
You should always always always use decimals for financial calculations, never floats.
The problem is that 0.005f is actually 0.004999999888241291046142578125... so less than 0.005. That's the closest float value to 0.005. When you multiply that by 200, you end up with something less than 1.
If you use decimal instead - all the time, not converting from float - you should be fine in this particular scenario. So:
decimal x = 0.005m;
decimal y = 200m;
decimal z = x * y;
Console.WriteLine(z == 1m); // True
However, don't assume that this means decimal has "infinite precision". It's still a floating point type with limited precision - it's just a floating decimal point type, so 0.005 is exactly representable.
If you cannot tolerate any floating point precision issues, use decimal.
http://msdn.microsoft.com/en-us/library/364x0z75.aspx
Ultimately even decimal has precision issues (it allows for 28-29 significant digits). If you are working in it's supported range ((-7.9 x 10^28 to 7.9 x 10^28) / (100^28)), you are quite unlikely to be impacted by them.
how to make the Rounded number ?
Example : 3341.48 to 3342.00
It seems you always want to round up here. In that case use
Math.Ceiling(3341.48)
This will return 3342.
If you want to round towards the nearest whole number, use
Math.Round(3341.48)
This will return 3341. Note that Bankers roundingis the default setting here, that might cause some unexpected result for rounding X.50.
If you want 3341.48 to round up to 3342, it sounds like you might want Math.Ceiling:
decimal m = 3341.48m;
decimal roundedUp = Math.Ceiling(m);
This will always round up - so 3341.0000001 would still round to 3342, for example. If that's not what you're after, please specify the circumstances in which you want it to round up, and those in which you want it to round down instead.
Note that this will round up to 3342, not 3342.00 - it doesn't preserve the original precision, because you've asked for an integer value by using Math.Ceiling.
It's relatively unusual to then want to force the precision to 2, but you could divide by 100 and then multiply by 100 again, if necessary. Alternatively, if you only need this for output you should look into formatting the result appropriately rather than changing the value.
Use Math.Round(number) if you want to round number to the nearest integer.
Use Math.Round(number,digits) if you want to round number to a specified number of fractional digits.
If you want to round to lower/higer value use Math.Floor(number) / Math.Ceiling(number) instead.
To round monetary amounts to 5 cents:
amount = 20 * int(amount / 20)
I'm having an issue with a query I wrote where for some reason the variable that I'm using to store a decimal value in returns 6 values after the decimal place (they're mostly 0).
I have tried the following (and different combinations using Math.Round) with no luck.
Sales =
(from invhed in INVHEAD
... // Joins here
orderby cust.State ascending
select new Sale
{
InvoiceLine = inv.InvoiceLine,
InvoiceNum = inv.InvoiceNum,
...
NetPrice = Math.Round((inv.ExtPrice - inv.Discount) * (Decimal) (qsales.RepSplit / 100.0), 2, MidpointRounding.ToEven),
}).ToList<Sale>();
The NetPrice member has values like 300.000000, 5000.500000, 3245.250000, etc.
Any clues? I can't seem to find anything on this issue online.
EDIT:
Decimal.Round did the trick (I forgot to mention that the NetPrice member was a Decimal type). See my answer below.
System.Decimal preserves trailing zeroes by design. In other words, 1m and 1.00m are two different decimals (though they will compare as equal), and can be interpreted as being rounded to different number of decimal places - e.g. Math.Round(1.001m) will give 1m, and Math.Round(1.001m, 2) will give 1.00m. Arithmetic operators treat them differently - + and - will produce a result that has the the same number of places as the operand which has most of them (so 1.50m + 0.5m == 1.10m), and * and / will have the sum of number of places for their operands (so 1.00m * 1.000m == 1.00000m).
Trailing zeros can appear in the output of .ToString on the decimal type. You need to specify the number of digits after the decimal point you want display using the correct format string. For example:-
var s = dec.ToString("#.00");
display 2 decimal places.
Internally the decimal type uses an integer and a decimal scaling factor. Its the scaling factor which gives rise to the trailing 0. If you start off with a decimal type with a scaling factor of 2, you will get 2 digits after the decimal point even if they are 0.
Adding and substracting decimals will result in a decimal which has a scaling factor of the is the maximum of the decimals involved. Hence subtracting one decimal with a scaling factor of 2 from another with the same the resulting decimal also has a factor of 2.
Multiplication and division of decimals will result in a decimal that has a scaling factor that is the sum of the scaling factors of the two decimal operands. Multiplying decimals with a scaling factor of 2 results in a new decimal that has a scaling factor of 4.
Try this:-
var x = new decimal(1.01) - (decimal)0.01;
var y = new decimal(2.02) - (decimal)0.02;
Console.WriteLine(x * y * x * x);
You get 2.00000000.
I got it to work using Decimal.Round() with the same arguments as before. :)
Looks like the issue is somewhat on the trail of what Pavel was saying, where Decimal types behave differently and it would seem Math.Round doesn't quite work with them as one would expect it to...
Thanks for all the input.