Performing Math operations on decimal datatype in C#?
I was wondering if the above was at all possible. For example:
Math.Sqrt(myVariableHere);
When looking at the overload, it requires a double parameter, so I'm not sure if there is another way to replicate this with decimal datatypes.
Solution 1:
I don't understand why all the answers to that question are the same.
There are several ways to calculate the square root from a number. One of them was proposed by Isaac Newton. I'll only write one of the simplest implementations of this method. I use it to improve the accuracy of double's square root.
// x - a number, from which we need to calculate the square root
// epsilon - an accuracy of calculation of the root from our number.
// The result of the calculations will differ from an actual value
// of the root on less than epslion.
public static decimal Sqrt(decimal x, decimal epsilon = 0.0M)
{
if (x < 0) throw new OverflowException("Cannot calculate square root from a negative number");
decimal current = (decimal)Math.Sqrt((double)x), previous;
do
{
previous = current;
if (previous == 0.0M) return 0;
current = (previous + x / previous) / 2;
}
while (Math.Abs(previous - current) > epsilon);
return current;
}
About speed: in the worst case (epsilon = 0 and number is decimal.MaxValue) the loop repeats less than a three times.
If you want to know more, read this (Hacker's Delight by Henry S. Warren, Jr.)
Solution 2:
In most cases involving a decimal
(currency etc), it isn't useful to take a root; and the root won't have anything like the expected precision that you might expect a decimal
to have. You can of course force it by casting (assuming we aren't dealing with extreme ends of the decimal
range):
decimal root = (decimal)Math.Sqrt((double)myVariableHere);
which forces you to at least acknowledge the inherent rounding issues.
Solution 3:
I just came across this question, and I'd suggest a different algorithm than the one SLenik proposed. This is based on the Babylonian Method.
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);
}
It doesn't require using the existing Sqrt
function, and thus avoids converting to double
and back, with the accompanying loss of precision.