# 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)