[英]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
很慢:它使用軟件計算。 另一方面, int
、 double
和類似的計算是在硬件中實現的。 在這里使用int
,無論如何都不要使用小數部分。Math.Pow
很慢。 不要用它來平方:用x * x
替換Math.Pow(x, 2)
Math.Sqrt
很慢。 不要將Math.Sqrt(x)
與y
進行比較,而是將x
與y * y
進行比較。 或者只在最后調用一次。Math.Floor
很慢:)請記住,當我的意思是慢時,它是相對的。 從絕對意義上講,所有這些操作都非常快 - 我只是說您可以使用更快的替代方法。
但是有一件事情非常緩慢(以至於對人類來說很明顯): Console
。 它在 Windows 10 上變得更好,但它仍然很慢,而且您正在代碼的熱路徑中使用控制台。 擺脫這些中間結果。
還有一件事,如果您在除法中使用int
,您將在 C# 中得到一個int
。 如果你想得到小數部分(如(double)x / y
),你需要在除法之前將一個操作數轉換為double
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.