2010-12-03 24 views
7

Floatの平方根をC#に、XNAでCore.Sqrtに似たものを計算するにはどうすればよいですか?Cで浮動小数点の平方根を計算する方法

+1

使用強力な魔法 - [0x5f3759df](http://www.codemaestro.com/reviews/9) – jball

+0

魔法は逆平方根であること。しかし、sqrtにも同様の魔法が存在します。そして、これは精度を失う。 – CodesInChaos

+0

@CodeInChaos - 記事の2番目のコードサンプルにはsqrtの実装があります:* "実際の違いは戻り値にあります - yを返す代わりに、数値* yを平方根として返します" * – jball

答えて

15

doubleと計算してから、再びフロートにキャストします。少し遅いかもしれませんが、うまくいくはずです。

(float)Math.Sqrt(inputFloat) 
+0

精度が緩んでいませんか? – Chris

+0

私はいつも何とか.Netがこれを完全な浮動小数点(32ビットすべて)の操作として最適化することを望んでいました。これが最適化されるかどうかは誰にも分かりますか? – Detmar

+0

@Chris、精度は入力と同じになります。計算はdoubleを使用して行われます。 –

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

floatとdoubleは違って計算されますか? – Chris

+2

@Chris - Math.Sqrtメソッドはdoubleをとり、doubleを返します。そのため、私はパラメータをdouble型にキャストしました。 –

+0

私はそれを見ます。しかし、私はフロートについて話しています。とにかくありがとう – Chris

4

はこれを言うために嫌い、しかし限りMath.Sqrtとして3倍取る0x5f3759dfようです。私はちょうどタイマーでいくつかのテストをしました。 for-loopで事前計算された配列にアクセスするMath.Sqrtは約80msでした。 同じ状況下で0x5f3759dfが得られました。180 + ms

リリースモードの最適化を使用してテストを数回行いました。以下

出典:

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

正直言って、これはかなりオフトピックですが、とにかく面白いです! – Tara

+1

http://stackoverflow.com/questions/268853/is-it-possible-to-write-quakes-fast-invsqrt-function-in-c? –

-3
private double operand1; 

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

スタックオーバーフローへようこそ!この回答はおそらく正確で有用なものですが、問題の解決に役立つ方法を説明するためには、[それにいくつかの説明を含めてください](http://meta.stackexchange.com/q/114762/159034)をお勧めします。これは、将来的には、作業が停止する原因となる変更(無関係かもしれない)があり、ユーザーは以前の作業の仕組みを理解する必要がある場合に、特に便利になります。 –

関連する問題