我正试图为随机数生成器编写停车场测试的实现。以下是我从:Intel math library documentation和Page 4 of this paper获得测试信息的来源,以及列出的概率密度的phi函数。
我用c编写了一个测试的实现。它使用一个100x100网格,其值最初设置为空。然后,我使用随机数生成器为x和y生成随机整数。如果网格的索引及其邻居为空,则该索引设置为1。否则,什么也不会发生,因为有一个“崩溃”。
我用C系统运行的。随机发生器。我不相信结果是正确的,因为我总是停在3079点附近,这比我应该得到的平均值少了500点。它的p值也是2.21829146215425e-90。
我的代码在下面。有没有人有过这样的经验,或者有人能看到我在实现过程中可能做的不正确的事情?任何帮助都将不胜感激。
private void RunParkingLotTest()
{
points = new int?[100,100];
int parked = 0;
for (int i = 0; i < 12000; i++)
{
int x = random.Next(100);
int y = random.Next(100);
if (IsSafeToPark(x, y))
{
points[x, y] = 1;
parked++;
}
}
Console.WriteLine("Parked: " + parked + "\nP value: " + PhiFunction((parked-3523)/21.9));
}
private bool IsSafeToPark(int x, int y)
{
return PointIsEmpty(x, y)
&& LeftOfPointIsEmpty(x, y)
&& RightOfPointIsEmpty(x, y)
&& BelowPointIsEmpty(x, y)
&& AbovePointIsEmpty(x, y);
}
private bool AbovePointIsEmpty(int x, int y)
{
if (y == 99)
{
return true;
}
else
return points[x, y + 1] == null;
}
private bool BelowPointIsEmpty(int x, int y)
{
if (y == 0)
{
return true;
}
else
return points[x, y - 1] == null;
}
private bool RightOfPointIsEmpty(int x, int y)
{
if (x == 99)
{
return true;
}
else
return points[x + 1, y] == null;
}
private bool LeftOfPointIsEmpty(int x, int y)
{
if (x == 0)
{
return true;
}
else
return points[x - 1, y] == null;
}
private bool PointIsEmpty(int x, int y)
{
return points[x, y] == null;
}
private double PhiFunction(double x)
{
//ϕ(x) = (2π)−½e−x2/2
return ((1 / Math.Sqrt(2 * Math.PI)) * Math.Exp(-(Math.Pow(x, 2)) / 2));
}
编辑-我最初实现的问题是
我画的是正方形而不是圆盘
我只绘制整数值的点。我应该用十进制值代替。
由于以上两个原因,我需要更改我的距离检查
感谢克里斯·辛克莱和我的Z帮我解决这个问题。最终代码发布在下面。
最佳答案
我要试试这个,不可否认,我没有尝试过这样的测试,所以请原谅我,如果我走远了。不过,一般来说,.netRandom
实现是非常好的,而且我从来没有遇到过这样的问题,所以我不会怀疑最初是这样,特别是因为您正确地重用了同一个实例,而不是创建了新的实例。
从parking.pdf和intel文档中可以看到,他们似乎在使用光盘,并计算与中心点的距离。您的实现是使用正方形(点之间的距离为1的数组)从而忽略对角线。
从pdf:
如果使用圆盘,粒子之间的距离r=
p(x(i)-z)2+(y(i)-z)2需要小于或等于1。
使用圆盘还是正方形有关系吗?表明
停车几何图形的重要性可以通过
比较1.0边的正方形和
直径为1.0的圆盘。面积比,圆盘与正方形,是π/4。
因此,预计将在
一个方块比方块在相同的尝试次数。
以及英特尔文档:
测试假设下一个随机点(x,y)成功“停车”,如果
这与之前成功“停车”的每一个点都相距甚远。这个
点(x1,y1)和(x2,y2)之间的足够距离为
最小值(x1-x2,y1-y2)>1。
我猜π/4的盘平方比,以及多少盘可以和正方形匹配的差异,可能是你看到不同数字的原因。(尽管现在我没有看到3523和3070与π/4之间的直接关系。3523*π/4=2767,这很接近,但我相信如果有关系的话,它会比简单的乘法稍微复杂一些。)
不是很好的答案,但我最好的猜测。
编辑:有趣的是,我用一个单位直径的光盘做了一个快速的实现,得到了大约4000个停车场的结果。所以也许这有点超出了我未经训练的自我所能理解的范围(或者也许.net的Random
没有通过测试?)无论如何,这是我的光盘实现:
List<Point> parkedCars = new List<Point>();
Random random = new Random();
void Main()
{
int parked = 0;
for (int i = 0; i < 12000; i++)
{
double x = random.NextDouble() * 100;
double y = random.NextDouble() * 100;
Point pointToPark = new Point(x, y);
if (IsSafeToPark(pointToPark))
{
parkedCars.Add(pointToPark);
parked++;
}
}
Console.WriteLine("Parked: " + parked);
}
private bool IsSafeToPark(Point pointToPark)
{
//make sure it's "inside" the box
if (pointToPark.X < 0.5 || pointToPark.X > 99.5
|| pointToPark.Y < 0.5 || pointToPark.Y > 99.5)
return false;
if (parkedCars.Any(p => Distance(pointToPark, p) <= 1))
return false;
return true;
}
private double Distance(Point p1, Point p2)
{
return Math.Sqrt((p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y));
}
用我可能太简单的π/4比值计算,得到了3142。再靠近一点,但似乎很不正确。
编辑:正如@mike z所指出的,我的测试使用直接距离是不正确的。根据我忘记的测试参数,只需检查x和y距离是否大于1。将我的检查更改为:
Math.Max(Math.Abs(p1.X - p2.X), Math.Abs(p1.Y - p2.Y))
在3450附近产生一个更接近的结果,这是相当接近的。如果我去掉我的“//确保它是“在”框内”复选框,平均10次以上得到3531!
所以我最后的“工作”代码是:
public struct Point
{
public double X,Y;
public Point(double x, double y)
{
this.X = x;
this.Y = y;
}
}
List<Point> parkedCars = new List<Point>();
Random random = new Random();
void Main()
{
int parked = 0;
for (int i = 0; i < 12000; i++)
{
double x = random.NextDouble() * 100;
double y = random.NextDouble() * 100;
Point pointToPark = new Point(x, y);
if (IsSafeToPark(pointToPark))
{
parkedCars.Add(pointToPark);
parked++;
}
}
Console.WriteLine("Parked: " + parked);
}
private bool IsSafeToPark(Point pointToPark)
{
if (parkedCars.Any(p => Distance(pointToPark, p) <= 1))
return false;
return true;
}
private double Distance(Point p1, Point p2)
{
return Math.Max(Math.Abs(p1.X - p2.X), Math.Abs(p1.Y - p2.Y));
}
编辑:我做了100次测试两次,平均结果分别为3521.29和3526.74。不确定这是否意味着还有更多的东西要做,但也许这只是表示.NET和Fortran之间的舍入或浮点精度差异。