实现更改为.NET的Random()

Nej*_*chy 16 .net c# random .net-1.1

我正在迁移一个用于从.NET Framework 1.1解码到.NET Framework 4的方法.我注意到Random的实现已更改.因此,给定相同的种子,Random.NextBytes返回不同的结果.

所以,如果我运行以下代码.

byte[] bytes = new byte[4];
System.Random random = new System.Random(50);
random.NextBytes(bytes);

for(int i=0; i< bytes.Length; i++)
{
  Console.WriteLine("bytes[" + i + "] = " + bytes[i]);
}
Run Code Online (Sandbox Code Playgroud)

在.NET Framework 1.1下,它返回:

bytes[0] = 216
bytes[1] = 124
bytes[2] = 183
bytes[3] =  58
Run Code Online (Sandbox Code Playgroud)

在.NET framework 4下,它返回:

bytes[0] = 154
bytes[1] =  49
bytes[2] = 183
bytes[3] =  48
Run Code Online (Sandbox Code Playgroud)

解决此问题的最佳方法是什么?

Gre*_*g D 27

这不是问题Random,它完全可以满足其记录的界面.这是您的软件依赖于实现细节的问题.从这个错误中吸取教训,不要再这样做了.

至于解决问题,您可以实现自己的1.1版伪随机数生成版本进行解码,然后实现一个新的编码/解码算法,该算法不依赖于新的不稳定行为(例如执行RandomGetHashCode)该软件的版本.

  • 这根本不公平.该算法未记录,因此是一个实现细节.这是围绕使用几乎任何适当的API的基本概念:不要依赖于实现细节,否则您可能会被烧毁.什么是不公平的是使用提供的api然后强制该API永远不会将其实现更改为优越的东西,因为您依赖于愚蠢的实现细节而不是已发布的合同. (11认同)
  • @RussC真的吗?从文档:"在.NET Framework的主要版本中,Random类中随机数生成器的实现不保证保持不变.因此,您的应用程序代码不应该假设相同的种子将导致不同版本的.NET Framework中的相同伪随机序列." (4认同)
  • 在我看来,问题是种子.来自MSDN:"为不同的Random对象提供相同的种子值会导致每个实例产生相同的随机数序列." 这意味着无论实现如何都将发生相同的序列.即使有免责声明,当功能完全以"可重复序列"为特征时,很难证明版本之间的变化是正确的. (3认同)
  • 请注意,在.NET 1.1文档中,随机类被记录为遵循"确定的数学算法".虽然没有记录特定算法及其细节,但文档可以被解释为指定记录这种"明确性".仅在.NET 3.5及其前进文件中记录了特定实现可能会发生变化. (3认同)
  • 那是非常不公平的; 由于我记得,使用随机存储种子是一种可靠的使用随机方式. (2认同)

Wil*_*ill 17

您可以使用Reflector从1.1 mscorlib复制Random类.

public class Random1_1
{
    // Fields
    private int inext;
    private int inextp;
    private const int MBIG = 0x7fffffff;
    private const int MSEED = 0x9a4ec86;
    private const int MZ = 0x0;
    private int[] SeedArray;

    // Methods
    public Random1_1()
        : this(Environment.TickCount)
    {
    }

    public Random1_1(int Seed)
    {
        this.SeedArray = new int[0x38];
        int num2 = 0x9a4ec86 - Math.Abs(Seed);
        this.SeedArray[0x37] = num2;
        int num3 = 0x1;
        for (int i = 0x1; i < 0x37; i++)
        {
            int index = (0x15 * i) % 0x37;
            this.SeedArray[index] = num3;
            num3 = num2 - num3;
            if (num3 < 0x0)
            {
                num3 += 0x7fffffff;
            }
            num2 = this.SeedArray[index];
        }
        for (int j = 0x1; j < 0x5; j++)
        {
            for (int k = 0x1; k < 0x38; k++)
            {
                this.SeedArray[k] -= this.SeedArray[0x1 + ((k + 0x1e) % 0x37)];
                if (this.SeedArray[k] < 0x0)
                {
                    this.SeedArray[k] += 0x7fffffff;
                }
            }
        }
        this.inext = 0x0;
        this.inextp = 0x15;
        Seed = 0x1;
    }

    public virtual int Next()
    {
        return (int)(this.Sample() * 2147483647.0);
    }

    public virtual int Next(int maxValue)
    {
        if (maxValue < 0x0)
        {
            throw new ArgumentOutOfRangeException("maxValue");
        }
        return (int)(this.Sample() * maxValue);
    }

    public virtual int Next(int minValue, int maxValue)
    {
        if (minValue > maxValue)
        {
            throw new ArgumentOutOfRangeException("minValue");
        }
        int num = maxValue - minValue;
        if (num < 0x0)
        {
            long num2 = maxValue - minValue;
            return (((int)((long)(this.Sample() * num2))) + minValue);
        }
        return (((int)(this.Sample() * num)) + minValue);
    }

    public virtual void NextBytes(byte[] buffer)
    {
        if (buffer == null)
        {
            throw new ArgumentNullException("buffer");
        }
        for (int i = 0x0; i < buffer.Length; i++)
        {
            buffer[i] = (byte)(this.Sample() * 256.0);
        }
    }

    public virtual double NextDouble()
    {
        return this.Sample();
    }

    protected virtual double Sample()
    {
        int inext = this.inext;
        int inextp = this.inextp;
        if (++inext >= 0x38)
        {
            inext = 0x1;
        }
        if (++inextp >= 0x38)
        {
            inextp = 0x1;
        }
        int num = this.SeedArray[inext] - this.SeedArray[inextp];
        if (num < 0x0)
        {
            num += 0x7fffffff;
        }
        this.SeedArray[inext] = num;
        this.inext = inext;
        this.inextp = inextp;
        return (num * 4.6566128752457969E-10);
    }
}
Run Code Online (Sandbox Code Playgroud)

经过测试,它可以提供所需的输出.

  • 法律上可疑.你不能只反编译和使用其他人的代码. (11认同)
  • 我确定他没有反编译它.他刚刚编写了测试用例,直到他的实现与1.1版本匹配.对?:-) (8认同)