8
votes

Comment calculer la racine carrée d'un flotteur en C #

Comment puis-je calculer la racine carrée d'un float dans C # , similaire à core.sqrt dans xna?


6 commentaires

Utilisez une magie puissante - 0x5f3759DF


Cette magie est la racine carrée inverse. Mais une magie similaire existe pour SQRT. Et cela perd la précision.


@CodeInchaos - Le deuxième échantillon de code de l'article a une implémentation pour SQRT: "Notez que la seule vraie différence est dans la valeur de retour - au lieu de retourner Y, numéro de retour y comme la racine carrée" *


@CodeInchaos Cela signifie-t-il que je suis d'utiliser "(float) MATH.SQRT (INPUTFLOAT)" Oui?


Oui. Ce que JALL a publié principalement une curiosité cool et que ce n'est utile que si la performance est beaucoup plus importante que la précision. J'utiliserais d'abord des éléments simples intégrés et ne passez que sur des solutions complexes si la performance l'exige vraiment et le profilage montre que le changement compte réellement.


@CodeInchaos est absolument raison (d'où ma "puissant magique" déclaration, et ne pas la publier comme une réponse). Toujours le code pour la lisibilité, la maintenabilité et la précision (par exemple (flotteur) math.sqrt (INPUTFLOAT) ) sauf si vous avez un problème de performance réel


4 Réponses :


15
votes

Calculez-le pour Double CODE> puis repliez-le à flotteur. Peut être un peu lent, mais devrait fonctionner.

(float)Math.Sqrt(inputFloat)


7 commentaires

J'ai toujours espéré qu'entreprime .Net optimiserait ceci comme une opération all-float (toutes les 32 bits) dans les coulisses. Est-ce que quelqu'un sait si cela est optimisé?


@Chris, la précision sera la même que l'entrée. Le calcul est effectué en utilisant des doubles.


@Chris: Non, il existe un théorème bien connu d'analyse des points flottants qui garantit que cela vous donnera le résultat correct.


Puisque le double a une précision beaucoup plus élevée que float la perte sera très petite ou inexistante. En utilisant des flotteurs, vous avez déjà dit que vous vous moquiez beaucoup de précision.


Et dans le mode par défaut, l'unité de point flottante X87 calcule avec des points flottants de 80 bits en interne.


@CODEINCHAOS: Notez que la perte de précision n'est même pas "très petite". En supposant que les conversions et la racine carrée de la double précision soient correctement arrondies, celles-ci fournissent une racine carrée à une précision simple arrondie pour toutes les entrées possibles.


Ou mieux encore utiliser mathf.sqrt (INPUTFLOAT).



0
votes
var result = Math.Sqrt((double)value);

3 commentaires

flotter et double calculer différemment non?


@Chris - La méthode MATH.SQRT prend un double et retourne un double. C'est pourquoi j'ai lancé le paramètre comme un double.


Je vois ça. Mais je parle de flotteurs. Merci quand même



5
votes

Déteste de dire cela, mais 0x5f3759DF semble prendre 3 fois aussi longtemps que MATH.SQRT. Je viens de faire des tests avec des minuteries. MATH.SQRT dans une accession à boucle Des tableaux pré-calculés ont entraîné environ 80 ms. 0x5f3759DF Dans les mêmes circonstances, le test a été effectué plusieurs fois à plusieurs reprises à l'aide des optimisations de mode de libération. P>

Source ci-dessous: P>

/*
    ================
    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();
    }
}


2 commentaires

Pour être honnête, cela semble joliment off-sujet, mais est intéressant quand même!


Stackoverflow.com/Questtions/268853/... ?



-5
votes
private double operand1;  

private void squareRoot_Click(object sender, EventArgs e)
{ 
    operand1 = Math.Sqrt(operand1);
    this.textBox1.Text = operand1.ToString();
}

1 commentaires

Bienvenue dans le débordement de la pile! Tandis que cette réponse est probablement correcte et utile, elle est préférée si vous Inclure une explication avec elle pour expliquer comment elle aide à résoudre le problème. Cela devient particulièrement utile à l'avenir, s'il y a une modification (éventuellement sans rapport), ce qui le fait arrêter de travailler et que les utilisateurs doivent comprendre comment il a fonctionné une fois.