RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1595861
Accepted
MrLavoviy
MrLavoviy
Asked:2024-10-06 20:52:06 +0000 UTC2024-10-06 20:52:06 +0000 UTC 2024-10-06 20:52:06 +0000 UTC

伪随机数生成生成重复值

  • 772

我正在使用 Random 类来生成数字。

class Random {
    UInt128 seed;
    public Random(UInt128 seed) {
        this.seed = seed;
    }
    public int Next(int maxValue) {
        NextSeed();
        return (int)((seed * seed * 158 + 52185) % (UInt128)maxValue);
    }
    public void NextSeed() {
        seed = (seed * seed + 1856237) % UInt128.MaxValue;
    }
}

然后通过循环for (int i = 0; i < 16; i++)我生成这些随机值并且它们是不同的。然而,当再次调用这个循环时,会生成同一系列的数字,尽管粒度应该不同,但我没有重新定义它并使用一个对象。

以下是具有相同值的行的输出示例:

7 1 7 1 7 1 7 1 7 1 7 1 7 1 7 1
7 1 7 1 7 1 7 1 7 1 7 1 7 1 7 1
7 1 7 1 7 1 7 1 7 1 7 1 7 1 7 1
7 1 7 1 7 1 7 1 7 1 7 1 7 1 7 1
... // и т.д.

PS我需要使用我自己的课程。是的,我知道代码很糟糕,而且转换为 UInt128 看起来不太好。

测试代码:

Random random = new(27652582738);  // сид задан для примера
for (int j = 0; j < 32; j++) {
    for (int i = 0; i < 16; i++) {
        Console.Write(random.Next(16).ToString() + " ");
    }
    Console.Write("\n");
}
c#
  • 1 1 个回答
  • 60 Views

1 个回答

  • Voted
  1. Best Answer
    aepot
    2024-10-06T21:48:00Z2024-10-06T21:48:00Z

    这段代码有两个问题:

    1. 不受任何方式控制的溢出
    2. 数学错误

    例如,这里是没有溢出的相同代码

    class Random
    {
        UInt128 seed;
        public Random(UInt128 seed)
        {
            this.seed = seed;
        }
        public int Next(int maxValue)
        {
            NextSeed();
            return (int)(((BigInteger)seed * seed * 158 + 52185) % (BigInteger)maxValue);
        }
        public void NextSeed()
        {
            seed = (UInt128)(((BigInteger)seed * seed + 1856237) % (BigInteger)UInt128.MaxValue);
        }
    }
    

    我们得到以下结论

    7 9 7 7 1 1 7 9 1 9 7 7 7 1 1 9
    7 7 1 7 7 9 9 7 1 7 1 1 1 1 7 7
    7 7 7 9 7 1 1 7 7 1 9 7 7 9 7 9
    7 1 7 7 1 7 9 7 7 7 7 7 7 9 7 1
    7 9 7 7 7 9 7 7 7 7 7 1 7 1 7 7
    7 7 7 1 1 1 1 9 7 7 7 7 7 7 9 7
    7 1 7 7 7 1 1 7 7 7 7 7 1 7 7 1
    ...
    

    这已经更像是一场意外了。我们看到,首先,所有数字都是奇数,其次,序列中只涉及 3 个不同的数字。

    为什么奇怪:

    这里有一个公式seed * seed * 158,其中 158 是偶数,这意味着该乘法的结果将始终是偶数。因此,如果向其添加奇数52185,则输出将是奇数。因此,输出不能包含偶数。

    为什么只有3个数字:

    通过取余数,您可以忽略所有高于左侧余数值最接近的 2 次方的位。也就是说,你只需丢弃这个公式可以给一边的所有熵。

    等等。所选择的公式根本不会给您预期的结果;事实上,它不是 PRCH。

    对 128 位种子的要求非常奇怪,而且还不完全清楚原因。我想修补一个好的 PRNG,这里是一个 System.Random基于Xoshiro256算法的实现。还有一种替代方案 - 较旧的 PRCH 算法“Mersenne Twister”,这是实现。正如您所看到的,具有良好分布的 PRNG 略多于 2 行,并进行乘法和取余。了解如何将数字减少到用户指定的限制而不取余数的基本实践。

    换句话说,你的问题的答案是采用一个好的算法并修改它以满足你的需要,以便它吃掉 128 位种子,仅此而已。或者搜索已经支持开箱即用的 128 位种子的实现。


    因此,我试图摆脱因取余而丢弃的位,并将 158 替换为素数 157,将 52185 替换为最接近的素数 52189。

    class Random
    {
        UInt128 seed;
        public Random(UInt128 seed)
        {
            this.seed = seed;
        }
        public int Next(int maxValue)
        {
            NextSeed();
            return (int)(((BigInteger)seed * seed * 157 + 52189) % UInt128.MaxValue * maxValue / ((BigInteger)UInt128.MaxValue + 1));
        }
        public void NextSeed()
        {
            seed = (UInt128)(((BigInteger)seed * seed + 1856237) % (BigInteger)UInt128.MaxValue);
        }
    }
    

    得到输出

    0 9 15 12 11 5 15 1 13 12 15 8 3 7 5 10
    8 6 13 6 11 2 15 0 12 15 10 6 9 7 13 2
    11 15 5 4 6 1 10 7 8 9 2 11 7 8 13 8
    9 4 4 1 15 11 9 0 1 8 6 13 1 6 7 2
    3 5 13 9 6 2 14 4 10 14 9 2 4 15 15 13
    5 2 9 9 5 2 15 8 9 0 10 4 7 1 1 3
    0 13 5 0 5 13 8 14 6 1 11 11 12 12 15 5
    0 13 6 15 4 12 2 4 6 14 7 14 2 13 14 12
    5 8 6 14 9 11 12 14 2 3 0 4 5 4 10 5
    8 0 8 14 15 10 6 1 11 11 5 5 11 12 6 11
    ...
    

    您是否同意这要好得多?但这个代码仍然不符合 GSPC 的资格。

    • 2

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5