簡體   English   中英

我怎樣才能優化這個算法來逼近 pi?

[英]How could I optimize this algorithm for approximating pi?

我在編碼方面非常缺乏經驗,但我設法寫了這個:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PiApprox
{

    public class PiApprox
    {
        //side of the rectangle
        public static int s;

        //radius of the circle
        public static int r;

        //indexers of the coordinates, points
        public static int ix;
        public static int iy;

        //current y
        public static decimal cury;
        //without rounding
        public static decimal wcury;

        //amounts of points relative to the circle
        public static decimal inAmount;
        public static decimal onAmount;
        public static decimal outAmount;

        //amount of all points
        public static decimal allAmount;

        //short for inAmount and on onAmount, 
        //used to make the calculations clearer in the final part
        public static decimal inanon;

        //final result, crude approximation of pi
        public static decimal piApprox;


        public static void Main()
        {
            while (true)
            {
                Calculate();
            }
        }

        public static void Calculate ()
        {
            s = Convert.ToInt32(Console.ReadLine());


            //calculate the radius of the circle
            r = s / 2;

            //calculate the total amount of points in the grid
            //rectangle area
            allAmount = (decimal) Math.Pow(s, 2);

            //reset values
            inAmount = 0;
            onAmount = 0;
            outAmount = 0;

            //main loop
            //iterate for y, from up to down 
            for (ix = -r; ix <= 0; ix++)
            {
                wcury = (decimal) Math.Sqrt(Math.Pow(r, 2) - Math.Pow(ix, 2));
                cury = Math.Floor(wcury);


                outAmount += r - (int)cury;

                if (wcury == cury)
                {
                    onAmount++;
                }

                if (wcury == cury)
                {
                    inAmount += (int)cury;
                }
                else
                {
                    inAmount += (int)cury + 1;
                }
                Result();
            }

            Result();
        }

        public static void Result()
        {
            //total amount of points
            inanon = 4 * (onAmount + inAmount - (r + 1)) + 1;

            //proportion
            piApprox = 4 * (inanon / allAmount);

            Console.SetCursorPosition(1, 0);
            Console.WriteLine(piApprox);
        }
    }

}

蒙特卡羅原理很簡單; 我計算圖 f(x) = sqrt(r^2 - ix^2) 的 y 值,它代表一個圓的第一季度。 然后我計算圓內的點並在最后輸出它。 piApprox = 4 * (inanon / allAmount) 線上的乘法; 來自正方形和圓形的比例:
(pi * r^2) / ( (2r) ^ 2 ) -> (pi * r ^ 2) / (4 * r ^ 2) -> pi / 4

有什么我可以做的來加速計算嗎?

我假設您是 C# 新手,所以我將在這里給您一些提示。

有幾個方面有改進的潛力:

  • decimal很慢:它使用軟件計算。 另一方面, intdouble和類似的計算是在硬件中實現的。 在這里使用int ,無論如何都不要使用小數部分。
  • Math.Pow很慢。 不要用它來平方:用x * x替換Math.Pow(x, 2)
  • Math.Sqrt很慢。 不要將Math.Sqrt(x)y進行比較,而是將xy * y進行比較。 或者只在最后調用一次。
  • Math.Floor:)
  • 您可以使用並行性來利用多核 CPU
  • 您應該使用局部變量,因為它們更易於優化

請記住,當我的意思是慢時,它是相對的 從絕對意義上講,所有這些操作都非常快 - 我只是說您可以使用更快的替代方法。

但是有一件事情非常緩慢(以至於對人類來說很明顯): Console 它在 Windows 10 上變得更好,但它仍然很慢,而且您正在代碼的熱路徑中使用控制台。 擺脫這些中間結果。

還有一件事,如果您在除法中使用int ,您將在 C# 中得到一個int 如果你想得到小數部分(如(double)x / y ),你需要在除法之前將一個操作數轉換為double

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM