11

How can I calculate the square root of a Float in C#, similar to Core.Sqrt in XNA?

howettl
  • 12,419
  • 13
  • 56
  • 91
Chris
  • 2,340
  • 6
  • 40
  • 63
  • 1
    Use powerful magic - [0x5f3759df](http://www.codemaestro.com/reviews/9) – jball Dec 03 '10 at 21:18
  • That magic is the inverse square-root. But similar magic exists for sqrt. And this loses precision. – CodesInChaos Dec 03 '10 at 21:22
  • @CodeInChaos - the second code sample in the article has an implementation for sqrt: *"Note that the only real difference is in the return value – instead of returning y, return number*y as the square root"* – jball Dec 03 '10 at 21:26
  • @CodeInChaos Does that mean I am to use "(float)Math.Sqrt(inputFloat)" yes? – Chris Dec 03 '10 at 21:26
  • 1
    yes. What jball posted in mainly a cool curiosity and only useful if performance is much more important than precision. First I'd use simple built in stuff and only switch to complicated solutions if performance really requires it, and profiling shows that the change actually matters. – CodesInChaos Dec 03 '10 at 21:29
  • 1
    @CodeInChaos is absolutely right (hence my *"powerful magic"* statement, and not posting it as an answer). Always code for readability, maintainability and accuracy (e.g. `(float)Math.Sqrt(inputFloat)` ) unless you have an actual performance problem – jball Dec 03 '10 at 22:00
  • @jball dead link – JAlex Apr 14 '22 at 15:20

4 Answers4

19

Since .net core 2.0 you can use MathF.Sqrt.

In older versions, you can calculate it for double and then cast back to float. May be a bit slow, but should work.

(float)Math.Sqrt(inputFloat)
CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
  • 1
    I've always hoped that somehow .Net would optimize this to be an all-float (all 32-bit) operation behind the scenes. Does anyone know if this gets optimized? – Detmar Dec 03 '10 at 21:15
  • @Chris, the precision will be the same as the input. The calculation is done using doubles. – Jackson Pope Dec 03 '10 at 21:15
  • 3
    @Chris: no, there's a well-known theorem of floating point analysis that guarantees that this will give you the correct result. – Stephen Canon Dec 03 '10 at 21:16
  • 2
    Since double has a much higher precision than `float` the loss will be very small or non existent. By using floats you already said you don't care much about precision. – CodesInChaos Dec 03 '10 at 21:19
  • And in the default mode the x87 floating point unit calculates with 80 bit floating points internally. – CodesInChaos Dec 03 '10 at 21:20
  • 4
    @CodeInChaos: note that the precision loss isn't even "very small". Assuming that the conversions and double-precision square root are correctly-rounded, this delivers a correctly-rounded single-precision square root for all possible inputs. – Stephen Canon Dec 03 '10 at 21:40
  • Or better yet use MathF.Sqrt(inputFloat). – Paul Childs Feb 08 '21 at 01:33
6

Hate to say this, but 0x5f3759df seems to take 3x as long as Math.Sqrt. I just did some testing with timers. Math.Sqrt in a for-loop accessing pre-calculated arrays resulted in approx 80ms. 0x5f3759df under the same circumstances resulted in 180+ms

The test was conducted several times using the Release mode optimizations.

Source below:

/*
    ================
    SquareRootFloat
    ================
    */
    unsafe static void SquareRootFloat(ref float number, out float result)
    {
        long i;
        float x, y;
        const float f = 1.5F;

        x = number * 0.5F;
        y = number;
        i = *(long*)&y;
        i = 0x5f3759df - (i >> 1);
        y = *(float*)&i;
        y = y * (f - (x * y * y));
        y = y * (f - (x * y * y));
        result = number * y;
    }

    /*
    ================
    SquareRootFloat
    ================
    */
    unsafe static float SquareRootFloat(float number)
    {
        long i;
        float x, y;
        const float f = 1.5F;

        x = number * 0.5F;
        y = number;
        i = *(long*)&y;
        i = 0x5f3759df - (i >> 1);
        y = *(float*)&i;
        y = y * (f - (x * y * y));
        y = y * (f - (x * y * y));
        return number * y;
    }

    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        int Cycles = 10000000;
        Random rnd = new Random();
        float[] Values = new float[Cycles];
        for (int i = 0; i < Cycles; i++)
            Values[i] = (float)(rnd.NextDouble() * 10000.0);

        TimeSpan SqrtTime;

        float[] Results = new float[Cycles];

        DateTime Start = DateTime.Now;

        for (int i = 0; i < Cycles; i++)
        {
            SquareRootFloat(ref Values[i], out Results[i]);
            //Results[i] = (float)Math.Sqrt((float)Values[i]);
            //Results[i] = SquareRootFloat(Values[i]);
        }

        DateTime End = DateTime.Now;

        SqrtTime = End - Start;

        Console.WriteLine("Sqrt was " + SqrtTime.TotalMilliseconds.ToString() + " long");
        Console.ReadKey();
    }
}
Devin
  • 61
  • 1
  • 2
0
var result = Math.Sqrt((double)value);
Mariusz Jamro
  • 30,615
  • 24
  • 120
  • 162
Randy Minder
  • 47,200
  • 49
  • 204
  • 358
-5
private double operand1;  

private void squareRoot_Click(object sender, EventArgs e)
{ 
    operand1 = Math.Sqrt(operand1);
    this.textBox1.Text = operand1.ToString();
}
nonsensickle
  • 4,438
  • 2
  • 34
  • 61
Mas
  • 1
  • 1
  • 2
    Welcome to Stack Overflow! While this answer is probably correct and useful, it is preferred if you [include some explanation along with it](http://meta.stackexchange.com/q/114762/159034) to explain how it helps to solve the problem. This becomes especially useful in the future, if there is a change (possibly unrelated) that causes it to stop working and users need to understand how it once worked. – Kevin Brown-Silva Oct 13 '15 at 14:50