将字符串转换为随机但确定性可重复的均匀概率
Convert string to random but deterministically repeatable uniform probability
如何转换字符串,例如一个用户 ID 加盐,到一个随机的但实际上是半开放范围 [0.0, 1.0) 中确定性可重复的均匀概率?这 means 即输出 ≥ 0.0 且 < 1.0。无论输入分布如何,输出分布必须均匀。例如,如果输入字符串是 'a3b2Foobar',则输出概率可以重复为 0.40341504.
需要跨语言和跨平台的算法重现性。除非有更好的方法,否则我倾向于使用哈希函数。这是我拥有的:
>>> in_str = 'a3b2Foobar'
>>> (int(hashlib.sha256(in_str.encode()).hexdigest(), 16) % 1e8) / 1e8
0.40341504
我使用的是最新的稳定版 Python 3. 请注意,此问题与 的相关问题类似但不完全相同。
使用散列
密码散列可能是 [0, MAX_HASH] 范围内均匀分布的整数。因此,它可以通过将其除以 MAX_HASH + 1.
来缩放为 [0, 1) 范围内的浮点数
import hashlib
Hash = hashlib.sha512
MAX_HASH_PLUS_ONE = 2**(Hash().digest_size * 8)
def str_to_probability(in_str):
"""Return a reproducible uniformly random float in the interval [0, 1) for the given string."""
seed = in_str.encode()
hash_digest = Hash(seed).digest()
hash_int = int.from_bytes(hash_digest, 'big') # Uses explicit byteorder for system-agnostic reproducibility
return hash_int / MAX_HASH_PLUS_ONE # Float division
>>> str_to_probability('a3b2Foobar')
0.3659629991207491
这是一个真实的世界usage example。
备注:
- 内置
hash
不能使用方法,因为它可以保留输入的
分布,例如hash(123)
。或者,当 Python 重新启动时,它可以 return 不同的值,例如hash('123')
.
- 不需要使用模数,因为浮点数除法就足够了。
使用随机
random
module can be used with in_str
as its seed, while addressing concerns surrounding both thread safety 和连续性。
使用这种方法,不仅跨语言的可再现性是一个问题,Python 多个未来版本的可再现性也可能是一个问题。因此不推荐。
import random
def str_to_probability(in_str):
"""Return a reproducible uniformly random float in the interval [0, 1) for the given seed."""
return random.Random(in_str).random()
>>> str_to_probability('a3b2Foobar')
0.4662507245848473
如何转换字符串,例如一个用户 ID 加盐,到一个随机的但实际上是半开放范围 [0.0, 1.0) 中确定性可重复的均匀概率?这 means 即输出 ≥ 0.0 且 < 1.0。无论输入分布如何,输出分布必须均匀。例如,如果输入字符串是 'a3b2Foobar',则输出概率可以重复为 0.40341504.
需要跨语言和跨平台的算法重现性。除非有更好的方法,否则我倾向于使用哈希函数。这是我拥有的:
>>> in_str = 'a3b2Foobar'
>>> (int(hashlib.sha256(in_str.encode()).hexdigest(), 16) % 1e8) / 1e8
0.40341504
我使用的是最新的稳定版 Python 3. 请注意,此问题与
使用散列
密码散列可能是 [0, MAX_HASH] 范围内均匀分布的整数。因此,它可以通过将其除以 MAX_HASH + 1.
来缩放为 [0, 1) 范围内的浮点数import hashlib
Hash = hashlib.sha512
MAX_HASH_PLUS_ONE = 2**(Hash().digest_size * 8)
def str_to_probability(in_str):
"""Return a reproducible uniformly random float in the interval [0, 1) for the given string."""
seed = in_str.encode()
hash_digest = Hash(seed).digest()
hash_int = int.from_bytes(hash_digest, 'big') # Uses explicit byteorder for system-agnostic reproducibility
return hash_int / MAX_HASH_PLUS_ONE # Float division
>>> str_to_probability('a3b2Foobar')
0.3659629991207491
这是一个真实的世界usage example。
备注:
- 内置
hash
不能使用方法,因为它可以保留输入的 分布,例如hash(123)
。或者,当 Python 重新启动时,它可以 return 不同的值,例如hash('123')
. - 不需要使用模数,因为浮点数除法就足够了。
使用随机
random
module can be used with in_str
as its seed, while addressing concerns surrounding both thread safety 和连续性。
使用这种方法,不仅跨语言的可再现性是一个问题,Python 多个未来版本的可再现性也可能是一个问题。因此不推荐。
import random
def str_to_probability(in_str):
"""Return a reproducible uniformly random float in the interval [0, 1) for the given seed."""
return random.Random(in_str).random()
>>> str_to_probability('a3b2Foobar')
0.4662507245848473