生成随机序列的奇怪行为
本文关键字:随机 | 更新日期: 2023-09-27 18:35:22
我有生成随机线性方程组的类
public class MatrixGenerator: IMatrixGenerator
{
private int vSize;
private int hSize;
private double[,] _matrix;
private double[] _right;
private double[] _solution;
private double maxValue;
public MatrixGenerator(int vSize, int hSize, double maxValue)
{
this.vSize = vSize;
this.hSize = hSize;
this.maxValue = maxValue;
_matrix = new double[vSize, hSize];
_right = new double[vSize];
_solution = new double[hSize];
}
public void Next()
{
_matrix = new double[vSize, hSize];
_right = new double[vSize];
Random r = new Random();
_solution = Enumerable.Repeat(0.0, hSize).Select(m => m = r.NextDouble()*maxValue).ToArray();
for (int i = 0; i < vSize; i++)
{
for (int j = 0; j < hSize; j++)
{
_matrix[i, j] = r.NextDouble() * maxValue;
}
for (int j = 0; j < hSize; j++)
{
_right[i] += _solution[j] * _matrix[i, j];
}
}
}
public double[,] Matrix
{
get { return _matrix; }
}
public double[] RightVector
{
get { return _right; }
}
public double[] SolutionVector
{
get { return _solution; }
}
}
和此类的 NUnit 测试:
[Test]
public void CanGenerateAnotherMatrixandVector()
{
MatrixGenerator mGen = new MatrixGenerator(vSize, hSize, maxValue);
mGen.Next();
double[,] firstMatrix = new double[mGen.Matrix.GetLength(0), mGen.Matrix.GetLength(1)];
double[] firstVector = new double[mGen.RightVector.GetLength(0)];
for (int i = 0; i < mGen.Matrix.GetLength(0); i++)
{
firstVector[i] = mGen.RightVector[i];
for (int j = 0; j < mGen.Matrix.GetLength(1); j++)
{
firstMatrix[i,j] = mGen.Matrix[i, j];
}
}
mGen.Next();
Assert.That(firstMatrix, Is.Not.EqualTo(mGen.Matrix));
Assert.That(firstVector, Is.Not.EqualTo(mGen.RightVector));
}
测试失败,但此代码有效。我尝试使用 TestDriven.Net 年的调试器工具调试此测试,并且所有工作和测试都通过了。谁能描述为什么这个测试失败了?
比你创建新的随机实例,它的种子初始化为当前时间,以毫秒为单位。如果紧接着创建一个实例,则种子可以使用一个值初始化。为了防止这种情况,您需要将一个随机实例传递给 Next 方法。
测试:
var random = new Random();
var mGen = new MatrixGenerator(4, 5, 10);
mGen.Next(random);
var firstMatrix = new double[mGen.Matrix.GetLength(0),mGen.Matrix.GetLength(1)];
var firstVector = new double[mGen.RightVector.GetLength(0)];
for (int i = 0; i < mGen.Matrix.GetLength(0); i++) {
firstVector[i] = mGen.RightVector[i];
for (int j = 0; j < mGen.Matrix.GetLength(1); j++) {
firstMatrix[i, j] = mGen.Matrix[i, j];
}
}
mGen.Next(random);
CollectionAssert.AreNotEqual(firstMatrix, mGen.Matrix);
CollectionAssert.AreNotEqual(firstVector, mGen.RightVector);
新的下一个方法:
public void Next(Random random) {
_matrix = new double[vSize,hSize];
_right = new double[vSize];
_solution = Enumerable.Repeat(0.0, hSize).Select(m => random.NextDouble()*maxValue).ToArray();
for (int i = 0; i < vSize; i++) {
for (int j = 0; j < hSize; j++) {
_matrix[i, j] = random.NextDouble()*maxValue;
}
for (int j = 0; j < hSize; j++) {
_right[i] += _solution[j]*_matrix[i, j];
}
}
}
虽然这不是一个完全重复的,但@L.B的链接回答了这个问题。Random
以当前时间戳作为种子进行初始化。如果您使用相同的时间,您将获得相同的"随机"数字。
但是,由于您正在创建一个随机数数组,并且该方法还执行其他操作,因此它可能会按预期工作。但这只是因为它需要更多时间在当前机器上执行,所以下一次调用 Next
会创建另一个双精度值列表。
因此,该软件可能在机器上运行得足够快,以始终保持相同的顺序。这就是测试失败的原因。
一个解决方案是始终使用相同的Random
实例,例如使用成员变量而不是局部变量。
public class MatrixGenerator: IMatrixGenerator
{
// ...
Random r = new Random();
// ...
public void Next()
{
_matrix = new double[vSize, hSize];
_right = new double[vSize];
_solution = Enumerable.Repeat(new Random(), hSize)
.Select(r => r.NextDouble() * maxValue)
.ToArray();
// ...
在这种情况下,最好将随机实例传递给 MatrixGenerator
的构造函数或作为参数传递给 Next
方法。
var random = new Random();
for(int i = 0; i< 1000; i++)
{
var mGen = new MatrixGenerator(4, 5, 10, random);
mGen.Next();
}