22

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.

Qcom
  • 18,263
  • 29
  • 87
  • 113

5 Answers5

62

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.)

SLenik
  • 815
  • 1
  • 8
  • 15
7

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.

Bobson
  • 13,498
  • 5
  • 55
  • 80
  • Bobson, you proposed another possible solution, but there is no flaw in SLenik's solution because he only uses double Sqrt(double) as a starting point - like a seed. Then, in the loop, he uses the full precision decimal `x` to adjust the resulting value of Sqrt. – farfareast Nov 08 '12 at 15:41
  • @farfareast - It's a valid point, and under most circumstances the precision issue won't matter. but if you have a very precise decimal in the first place, you will lose a portion of it, which could lead to a slightly-off result. I also find it philosophically objectionable to calculate the square root by using the square root, although that certainly wouldn't stop me from coding that if I actually needed it and there was a performance reason to do so. – Bobson Nov 08 '12 at 16:37
  • Also, in my initial testing (and post), my algorithm appeared to be something like 100x faster, but upon further testing, I discovered that the order in which I did the tests affected the results, so I removed that part. It's still a valid algorithm, and I think it's slightly faster, but it's only a minor difference. The built-in `double` version of `Sqrt` is still significantly faster than either. – Bobson Nov 08 '12 at 16:38
  • No wonder double sqrt is faster. Look at this quote from this [wikipedia article](http://en.wikipedia.org/wiki/X86_assembly_language): `Floating point instructions x86 assembly language includes instructions for a stack-based floating point unit. They include addition, subtraction, negation, multiplication, division, remainder, square roots, integer truncation, fraction truncation, and scale by power of two.` In particular there is FSQRT instruction in the Intel machine code instruction set. :-) See also: [here](http://en.wikipedia.org/wiki/X86_instruction_listings) – farfareast Nov 08 '12 at 19:25
  • 1
    I think this is a really awesome solution. Thanks. – Sachin Kainth Sep 07 '18 at 09:28
6

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.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 7
    Well, I'm making an app calculates golden ratio, which will eventually go to decimal range. Won't work in my scenario. – ave Dec 10 '14 at 13:51
-2

Simple: Cast your decimal to a double and call the function, get the result and cast that back to a decimal. That will probably be faster than any sqrt function you could make on your own, and save a lot of effort.

Paul Fleming
  • 24,238
  • 8
  • 76
  • 113
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
-3
Math.Sqrt((double)myVariableHere);

Will give you back a double that's the square root of your decimal myVariableHere.

Paul Fleming
  • 24,238
  • 8
  • 76
  • 113
dsolimano
  • 8,870
  • 3
  • 48
  • 63