snapshot before regression test
This commit is contained in:
379
includes/vrandom.py
Normal file
379
includes/vrandom.py
Normal file
@@ -0,0 +1,379 @@
|
||||
# vrandom - 硬件随机数生成库
|
||||
# 基于 x86 RDRAND / RDSEED 指令,使用内嵌汇编实现
|
||||
import t, c
|
||||
import vipermath
|
||||
|
||||
|
||||
# 重试次数限制(RDRAND 通常不需要重试,RDSEED 可能需要)
|
||||
RDRAND_RETRY_LIMIT: t.CDefine = 10
|
||||
RDSEED_RETRY_LIMIT: t.CDefine = 100
|
||||
|
||||
|
||||
# ============================================================
|
||||
# RDRAND - 硬件随机数(伪随机数发生器输出)
|
||||
# ============================================================
|
||||
|
||||
def rdrand16() -> t.CUInt16T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return t.CUInt16T(val)
|
||||
|
||||
|
||||
def rdrand32() -> t.CUInt32T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
def rdrand64() -> t.CUInt64T:
|
||||
val: t.CUInt64T = 0
|
||||
c.Asm(f"rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
# ============================================================
|
||||
# RDSEED - 硬件随机种子(熵源直接输出)
|
||||
# ============================================================
|
||||
|
||||
def rdseed16() -> t.CUInt16T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return t.CUInt16T(val)
|
||||
|
||||
|
||||
def rdseed32() -> t.CUInt32T:
|
||||
val: t.CUInt32T = 0
|
||||
c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
def rdseed64() -> t.CUInt64T:
|
||||
val: t.CUInt64T = 0
|
||||
c.Asm(f"rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC])
|
||||
return val
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Step 版本(带成功标志,匹配 GCC builtin 接口)
|
||||
# 返回 1 表示成功,0 表示失败;随机值写入 *p
|
||||
# ============================================================
|
||||
|
||||
def rdrand16_step(p: t.CUInt16T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = t.CUInt16T(val)
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdrand32_step(p: t.CUInt32T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdrand64_step(p: t.CUInt64T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt64T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdrand {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdseed16_step(p: t.CUInt16T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = t.CUInt16T(val)
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdseed32_step(p: t.CUInt32T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt32T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
def rdseed64_step(p: t.CUInt64T | t.CPtr) -> t.CInt:
|
||||
val: t.CUInt64T = 0
|
||||
ok: t.CUInt32T = 0
|
||||
c.Asm(f"""rdseed {c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG)}
|
||||
setc al
|
||||
movzx {c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)}, al""",
|
||||
out=[c.AsmOut(val, t.ASM_DESCR.OUTPUT_REG), c.AsmOut(ok, t.ASM_DESCR.OUTPUT_REG)],
|
||||
op=[t.ASM_DESCR.CLOBBER_CC, t.ASM_DESCR.CLOBBER_AL])
|
||||
p[0] = val
|
||||
return t.CInt(ok)
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 带重试的便捷接口(自动重试直到成功或达到上限)
|
||||
# ============================================================
|
||||
|
||||
def random_u16() -> t.CUInt16T:
|
||||
r: t.CUInt16T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDRAND_RETRY_LIMIT:
|
||||
if rdrand16_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def random_u32() -> t.CUInt32T:
|
||||
r: t.CUInt32T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDRAND_RETRY_LIMIT:
|
||||
if rdrand32_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def random_u64() -> t.CUInt64T:
|
||||
r: t.CUInt64T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDRAND_RETRY_LIMIT:
|
||||
if rdrand64_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def seed_u16() -> t.CUInt16T:
|
||||
r: t.CUInt16T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDSEED_RETRY_LIMIT:
|
||||
if rdseed16_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def seed_u32() -> t.CUInt32T:
|
||||
r: t.CUInt32T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDSEED_RETRY_LIMIT:
|
||||
if rdseed32_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
def seed_u64() -> t.CUInt64T:
|
||||
r: t.CUInt64T = 0
|
||||
i: t.CInt = 0
|
||||
while i < RDSEED_RETRY_LIMIT:
|
||||
if rdseed64_step(c.Addr(r)) == 1:
|
||||
return r
|
||||
i += 1
|
||||
return 0
|
||||
|
||||
|
||||
# ============================================================
|
||||
# Python random 标准库函数实现
|
||||
# 默认类型:t.CUInt64T (u64), t.CDouble (f64), t.CInt (i32)
|
||||
# ============================================================
|
||||
|
||||
# ---------- 一、随机整数 ----------
|
||||
|
||||
def randint(a: t.CInt, b: t.CInt) -> t.CInt:
|
||||
return t.CInt(a + t.CInt(random_u64() % t.CUInt64T(b - a + 1)))
|
||||
|
||||
|
||||
def randrange(start: t.CInt, stop: t.CInt, step: t.CInt = 1) -> t.CInt:
|
||||
width: t.CInt = 0
|
||||
if step > 0:
|
||||
width = (stop - start + step - 1) // step
|
||||
else:
|
||||
width = (start - stop - step - 1) // (-step)
|
||||
return t.CInt(start + t.CInt(random_u64() % t.CUInt64T(width)) * step)
|
||||
|
||||
|
||||
def getrandbits(k: t.CInt) -> t.CUInt64T:
|
||||
r: t.CUInt64T = rdrand64()
|
||||
if k >= 64:
|
||||
return r
|
||||
mask: t.CUInt64T = (t.CUInt64T(1) << k) - t.CUInt64T(1)
|
||||
return r & mask
|
||||
|
||||
|
||||
# ---------- 二、随机浮点数 ----------
|
||||
|
||||
def random() -> t.CDouble:
|
||||
return t.CDouble(rdrand64() >> 11) * (t.CDouble(1.0) / t.CDouble(9007199254740992.0))
|
||||
|
||||
|
||||
def uniform(a: t.CDouble, b: t.CDouble) -> t.CDouble:
|
||||
return a + (b - a) * random()
|
||||
|
||||
|
||||
def triangular(low: t.CDouble, high: t.CDouble, mode: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
c: t.CDouble = (mode - low) / (high - low)
|
||||
if u > c:
|
||||
u = t.CDouble(1.0) - u
|
||||
c = t.CDouble(1.0) - c
|
||||
tmp: t.CDouble = low
|
||||
low = high
|
||||
high = tmp
|
||||
return low + (high - low) * vipermath.sqrt(u * c)
|
||||
|
||||
|
||||
def betavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble:
|
||||
y: t.CDouble = gammavariate(alpha, t.CDouble(1.0))
|
||||
if y != t.CDouble(0.0):
|
||||
return y / (y + gammavariate(beta, t.CDouble(1.0)))
|
||||
return t.CDouble(0.0)
|
||||
|
||||
|
||||
def expovariate(lambd: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return -vipermath.log(t.CDouble(1.0) - u) / lambd
|
||||
|
||||
|
||||
def gammavariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = t.CDouble(0.0)
|
||||
d: t.CDouble = t.CDouble(0.0)
|
||||
c: t.CDouble = t.CDouble(0.0)
|
||||
x: t.CDouble = t.CDouble(0.0)
|
||||
v: t.CDouble = t.CDouble(0.0)
|
||||
if alpha <= t.CDouble(0.0) or beta <= t.CDouble(0.0):
|
||||
return t.CDouble(0.0)
|
||||
if alpha < t.CDouble(1.0):
|
||||
u = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return gammavariate(alpha + t.CDouble(1.0), beta) * vipermath.pow(u, t.CDouble(1.0) / alpha)
|
||||
d = alpha - t.CDouble(1.0) / t.CDouble(3.0)
|
||||
c = t.CDouble(1.0) / vipermath.sqrt(t.CDouble(9.0) * d)
|
||||
while 1:
|
||||
x = gauss(t.CDouble(0.0), t.CDouble(1.0))
|
||||
v = t.CDouble(1.0) + c * x
|
||||
if v > t.CDouble(0.0):
|
||||
v = v * v * v
|
||||
u = random()
|
||||
if u < t.CDouble(1.0) - t.CDouble(0.0331) * x * x * x * x:
|
||||
return d * v * beta
|
||||
if vipermath.log(u) < t.CDouble(0.5) * x * x + d * (t.CDouble(1.0) - v + vipermath.log(v)):
|
||||
return d * v * beta
|
||||
|
||||
|
||||
def gauss(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble:
|
||||
u1: t.CDouble = random()
|
||||
u2: t.CDouble = random()
|
||||
if u1 < t.CDouble(1e-300):
|
||||
u1 = t.CDouble(1e-300)
|
||||
z0: t.CDouble = vipermath.sqrt(t.CDouble(-2.0) * vipermath.log(u1)) * vipermath.cos(t.CDouble(2.0) * vipermath.U_M_PI * u2)
|
||||
return mu + sigma * z0
|
||||
|
||||
|
||||
def normalvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble:
|
||||
NV_MAGICCONST: t.CDouble = t.CDouble(1.7155277699214135)
|
||||
u1: t.CDouble = t.CDouble(0.0)
|
||||
u2: t.CDouble = t.CDouble(0.0)
|
||||
z: t.CDouble = t.CDouble(0.0)
|
||||
zz: t.CDouble = t.CDouble(0.0)
|
||||
while 1:
|
||||
u1 = random()
|
||||
u2 = random()
|
||||
if u2 < t.CDouble(1e-300):
|
||||
continue
|
||||
z = NV_MAGICCONST * (u1 - t.CDouble(0.5)) / u2
|
||||
zz = z * z / t.CDouble(4.0)
|
||||
if zz <= t.CDouble(0.0) - vipermath.log(u2):
|
||||
break
|
||||
return mu + z * sigma
|
||||
|
||||
|
||||
def lognormvariate(mu: t.CDouble, sigma: t.CDouble) -> t.CDouble:
|
||||
return vipermath.exp(gauss(mu, sigma))
|
||||
|
||||
|
||||
def vonmisesvariate(mu: t.CDouble, kappa: t.CDouble) -> t.CDouble:
|
||||
if kappa <= t.CDouble(1e-6):
|
||||
return vipermath.U_M_PI * t.CDouble(2.0) * random()
|
||||
s: t.CDouble = t.CDouble(0.5) / kappa
|
||||
r: t.CDouble = s + vipermath.sqrt(t.CDouble(1.0) + s * s)
|
||||
u1: t.CDouble = t.CDouble(0.0)
|
||||
u2: t.CDouble = t.CDouble(0.0)
|
||||
u3: t.CDouble = t.CDouble(0.0)
|
||||
z: t.CDouble = t.CDouble(0.0)
|
||||
d: t.CDouble = t.CDouble(0.0)
|
||||
q: t.CDouble = t.CDouble(0.0)
|
||||
f: t.CDouble = t.CDouble(0.0)
|
||||
theta: t.CDouble = t.CDouble(0.0)
|
||||
two_pi: t.CDouble = vipermath.U_M_PI * t.CDouble(2.0)
|
||||
while 1:
|
||||
u1 = random()
|
||||
z = vipermath.cos(vipermath.U_M_PI * u1)
|
||||
d = t.CDouble(1.0) / (r + z)
|
||||
u2 = random()
|
||||
if u2 < t.CDouble(1.0) - d * d:
|
||||
break
|
||||
if u2 < (t.CDouble(1.0) - z) * vipermath.exp(kappa * (z - t.CDouble(1.0)) - d * kappa * r):
|
||||
break
|
||||
q = t.CDouble(1.0) / r
|
||||
f = (q + z) / (t.CDouble(1.0) + q * z)
|
||||
u3 = random()
|
||||
if u3 > t.CDouble(0.5):
|
||||
theta = mu + vipermath.acos(f)
|
||||
else:
|
||||
theta = mu - vipermath.acos(f)
|
||||
while theta < t.CDouble(0.0):
|
||||
theta += two_pi
|
||||
while theta >= two_pi:
|
||||
theta -= two_pi
|
||||
return theta
|
||||
|
||||
|
||||
def paretovariate(alpha: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return t.CDouble(1.0) / vipermath.pow(t.CDouble(1.0) - u, t.CDouble(1.0) / alpha)
|
||||
|
||||
|
||||
def weibullvariate(alpha: t.CDouble, beta: t.CDouble) -> t.CDouble:
|
||||
u: t.CDouble = random()
|
||||
if u < t.CDouble(1e-300):
|
||||
u = t.CDouble(1e-300)
|
||||
return alpha * vipermath.pow(t.CDouble(-1.0) * vipermath.log(t.CDouble(1.0) - u), t.CDouble(1.0) / beta)
|
||||
Reference in New Issue
Block a user