Rounding of decimal in c# seems wrong - c#

This part of code should speak for itself, my question is can I get 1242.08 result in res variable, and not 1242.07, because in math
b = 1/(1/b)
and in double which has less precision it seems I got good result
Can I fix decimal part of calculation to give me mathematically right result:
decimal rate = 124.2075M;
decimal amount = 10M;
decimal control = decimal.Round(rate * amount, 2); //it is 1242.08
//but
decimal res = decimal.Round(amount * (1 / (1 / rate)), 2);//1242.07 - should be 1242.08
decimal res1 = decimal.Round(amount * 124.2075M, 2);//1242.08 OK
/////////////////////////////////////////////////////////////
//while with double seems OK
double ratef = 124.2075;
double amountf = 10;
double resf = Math.Round(amountf * (1 / (1 / ratef)), 2);//1242.08 OK
double res1f = Math.Round(amountf * 124.2075, 2);//1242.08 OK

That's a limitation of the datatype decimal that can hold up to 29 digits
The result of the first calculation (res1) does not fit into decimal so you get a invalid/imprecisely result.
decimal rate = 124.2075M;
decimal amount = 10M;
decimal res1 = (1 / rate); //0.0080510436165287925447336111M <- not enough decimal places
decimal res2 = (1 / res1); //124.20749999999999999999999991M
decimal res3 = amount * res2; //1242.0749999999999999999999991M
decimal res4 = decimal.Round(res3, 2); //1242.07M <- correct rounding

Related

Getting incorrect decimal places with percentage calculation [duplicate]

This question already has answers here:
C# is rounding down divisions by itself
(10 answers)
Closed 4 years ago.
I am performing calculations on 2 numbers like below :
No1 = 263
No2 = 260
Decimal places = 2
Expected output = 98.86
Code :
decimal output = 0;
int decimalPlaces = 2;
if (No1 > 0)
output = ((100 * Convert.ToDecimal(((No2 * 100) / No1))) / 100);
output = TruncateDecimal(output, decimalPlaces); // 98
public static decimal TruncateDecimal(decimal value, int precision)
{
decimal step = (decimal)Math.Pow(10, precision);
decimal tmp = Math.Truncate(step * value);
return tmp / step;
}
Above code renders output = 98
When i divide 263/260 in calculator i get 0.988593
decimalPlaces = 2 : Take 2 digits after decimal places
decimalPlaces = 2 : Round off will also take from this position after 2 decimal places i.e round off should take from 593 rendering 98.86
No1 = 117
No2 = 120
decimal places = 2
Expected Output = 97.50
Can anybody please me with this?
The problem is integer division. When you divide an integer by an integer, you will get an integer. You need to cast the values (at minimum one of them) to a decimal
output = Math.Round((100 * ((decimal)No2/(decimal)No1)),2);
try to change some parenthesis positions, from:
output = ((100 * Convert.ToDecimal(((No2 * 100) / No1))) / 100);
to
output = ((100 * ((Convert.ToDecimal(No2 * 100) / No1))) / 100);
In your code the division is calculated before decimal conversion, so you convert only integer result of the division.
Besides use Math.Round instead of Math.Truncate, in order to get your desired result.

Something is wrong with the accuracy of calculation between variables

I have some problems with my code where I think the accuracy is a bit off. I'll take out the declarations of variables from my code, so the code is as small as possible:
int a = Int32.Parse(tb_weight.Text);
double b = 0;
b = (a * 1.03) / 1000;
double g = 0;
g = (1.09 + (0.41 * (Math.Sqrt(50 / b))));
lbl_vertforce.Content = Math.Round((b * g * 9.81), 2);
So, tb_weight is a textbox where the input is made, and lets say the input is 5000, the label lbl_vertforce is showing 119,61 and according to my calculator, it should show 119,74. What is wroing here?
Doubles are not 100% precise and can vary in the least common digits. If you want exact precision you need to use Decimal type which has a bigger memory foot print, but was designed to be very precise. Unfortunately Math.Sqrt is not overloaded for Decimal and only works on doubles. I have provide code I found in another posting discussing the subject of Decimal Square roots: Performing Math operations on decimal datatype in C#?
public void YourCodeModifiedForDecimal()
{
int a = Int32.Parse(tb_weight.Text);
decimal b = 0;
b = (a* 1.03m) / 1000m;
decimal g = 0;
g = (1.09m + (0.41m * (Sqrt(50m / b))));
lbl_vertforce.Content = Math.Round((b* g * 9.81m), 2);
}
public static decimal Sqrt(decimal x, decimal? guess = null)
{
var ourGuess = guess.GetValueOrDefault(x / 2m);
var result = x / ourGuess;
var average = (ourGuess + result) / 2m;
if (average == ourGuess) // This checks for the maximum precision possible with a decimal.
return average;
else
return Sqrt(x, average);
}
You need to round g to 2 decimal places to get 119.74 in the final calculation.
g = Math.Round(1.09 + (0.41 * (Math.Sqrt(50 / b))), 2);

