【问题标题】:Given a number, produce another random number that is the same every time and distinct from all other results给定一个数字,生成另一个每次都相同且与所有其他结果不同的随机数
【发布时间】:2016-03-28 20:47:14
【问题描述】:

基本上,我想帮助设计一种算法,该算法采用给定的数字,并返回一个与第一个数字无关的随机数。规定是 a) 对于相似的输入数字,给定的输出数字将始终相同,并且 b) 在一定范围内(例如 1-100),所有输出数字都是不同的。即,100 以下的两个不同输入数字不会给出相同的输出数字。

我知道通过创建一个有序的数字列表、随机打乱它们然后返回输入的索引很容易做到这一点。但我想知道它是否可以在没有任何缓存的情况下完成。也许使用某种散列算法?这主要是因为如果可能的输出范围更大,比如 10000000000,那么生成整个数字范围然后随机打乱它们是很可笑的,如果你只想得到一些结果的话它。

不管它是用什么语言完成的,我只是想知道它是否可能。这个问题我想了很久,除了我已经想出的解决方案,我想不出一个解决方案。

编辑:我刚刚有了另一个想法;如果有另一种算法返回第一个算法的倒数,那将会很有趣。这是否可能是一个值得探索的有趣挑战。

【问题讨论】:

  • 你可以通过一些简单的计算,并缓存一些信息(主要是输入X返回哪个随机数,这样你就可以得到你要求的一致的返回值)。
  • 我宁愿不做任何类型的缓存。此外,该算法可能会在一段时间后变得低效,因为必须多次生成随机结果以确保它不匹配任何其他答案。此外,这不会保留运行时之间的相似性。纯粹的数学结果不仅会为不同运行时之间的输入提供相同的输出,而且完全可以在不同的计算机上提供相同的输出。这就是我正在寻找的解决方案。
  • 您正在寻找multiplicative inverse
  • 您是否愿意将答案(即使是简单的答案)作为答案而不是 cmets?
  • 这个问题很奇怪。您要求数字之间的关系使得这些数字除了关系之外不相关。我想不出如何区分除了关系之外相关数字不相关的关系,以及相关数字以关系以外的方式相关的关系。应该如何开始回答这个问题?

标签: algorithm random hash distinct-values


【解决方案1】:

你不能有完全不相关的(特别是如果你也想反过来)。

有一个数字的modulo inverse 的概念,但这仅在range 数字是素数时才有效,例如。 100 行不通,你需要 101(素数)。如果你愿意,这可以为你提供一个伪随机数。

这里是模逆的概念:

如果有两个数字a and b,那么

(a * b) % p = 1

其中p 是任意数字,那么

a and b are modular inverses of each other.

要做到这一点,如果我们必须找到 a 与数字 p 的模逆,那么 a and p 必须是互质数,即。 gcd(a,p) = 1

因此,对于范围内的所有数字都具有模逆,范围界限必须是素数。

范围界限 101 的一些输出将是:

1 == 1
2 == 51
3 == 34
4 == 76
etc.

编辑:

嘿...其实你知道的,你可以使用模逆和@Paul定义的方法的组合方法。由于每一对都是唯一的并且所有数字都将被覆盖,因此您的随机数可以是:

random(k) = randomUniqueNumber(ModuloInverse(k), p)      //this is Paul's function

【讨论】:

  • 非常有趣。尽管您似乎有一个相对完整的答案,但我也已链接到 this article,这似乎是说 可能有一个不是素数的任意大小范围。我会继续调查这个问题,除非你有什么要说的。
  • @Maurdekye,请查看编辑(回答)。这可能会有所帮助。
【解决方案2】:

这听起来像是一个不重复的随机数生成器。有几种可能的方法。

正如article 中所述,我们可以通过选择一个足够大的素数p 并满足p % 4 = 3 来生成它们(大于输出范围中的最大值),并以这种方式生成它们:

int randomNumberUnique(int range_len , int p , int x)
    if(x * 2 < p)
       return (x * x) % p
    else
       return p - (x * x) % p

对于[0 , p) 范围内的输入,该算法将覆盖[0 , p) 中的所有值。

【讨论】:

  • 我试过用你的方法,但结果不是唯一的。使用 101 的范围限制,我生成了从 0 到 100 的所有数字,并且只有 51 个唯一结果。
  • @Maurdekye 对不起,我忘记了 p 的属性。我已经编辑了帖子。如果p 满足p % 4 = 3,代码本身就可以正常工作。例如,它适用于p = 103
  • 所以 p 必须既是素数又比 4 的除数小一?这是范围限制的相当数量的规定。如果没有这些要求,是否可以任意限制?
  • @Maurdekye 当然。只有 p 需要满足这些约束。只要最大值小于 p,范围本身可以具有任意限制。如果 p 大于范围限制,则只有一些在范围内的值不会被覆盖。
【解决方案3】:

这是一个 C# 示例:

    private void DoIt()
    {
        const long m = 101;
        const long x = 387420489; // must be coprime to m

        var multInv = MultiplicativeInverse(x, m);

        var nums = new HashSet<long>();
        for (long i = 0; i < 100; ++i)
        {
            var encoded = i*x%m;
            var decoded = encoded*multInv%m;
            Console.WriteLine("{0} => {1} => {2}", i, encoded, decoded);
            if (!nums.Add(encoded))
            {
                Console.WriteLine("Duplicate");
            }
        }
    }

    private long MultiplicativeInverse(long x, long modulus)
    {
        return ExtendedEuclideanDivision(x, modulus).Item1%modulus;
    }

    private static Tuple<long, long> ExtendedEuclideanDivision(long a, long b)
    {
        if (a < 0)
        {
            var result = ExtendedEuclideanDivision(-a, b);
            return Tuple.Create(-result.Item1, result.Item2);
        }
        if (b < 0)
        {
            var result = ExtendedEuclideanDivision(a, -b);
            return Tuple.Create(result.Item1, -result.Item2);
        }
        if (b == 0)
        {
            return Tuple.Create(1L, 0L);
        }
        var q = a/b;
        var r = a%b;
        var rslt = ExtendedEuclideanDivision(b, r);
        var s = rslt.Item1;
        var t = rslt.Item2;
        return Tuple.Create(t, s - q*t);
    }

从 0-100 范围内的输入生成 0-100 范围内的数字。每个输入都会产生一个唯一的输出。

它还展示了如何使用乘法逆运算来逆过程。

您可以通过增加m 的值来扩展范围。 x 必须与 m 互质。

代码抄自 Eric Lippert 的文章 A practical use of multiplicative inverses,以及该系列之前的几篇文章。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-01
    • 1970-01-01
    • 2020-10-17
    相关资源
    最近更新 更多