我有一个生成随机线性方程组的类
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中的Debugger工具调试此测试,并且所有工作和测试都通过了。任何人都可以形容我为什么这个测试失败了吗?
答案 0 :(得分:0)
虽然这不完全相同,但@ 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();
}
答案 1 :(得分:0)
比你创建新的Random实例,它的seed initialised form the current time以毫秒为单位。如果一个接一个地创建一个实例,那么种子可以用一个值初始化。为防止这种情况,您需要将一个随机实例传递给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];
}
}
}