I'm performing some calculations and inserting the result into a database.
My problem is, that the answers I'm getting seem to be rounding down rather than up. This might not seem important but over the course of a lot of sales, the cents start adding up!!
Decimal pubCut = rrp * (percentageCutD / 100);
Decimal retCut = rrp * retailerCut;
Decimal edcut = rrp * edpercentage;
I'll be honest, I'm rubbish with figures and the whole Maths function was something I tried to avoid in college. Can anyone tell me how I can get these figures to round up as opposed to down?
Use Math.Ceiling() method.
double[] values = {7.03, 7.64, 0.12, -0.12, -7.1, -7.6};
Console.WriteLine(" Value Ceiling Floor\n");
foreach (double value in values)
Console.WriteLine("{0,7} {1,16} {2,14}",
value, Math.Ceiling(value), Math.Floor(value));
// The example displays the following output to the console:
// Value Ceiling Floor
//
// 7.03 8 7
// 7.64 8 7
// 0.12 1 0
// -0.12 0 -1
// -7.1 -7 -8
// -7.6 -7 -8
Your problem is this
(percentageCutD / 100)
Since 100 is an int, it will perform integer division, so that 150/100 becomes 1. You can fix this by maksing sure that 100 is a decimal since you want a decimal as result in the end. Change your code to.
(percentageCutD / 100D)
However, if you always want to round values even like 1.1 up to 2, then you will have to use Math.Ceiling to accomplish this. If you for some reason want to avoid the Math class (I can't see why you want to do it, you can add 1 to the result and cast it to an int to effectively round up to the nearest integer.
.Net's Math.Round function uses something commonly referred to as banker's rounding which works by rounding .5 to the nearest even integer, ie 22.5 = 22 and 23.5 = 24. This gives a more even distribution when rounding.
It's also worth noting the SQL server doesn't use bankers rounding
Your incoming percentages probably don't add to 100 %. Compute one of your fractions by substracting the sum of the other fractions from the total.
var v = 100D;
var p1 = 33D/100;
var p2 = 33D/100;
var p3 = 33D/100;
var v1 = p1*v;
var v2 = p2*v;
var v3 = p3*v;
var sum = v1 + v2 + v3;
Unfortunately sum is 99 and not 100.
You can compute v3 like this instead:
var v3 = v - (v1 + v2);
Or better fix the rounding error in the incoming percentages:
Related
I Have to get amounts as below
1099948.275 = 1099948.27,
1099948.276 = 1099948.28,
1099948.274 = 1099948.27
when I use Math.Round(1_099_948.275, 2) I am getting output as 1099948.28 but not 1099948.27. I even tried with awayfromzero and toeven and none of them are working. Any idea?
Is there way to find 3rd number after decimal and if it is 5 just take first two number after decimal else go with mat.round?
This is not how rounding works, neither in C# nor in Math.
By default, anything 5 or more is rounded up, and anything less than 5 is rounded down. This is called "Away from Zero" rounding.
Rounding away from zero
Midpoint values are rounded to the next number away from zero. For example, 3.75 rounds to 3.8, 3.85 rounds to 3.9, -3.75 rounds to -3.8, and -3.85 rounds to -3.9. This form of rounding is represented by the MidpointRounding.AwayFromZero enumeration member.
The other mode is rounding to the closest even number. This is half of what you're looking for. In this way, when something ends with a "5" (the midpoint), that number is rounded to the closest even number, which could be up or down. This is done to distribute out the chances a rounding affects one particular party in a monetary transaction.
Rounding to nearest even, or banker's rounding
Midpoint values are rounded to the nearest even number. For example, both 3.75 and 3.85 round to 3.8, and both -3.75 and -3.85 round to -3.8. This form of rounding is represented by the MidpointRounding.ToEven enumeration member.
The source for both of the above quotes are on the Math.Round documentation page.
There is no supported rounding system that always rounds a 5 down. You'd need to inspect the value first to see if the last digit is a 5, then truncate the digit rather than attempt rounding.
One could implement your own rounding strategy:
public static double RoundDown(double value, int precision)
{
var rounded = Math.Ceiling(value * Math.Pow(10,precision) - 0.5) / Math.Pow(10,precision);
return rounded;
}
public static decimal RoundDown(decimal value, int precision)
{
decimal scale = 1;
for(int i=0;i<precision;i++)
{
scale *= 10;
}
var rounded = Math.Ceiling(value * scale - 0.5M) / scale;
return rounded;
}
Usage:
var values = new double[] {1099948.275, 1099948.276, 1099948.274 };
Console.WriteLine("double:");
foreach(var value in values)
{
var rounded = RoundDown(value, 2);
Console.WriteLine($"{value} = {rounded}");
}
Console.WriteLine("decimal:");
var values_m = new decimal[] {1099948.275M, 1099948.276M, 1099948.274M };
foreach(var value in values_m)
{
var rounded = RoundDown(value, 2);
Console.WriteLine($"{value} = {rounded}");
}
double:
1099948.275 = 1099948.27
1099948.276 = 1099948.28
1099948.274 = 1099948.27
decimal:
1099948.275 = 1099948.27
1099948.276 = 1099948.28
1099948.274 = 1099948.27
You can get what you need by subtracting 0.001 from the number before rounding it
Math.Round(1099948.275-0.001,2)
Edit:
to answer some of the comments
Math.Round(1099948.270-0.001,2) will still give the correct answer which is 1099948.27
similarly for any other number.
negative numbers may need to be handled differently depending on requirements.
Is there a simple way in c# to round a decimal to the nearest quarter i.e. x.0, x.25, x.50 x.75
for example 0.21 would round to 0.25, 5.03 would round to 5.0
Thanks in advance for any help.
Multiply it by four, round it as you need to an integer, then divide it by four again:
x = Math.Round (x * 4, MidpointRounding.ToEven) / 4;
The various options for rounding, and their explanations, can be found in this excellent answer here :-)
Alternatively, you can use UltimateRoundingFunction given in this blog:
http://rajputyh.blogspot.in/2014/09/the-ultimate-rounding-function.html
//amountToRound => input amount
//nearestOf => .25 if round to quater, 0.01 for rounding to 1 cent, 1 for rounding to $1
//fairness => btween 0 to 0.9999999___.
// 0 means floor and 0.99999... means ceiling. But for ceiling, I would recommend, Math.Ceiling
// 0.5 = Standard Rounding function. It will round up the border case. i.e. 1.5 to 2 and not 1.
// 0.4999999... non-standard rounding function. Where border case is rounded down. i.e. 1.5 to 1 and not 2.
// 0.75 means first 75% values will be rounded down, rest 25% value will be rounded up.
decimal UltimateRoundingFunction(decimal amountToRound, decimal nearstOf, decimal fairness)
{
return Math.Floor(amountToRound / nearstOf + fairness) * nearstOf;
}
Call below for standard rounding. i.e. 1.125 will be rounded to 1.25
UltimateRoundingFunction(amountToRound, 0.25m, 0.5m);
Call below for rounding down border values. i.e. 1.125 will be rounded to 1.00
UltimateRoundingFunction(amountToRound, 0.25m, 0.4999999999999999m);
So called "Banker's Rounding" is not possible with UltimateRoundingFunction, you have to go with paxdiablo's answer for that support :)
An extension method based on this answer.
namespace j
{
public static class MathHelpers
{
public static decimal RoundToNearestQuarter(this decimal x)
{
return Math.Round(x * 4, MidpointRounding.ToEven) / 4;
}
}
}
I want to round off a decimal number to the next higher number nn c#.
for example:
23.3 should become 24
25.8 should become 26
26.1 should become 27
currently i am using this code but it is not fulfilling my requirements.
double pages = Math.Floor((float)anyNumber / 5);
Math.Floor rounds down, use Math.Ceiling to round up:
double pages = Math.Ceiling( anyNumber / 5.0 );
Math.Ceiling will do what you want...
double pages = Math.Ceiling((float)anyNumber / 5);
as an aside, you might choose to cast to double instead of float to avoid extra implicit casts from float to double:
double pages = Math.Ceiling((double)anyNumber / 5d);
I'm trying convert a decimal into integer and want to round the value up or down depending on the situation.
Basically example is:
12/3 = 4 so should round to 4
11/3 = 3.66666 so should round to 4
10/3 = 3 = 3.33333 so should round to 3
9/3 = 3 so should round to 3
Whatever I found on the internet always rounds down or always rounds up, never makes a judgment call based on the numbers.
If x is the number you want to round and you want the "normal" rounding behavior (so that .5 always gets rounded up), you need to use Math.Round(x, MidpointRounding.AwayFromZero). Note that if you are actually computing fractions and the numerator and denominator are integers, you need to cast one of them to double first (otherwise, the division operator will produce an integer that is rounded down), and that if you want the result to be an int, you need to cast the result of Round():
int a = 5;
int b = 2;
double answer = (int) Math.Round(a / (double) b, MidpointRounding.AwayFromZero);
Math.Round(value) should do what you want. Examples console app code to demonstrate:
Console.Write("12 / 3 = ");
Console.WriteLine((int)Math.Round(12d / 3d));
Console.WriteLine();
Console.Write("11 / 3 = ");
Console.WriteLine((int)Math.Round(11d / 3d));
Console.WriteLine();
Console.Write("10 / 3 = ");
Console.WriteLine((int)Math.Round(10d / 3d));
Console.WriteLine();
Console.Write("9 / 3 = ");
Console.WriteLine((int)Math.Round(9d / 3d));
Console.WriteLine();
Console.ReadKey();
Does Math.Round(d) do what you require?
Return Value:
The integer nearest parameter d. If the fractional component of d is halfway between two integers, one of which is even and the other odd, the even number is returned. Note that this method returns a Decimal instead of an integral type.
Check out the Round reference page
You could try this
Math.Round(d, 0, MidpointRounding.AwayFromZero)
Sometime, people add 0.5 to the number before converting to int.
I'm running NUnit tests to evaluate some known test data and calculated results. The numbers are floating point doubles so I don't expect them to be exactly equal, but I'm not sure how to treat them as equal for a given precision.
In NUnit we can compare with a fixed tolerance:
double expected = 0.389842845321551d;
double actual = 0.38984284532155145d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
and that works fine for numbers below zero, but as the numbers grow the tolerance really needs to be changed so we always care about the same number of digits of precision.
Specifically, this test fails:
double expected = 1.95346834136148d;
double actual = 1.9534683413614817d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
and of course larger numbers fail with tolerance..
double expected = 1632.4587642911599d;
double actual = 1632.4587642911633d; // really comes from a data import
Expect(actual, EqualTo(expected).Within(0.000000000000001));
What's the correct way to evaluate two floating point numbers are equal with a given precision? Is there a built-in way to do this in NUnit?
From msdn:
By default, a Double value contains 15 decimal digits of precision, although a maximum of 17 digits is maintained internally.
Let's assume 15, then.
So, we could say that we want the tolerance to be to the same degree.
How many precise figures do we have after the decimal point? We need to know the distance of the most significant digit from the decimal point, right? The magnitude. We can get this with a Log10.
Then we need to divide 1 by 10 ^ precision to get a value around the precision we want.
Now, you'll need to do more test cases than I have, but this seems to work:
double expected = 1632.4587642911599d;
double actual = 1632.4587642911633d; // really comes from a data import
// Log10(100) = 2, so to get the manitude we add 1.
int magnitude = 1 + (expected == 0.0 ? -1 : Convert.ToInt32(Math.Floor(Math.Log10(expected))));
int precision = 15 - magnitude ;
double tolerance = 1.0 / Math.Pow(10, precision);
Assert.That(actual, Is.EqualTo(expected).Within(tolerance));
It's late - there could be a gotcha in here. I tested it against your three sets of test data and each passed. Changing pricision to be 16 - magnitude caused the test to fail. Setting it to 14 - magnitude obviously caused it to pass as the tolerance was greater.
This is what I came up with for The Floating-Point Guide (Java code, but should translate easily, and comes with a test suite, which you really really need):
public static boolean nearlyEqual(float a, float b, float epsilon)
{
final float absA = Math.abs(a);
final float absB = Math.abs(b);
final float diff = Math.abs(a - b);
if (a * b == 0) { // a or b or both are zero
// relative error is not meaningful here
return diff < (epsilon * epsilon);
} else { // use relative error
return diff / (absA + absB) < epsilon;
}
}
The really tricky question is what to do when one of the numbers to compare is zero. The best answer may be that such a comparison should always consider the domain meaning of the numbers being compared rather than trying to be universal.
How about converting the items each to string and comparing the strings?
string test1 = String.Format("{0:0.0##}", expected);
string test2 = String.Format("{0:0.0##}", actual);
Assert.AreEqual(test1, test2);
Assert.That(x, Is.EqualTo(y).Within(10).Percent);
is a decent option (changes it to a relative comparison, where x is required to be within 10% of y). You may want to add extra handling for 0, as otherwise you'll get an exact comparison in that case.
Update:
Another good option is
Assert.That(x, Is.EqualTo(y).Within(1).Ulps);
where Ulps means units in the last place. See https://docs.nunit.org/articles/nunit/writing-tests/constraints/EqualConstraint.html#comparing-floating-point-values.
I don't know if there's a built-in way to do it with nunit, but I would suggest multiplying each float by the 10x the precision you're seeking, storing the results as longs, and comparing the two longs to each other.
For example:
double expected = 1632.4587642911599d;
double actual = 1632.4587642911633d;
//for a precision of 4
long lActual = (long) 10000 * actual;
long lExpected = (long) 10000 * expected;
if(lActual == lExpected) { // Do comparison
// Perform desired actions
}
This is a quick idea, but how about shifting them down till they are below zero? Should be something like num/(10^ceil(log10(num))) . . . not to sure about how well it would work, but its an idea.
1632.4587642911599 / (10^ceil(log10(1632.4587642911599))) = 0.16324587642911599
How about:
const double significantFigures = 10;
Assert.AreEqual(Actual / Expected, 1.0, 1.0 / Math.Pow(10, significantFigures));
The difference between the two values should be less than either value divided by the precision.
Assert.Less(Math.Abs(firstValue - secondValue), firstValue / Math.Pow(10, precision));
open FsUnit
actual |> should (equalWithin errorMargin) expected