0

一次方程式のランダムなシステムを生成するクラスがあります

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 のデバッガ ツールを使用してこのテストをデバッグしようとすると、すべてが機能し、テストに合格しました。このテストが失敗する理由を説明できる人はいますか?

4

2 に答える 2

0

新しい Random インスタンスを作成するよりも、そのシードはミリ秒単位の現在の時間から初期化されます。インスタンスを次々と作成すると、シードは 1 つの値で初期化される場合があります。これを防ぐには、1 つのランダムなインスタンスを 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];
            }
        }
    }
于 2012-05-27T00:02:14.577 に答える
0

これは完全な複製ではありませんが、@LB のリンクがこの質問に答えています。ARandomは現在のタイムスタンプをシードとして初期化されます。同じ時間を使用すると、同じ「乱数」が得られます。

ただし、乱数の配列を作成していて、メソッドは他のことも行うため、期待どおりに機能する可能性があります。ただし、現在のマシンで実行するにはさらに時間が必要なため、次の の呼び出しNextで double 値の別のリストが作成されます。

したがって、このソフトウェアの一部は、常に同じシーケンスをクレートするのに十分な速度でマシン上で実行される可能性があります。そのため、テストは失敗します。

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();
}
于 2012-05-26T23:45:23.440 に答える