decimal round off: why?

string a = "9.42";
string b = "1610.25";
decimal aa = decimal.Parse(a, CultureInfo.InvariantCulture);
decimal bb = decimal.Parse(b, CultureInfo.InvariantCulture);
decimal res = decimal.Multiply(aa, bb);
string res2 = res.ToString("#0.00", CultureInfo.CreateSpecificCulture("sv-SE"));
Result
//res = 15168.555
//res2 = "15168,56"
I want output res2=15168,55. How to achive it?
The default rounding method is to round a midpoint value to the closest even decimal, e.g. 1.555 is rounded to 1.56 but 1.585 is rounded to 1.58.
You can use the Math.Floor method to round down, but it doesn't have an overload where you can specify the number of decimal places, so you need to multiply and divide:
res = Math.Floor(res * 100m) / 100m;
string res2 = (Math.Floor(res * 100) / 100).ToString();

Rounding Decimal with no precision

I want to round this decimal number 14999994 to this value 15000000, but Math.Round() doesn't work for me!
Please notice that my decimal number doesn't have any precision
static double RoundToSignificantDigits(double d, int digits)
{
if (d == 0)
{
return 0;
}
double scale = Math.Pow(10, Math.Floor(Math.Log10(Math.Abs(d))) + 1 - digits);
return Math.Sign(d) * scale * Math.Ceiling(Math.Abs(d) / scale);
}
It's based on calculating a "scale" based on the Math.Log10 (but note that Math.Abs for the negative numbers!), minus the digits precision given, then dividing the number by this "scale", rounding and re-multiplying by this "scale". Note even the use of Math.Sign: we round up (Math.Ceiling) the absolute value of d and then "reattach" the sign.
Use it like:
double n = RoundToSignificantDigits(14999994, 2); // 15000000
Note that double are an ugly beast:
double num = 0.2;
num += 0.1; // 0.30000000000000004
double num2 = RoundToSignificantDigits(num, 1); // 0.4

Excel RoundUp vs .NET Math.Round

