【问题标题】:Issue with Random.Next() not choosing random valuesRandom.Next() 不选择随机值的问题
【发布时间】:2012-07-23 11:07:58
【问题描述】:

据我了解,Random.Next() 使用系统时间来获取种子,但是当快速迭代循环时,系统时间没有改变或几乎没有改变,给了我相同的“随机”数字.我正在尝试使用随机选择起始位置来开始将字节写入音乐文件中大约 2 秒的静态时间,选择了 30 个不同的位置,但它们几乎相同。我从一开始就几乎是连续的静态,在几秒钟内中断了大约 3 次,然后在大约 30 秒后恢复正常播放音乐;这不是我想要的,我需要它在整个剪辑中展开。 “int pos”是问题,它不是随机的,每个起始位置几乎与其他所有位置相同,所以我有长时间的静态,而不是随机分布在整个音乐中的静态。我的随机数也是静态的。

FileStream stream = new FileStream(file, FileMode.Open, FileAccess.ReadWrite);
for (int i = 0; i < 20; i++)
{
    int pos = rand2.Next(75000, 4000000 /*I've been too lazy to get the file length, so I'm using 4000000*/ );
    for (int x = 0; x < 500000/*500000 is a little over 2 seconds of static*/; x++)
    {
        byte number = array[rand.Next(array.Length)];
        stream.Position = pos;
        pos++;
        stream.WriteByte(number); 
    }
}

我假设每次写入需要 5 秒左右(在我的慢速 CPU 上),这足以让下一个随机数给我一个与前一个不完全相同或非常接近的位置一。就目前而言,每次我似乎都获得了大约 90000 的初始位置(音乐的前几秒);所有接下来的都在 20 秒内。所以我的问题是,为了达到我想要的结果,我需要做些什么修改/做不同的事情?我想要几秒钟的静电散布在整个剪辑中,而不是聚集在一起。

我有一个字节数组来存储我的十六进制数字,这些数字是随机选择的,看起来工作正常,只是书写位置的随机性根本不是随机的,它们都非常接近。

byte[] array = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F };

谢谢。

附:我知道我应该为 FileStream 使用块,当我找到它时我会添加它。

【问题讨论】:

  • 可以在生成随机数之前使用 thread.sleep(1000) 吗?因为你的程序因为这个随机没有改变而暂停了 1 秒。
  • 嵌套的 for 循环大约需要 5 秒才能完成,因此 int pos 在再次随机化之前将有 5 秒的时间过去。这就是为什么我不明白为什么它甚至不接近随机。
  • 我倾向于认为这个问题与 Jonathan Rupp 所建议的类似。您是否真的单步执行了代码,在每次迭代中查看了pos 的值,并验证这些值都非常接近?这对我来说似乎不太可能;我敢打赌,您会发现这些值在 75000 和 4000000 之间分布得相当均匀。结果可能由于规模压缩而显得“非随机”。

标签: c# .net


【解决方案1】:

我在生成随机数时遇到了同样的问题。它正在生成相同的值。下面的简单代码解决了我的问题。

private static readonly Random random = new Random();
private static readonly object syncLock = new object();
public int RandomNumber(int min, int max)
{
   lock (syncLock)
   { // synchronize
       return random.Next(min, max);
   }
}

你将使用如下:

int rn = RandomNumber(0, 10); //for example

【讨论】:

  • 假设发帖者的代码不是多线程的,锁不会有任何实际影响。
【解决方案2】:

首先,Random.Next 不使用系统时钟来生成随机数。在提供的种子的基础上生成随机数,默认构造函数(无参数)使用系统时钟作为种子,但它仅将系统时钟设置为种子。 如果我错了,请纠正我,但它看起来你得到随机数,但这些数字足够接近以产生几乎相同的声音,你希望你的数字以较大的间隔分散(连续随机数之间的差异)。为此,我建议您使用最低阈值。如果连续数字之间的差异小于阈值,则尝试生成下一个或调整值以满足阈值。一段代码可以更好地解释我想说的话。

int RandomNumber(Random rand,int? lastRandomNumber, int min, int max, int threshold)
        {
            var number = rand.Next(min, max);
            if (lastRandomNumber.HasValue && Math.Abs(lastRandomNumber.Value - number) < threshold)
            {
                Console.WriteLine("Actual:{0}", number);
                if (lastRandomNumber.Value < number)
                {
                    number += threshold;
                    if (number > max)
                        number = max;
                }
                else
                {
                    number -= threshold;
                    if (number < min)
                        number = min;

                }
            }
            return number;
        }

【讨论】:

    【解决方案3】:

    当你写: int pos = rand2.Next(75000, 4000000) 如果您的文件是立体声 16 位 48KHz,则 4000000 / (2*2*48000) = 20 秒 的声音。使用文件大小,很容易。你不应该偷懒 :-) .
    但是,如果您“添加”噪声,则不应替换文件值,而应添加到 它是一个随机值。
    为什么噪声幅度只有 16 / Byte?并固定?使用 number = rand.Next(Amplitude) 计算添加的噪声似乎很好。
    另请注意,您正在创建两个白噪声,每个通道上一个。

    【讨论】:

    • 我对这些文件如何包含数据的理解极为有限。你是说读取字节然后稍微修改它们,以便我没有用静态替换音乐,而是将它作为背景噪音?我该怎么做呢?
    • 去网上查找有关声音文件格式的信息。在 16 位立体声 48000 中,每个样本为 2 字节=16 位=-32767 --> 32768,表示这 1/48000 时间片的声压值。左右样本在一起(L1R1L2R2L3R3 ....)。是的添加噪音,所以使用Stream.read,然后再次设置位置写入。由于您在字节而不是 int16 级别操作,因此噪声应在 0->255 范围内。记得处理溢出。
    【解决方案4】:

    如果 500000 字节大约是 2 秒的音频,并且您从 75000 到 4000000 之间的某个位置开始播放,那么您将在 0.15 秒到 8 秒之间开始播放歌曲。这就解释了为什么在歌曲播放大约 10 秒后您没有听到任何静电。尝试使用实际文件大小(减去 500000)作为 rand 的上限。Next 调用用于填充 pos

    【讨论】:

    • 我不敢相信我没有看到这个;我将尝试使用文件大小并查看是否获得所需的结果,如果有效,我会将其标记为已接受的答案。编辑:是的,这很好用,谢谢。现在每个人都知道我是如何选择我的用户名的,它很合适。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    • 1970-01-01
    相关资源
    最近更新 更多