从没有重复的另一个人中产生确定性的INT

发布于 2025-02-12 06:33:52 字数 303 浏览 3 评论 0原文

我希望创建一个确定的数字生成函数,其中输入号始终会生成相同的数字,但是没有两个数字最终会生成相同的结果。

例如:

1 -> 3
2 -> 5
3 -> 4
4 -> 2
5 -> 1

但是,我需要为所有可以用特定数据类型表示的数字(例如INT64)代表的所有数字工作。

这感觉像是应该很简单或完全不可能的东西。是否有一些随机数生成方案可以保证这种分布,而无需我创建所有可能数字的数组,然后随机排序,然后使用索引(并在此期间让我用尽我的内存)?

非常感谢 f

I'm looking to create a deterministic number generation function where the input number will always generate the same number, but no two numbers will end up generating the same result.

E.g.:

1 -> 3
2 -> 5
3 -> 4
4 -> 2
5 -> 1

However I need this to work for all numbers that can be represented by a specific datatype, e.g. an int64.

This feels like something that should either be really straightforward, or completely impossible. Is there some random number generation scheme that guarantees this sort of distribution without me having to create an array of all possible numbers, randomly sort, and then use the index (and making me run out of memory in the meantime)?

Many thanks
F

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

像你 2025-02-19 06:33:54

您需要的转换公式是:

f(P) = (mP + s) mod n

// n = range - so for uint64 2^64
// s < range i.e. < 2^64
// m = must be coprime with n

这是仿射密码

mod确保它在所需的范围内,s是一个简单的偏移,m应该为 coprime 带有n
企业简单地表示nm不应共享任何常见因素。
由于n是2^64,其唯一的因素是2 - so m基本上不应偶尔(即2):2):

因此,对于uint64范围:

var (
    m = uint64(39293)    // some non-even number
    s = uint64(75321908) // some random number below 2^64
)

func transform(p uint64) uint64 {
    return p*m + s // implicitly mod'ed 2^64 by the type's size
}

这可能看起来很魔术,但是您可以说服自己,它可以与uint16

https://go.dev/play/p/ekb6sh3-sgu

uint64 将需要大量资源来运行:-)


更新

对于签名的数字(即int64)逻辑没有什么不同。由于我们知道我们使用uint64的唯一一对一映射,一种方法就是转换输入&amp;输出从UINT64INT64,反之亦然:

// original unsigned version
func transform(p uint64) uint64 {
    return m*p + s
}

func signedTransform(p int64) int64 {
    return int64(transform(uint64(p)))
}

再次是int16示例证明没有碰撞:

https://go.dev/play/p/fkw5flmk0fu

The transformation formula you need is:

f(P) = (mP + s) mod n

// n = range - so for uint64 2^64
// s < range i.e. < 2^64
// m = must be coprime with n

This is modular arithmetic as used in the Affine cipher.

The mod ensures it is within desired range, s is a simple shift and m should be coprime with n.
Coprime simply means n and m should not share any common factors.
Since n is 2^64 its only factors are the number 2 - so m should basically not be even (i.e. not divisible by 2):

So for uint64 range:

var (
    m = uint64(39293)    // some non-even number
    s = uint64(75321908) // some random number below 2^64
)

func transform(p uint64) uint64 {
    return p*m + s // implicitly mod'ed 2^64 by the type's size
}

This may appear magic, but you can convince yourself it works with uint16:

https://go.dev/play/p/EKB6SH3-SGu

(as uint64 would take quite some resources to run :-)


Update:

For signed numbers (i.e. int64) the logic is no different. Since we know we have a unique one-to-one mapping with uint64 one approach would simply be to convert inputs & outputs from uint64 to int64 and vice versa:

// original unsigned version
func transform(p uint64) uint64 {
    return m*p + s
}

func signedTransform(p int64) int64 {
    return int64(transform(uint64(p)))
}

again here's a int16 example proving there's no collisions:

https://go.dev/play/p/Fkw5FLMK0Fu

丶视觉 2025-02-19 06:33:54

要添加到 colm.anseo 答案,这种映射也被称为线性一致生成器

x n+1 =(ax n +c)mod m

当c≠0时,正确选择的参数允许所有种子值等于m的周期。这种情况才会发生,并且仅在以下情况下:

  • M和C相对较好时,
  • A-1由M的所有主要因素排除,
  • 如果M可以通过4分组4

。 –Dobell定理。

对于64位LCG a = 6364136223846793005和C = 1442695040888963407,来自Knuth看起来不错。

请注意,LCG映射为1-1,它将整个[0 ... 2 64 -1]区域映射到本身。如果需要,可以倒置。作为RNG,它具有独特的跳跃能力。

To add to colm.anseo answer, this kind of mapping is also known as Linear congruential generator.

Xn+1 = (aXn+c) mod m

When c ≠ 0, correctly chosen parameters allow a period equal to m, for all seed values. This will occur if and only if:

  • m and c are relatively prime,
  • a-1 is divisible by all prime factors of m,
  • a-1 is divisible by 4 if m is divisible by 4.

These three requirements are referred to as the Hull–Dobell Theorem.

For 64bit LCG a=6364136223846793005 and c=1442695040888963407 from Knuth looks good.

Note, that LCG mapping is 1-to-1, it maps whole [0...264-1] region to itself. You could invert it if you want. And as RNG it has distinctive ability for jump-ahead.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文