in Excel, =ROUNDUP(474.872126666666, 2) -> 474.88
in .NET,
Math.Round(474.87212666666666666666666666667, 2, MidpointRounding.ToEven) // 474.87
Math.Round(474.87212666666666666666666666667, 2, MidpointRounding.AwayFromZero) // 474.87
My client want Excel rounding result, is there any way I can get 474.88 in .NET?
Thanks a lot
double ROUNDUP( double number, int digits )
{
return Math.Ceiling(number * Math.Pow(10, digits)) / Math.Pow(10, digits);
}
Math.Ceiling is what you're looking for.
Here's my try on a solution that behaves like Excel ROUNDUP function.
I tried to cover cases such as: negative decimal numbers, negative digits (yep Excel supports that), large decimal values
public static decimal RoundUp(decimal number, int digits)
{
if (digits > 0)
{
// numbers will have a format like +/-1.23, where the fractional part is optional if numbers are integral
// Excel RoundUp rounds negative numbers as if they were positive.
// To simulate this behavior we will use the absolute value of the number
// E.g. |1.23| = |-1.23| = 1.23
var absNumber = Math.Abs(number);
// Now take the integral part (E.g. for 1.23 is 1)
var absNumberIntegralPart = Decimal.Floor(absNumber);
// Now take the fractional part (E.g. for 1.23 is 0.23)
var fraction = (absNumber - absNumberIntegralPart);
// Multiply fractional part by the 10 ^ number of digits we're rounding to
// E.g. For 1.23 with rounded to 1 digit it will be 0.23 * 10^1 = 2.3
// Then we round that value UP using Decimal.Ceiling and we transform it back to a fractional part by dividing it by 10^number of digits
// E.g. Decimal.Ceiling(0.23 * 10) / 10 = Decimal.Ceiling(2.3) / 10 = 3 / 10 = 0.3
var tenPower = (decimal)Math.Pow(10, digits);
var fractionRoundedUp = Decimal.Ceiling(fraction * tenPower) / tenPower;
// Now we add up the absolute part with the rounded up fractional part and we put back the negative sign if needed
// E.g. 1 + 0.3 = 1.3
return Math.Sign(number) * (absNumberIntegralPart + fractionRoundedUp);
} else if (digits == 0)
{
return Math.Sign(number) * Decimal.Ceiling(Math.Abs(number));
} else if (digits < 0)
{
// negative digit rounding means that for RoundUp(149.12, -2) we will discard the fractional part, shift the decimal point on the left part 2 places before rounding up
// then replace all digits on the right of the decimal point with zeroes
// E.g. RoundUp(149.12, -2). Shift decimal point 2 places => 1.49. Now roundup(1.49) = 2 and we put 00 instead of 49 => 200
var absNumber = Math.Abs(number);
var absNumberIntegralPart = Decimal.Floor(absNumber);
var tenPower = (decimal)Math.Pow(10, -digits);
var absNumberIntegraPartRoundedUp = Decimal.Ceiling(absNumberIntegralPart / tenPower) * tenPower;
return Math.Sign(number)*absNumberIntegraPartRoundedUp;
}
return number;
}
[TestMethod]
public void Can_RoundUp_Correctly()
{
Assert.AreEqual(1.466m, MathExtensions.RoundUp(1.4655m, 3));
Assert.AreEqual(-1.466m, MathExtensions.RoundUp(-1.4655m, 3));
Assert.AreEqual(150m, MathExtensions.RoundUp(149.001m, 0));
Assert.AreEqual(-150m, MathExtensions.RoundUp(-149.001m, 0));
Assert.AreEqual(149.2m, MathExtensions.RoundUp(149.12m, 1));
Assert.AreEqual(149.12m, MathExtensions.RoundUp(149.12m, 2));
Assert.AreEqual(1232m, MathExtensions.RoundUp(1232, 2));
Assert.AreEqual(200m, MathExtensions.RoundUp(149.123m, -2));
Assert.AreEqual(-200m, MathExtensions.RoundUp(-149.123m, -2));
Assert.AreEqual(-20m, MathExtensions.RoundUp(-12.4655m, -1));
Assert.AreEqual(1.67m, MathExtensions.RoundUp(1.666666666666666666666666666m, 2));
Assert.AreEqual(1000000000000000000000000000m, MathExtensions.RoundUp(999999999999999999999999999m, -2));
Assert.AreEqual(10000000000000m, MathExtensions.RoundUp(9999999999999.999m, 2));
}
Here is the correct calculation for ROUNDUP and ROUNDDOWN:
private static object RoundDown(List<Expression> p)
{
var target = (decimal)p[0].Evaluate();
var digits = (decimal)p[1].Evaluate();
if (target < 0) return (Math.Ceiling((double)target * Math.Pow(10, (int)digits)) / Math.Pow(10, (int)digits));
return Math.Floor((double)target * Math.Pow(10, (int)digits)) / Math.Pow(10, (int)digits);
}
private static object RoundUp(List<Expression> p)
{
var target = (decimal)p[0].Evaluate();
var digits = (decimal)p[1].Evaluate();
if (target < 0) return (Math.Floor((double)target * Math.Pow(10, (int)digits)) / Math.Pow(10, (int)digits));
return Math.Ceiling((double)target * Math.Pow(10, (int)digits)) / Math.Pow(10, (int)digits);
}

Categories