Skip to content

[215_18] 实现 (liii random) 和 (srfi srfi-27) 随机数模块#666

Merged
da-liii merged 2 commits intomainfrom
da/215_18/random
Apr 3, 2026
Merged

[215_18] 实现 (liii random) 和 (srfi srfi-27) 随机数模块#666
da-liii merged 2 commits intomainfrom
da/215_18/random

Conversation

@da-liii
Copy link
Copy Markdown
Contributor

@da-liii da-liii commented Apr 3, 2026

摘要

实现 SRFI-27 随机数生成器及相关功能:

  • (srfi srfi-27) 模块:提供符合 SRFI-27 规范的随机数生成接口
  • (liii random) 模块:提供更便捷的随机数 API

新增文件

  • goldfish/liii/random.scm - liii random 模块实现
  • goldfish/srfi/srfi-27.scm - SRFI-27 标准实现
  • devel/215_18.md - 开发文档
  • tests/liii/random-test.scm - 基础测试
  • tests/liii/random/*.scm - 各功能详细测试

测试计划

  • 所有新增测试用例通过
  • 符合 SRFI-27 规范

🤖 Generated with Claude Code

@da-liii da-liii merged commit 37e4730 into main Apr 3, 2026
4 checks passed
@da-liii da-liii deleted the da/215_18/random branch April 3, 2026 15:41
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 3, 2026

Greptile Summary

本 PR 实现了 (srfi srfi-27) 随机数生成器标准及基于它的 (liii random) 便捷封装模块,采用 s7 Scheme 内置的 random-state / random 作为底层引擎,通过闭包共享状态变量的方式实现了记录类型的可变状态语义。

主要变更:

  • goldfish/srfi/srfi-27.scm:基于 s7 内置 random 函数完整实现 SRFI-27 接口,包括随机源记录类型、状态保存/恢复、时间随机化和伪随机化,以及整数/实数生成器工厂。
  • goldfish/liii/random.scm:薄包装层,将 (srfi srfi-27) 全部导出符号重导出到 (liii random)
  • 测试文件:覆盖每个 API 函数的独立测试文件以及可复现性测试。

发现的问题:

  • random-source-make-reals 接受并校验 unit 参数,但实际生成时完全忽略了它,违反 SRFI-27 规范(P1 逻辑 bug)。
  • random-real-test.scm 末尾的"范围验证"使用闭区间 >=/<=,与 SRFI-27 要求的开区间 (0,1) 矛盾(P1)。
  • random-source-randomize-test.scm 中"多次随机化产生不同状态"的测试依赖纳秒级时间差,在高速机器上可能成为不稳定测试(P1)。
  • 所有 make-random-source 调用固定以 seed=0 初始化,未经显式随机化的新源会产生相同序列(P2 设计建议)。
  • 零值回退的魔法数字注释描述不准确(P2)。

Confidence Score: 3/5

存在一个 SRFI-27 规范违反(unit 参数被忽略)和两个测试逻辑问题,建议修复后合并。

核心随机数生成功能实现正确,但 random-source-make-reals 的 unit 参数被接受和校验后未实际使用,违反 SRFI-27 规范;random-real-test.scm 末尾范围检查用了闭区间与规范矛盾;randomize 测试存在时间竞争条件。这些问题影响了规范符合度和测试可靠性,因此扣分。

重点关注 goldfish/srfi/srfi-27.scm(unit 参数逻辑 bug、初始 seed 问题)以及 tests/liii/random/random-real-test.scm 和 tests/liii/random/random-source-randomize-test.scm(测试逻辑问题)。

Important Files Changed

Filename Overview
goldfish/srfi/srfi-27.scm SRFI-27 核心实现:使用闭包共享 state 变量的方式实现随机源记录类型,整体结构合理,但存在 unit 参数被忽略的逻辑 bug、所有新源固定以 seed=0 初始化的设计问题,以及零值回退的注释有误。
goldfish/liii/random.scm 薄包装层,将 (srfi srfi-27) 的全部符号重导出到 (liii random),逻辑简单无问题。
tests/liii/random/random-source-randomize-test.scm "多次随机化产生不同状态"测试依赖纳秒级时间差,在高速机器上可能是不稳定测试(flaky test)。
tests/liii/random/random-real-test.scm 前两个范围检查正确使用开区间,但末尾"范围验证"改用闭区间 >= 和 <=,与 SRFI-27 规范及文档矛盾。
tests/liii/random/reproducibility-test.scm 可复现性测试逻辑正确:验证了状态保存/恢复和相同伪随机化索引产生相同序列。
tests/liii/random/random-source-make-reals-test.scm 测试 unit 参数时仅验证了生成值范围,未验证 unit 参数对精度的实际影响(因实现本身就忽略了 unit)。
devel/215_18.md 开发文档格式符合规范,清晰描述了任务目标、文件列表、测试步骤和实现细节。

Sequence Diagram

sequenceDiagram
    participant U as 用户代码
    participant LR as (liii random)
    participant S27 as (srfi srfi-27)
    participant S7 as s7 random 内置

    U->>LR: (import (liii random))
    LR->>S27: re-export all symbols

    U->>S27: (make-random-source)
    S27->>S7: (random-state 0)
    S7-->>S27: state 对象
    S27-->>U: random-source 记录

    U->>S27: (random-source-pseudo-randomize! s i j)
    S27->>S7: (random-state seed carry)
    S7-->>S27: 新 state
    S27->>S27: set! state 更新闭包变量

    U->>S27: (random-source-make-integers s)
    S27-->>U: (lambda (n) (random n state))

    U->>S7: rand-int 调用 → (random n state)
    S7-->>U: 随机整数 [0, n-1]

    U->>S27: (random-source-state-ref s)
    S27->>S7: (random-state->list state)
    S7-->>U: (random-source-state seed carry)

    U->>S27: (random-source-state-set! s saved)
    S27->>S7: (random-state seed carry)
    S27->>S27: set! state 恢复闭包变量
Loading

Reviews (1): Last reviewed commit: "[215_18] 实现 (liii random) 和 (srfi srfi-2..." | Re-trigger Greptile

Comment on lines +155 to +177
(lambda args
(let ((unit #f))
(if (pair? args)
(begin
(set! unit (car args))
(unless (and (real? unit) (< 0 unit 1))
(error 'wrong-type-arg "random-source-make-reals: unit must be a real in (0,1)" unit)
) ;unless
) ;begin
) ;if
(lambda ()
(let ((r (random 1.0 state)))
;; random returns [0.0, 1.0), but SRFI-27 requires (0, 1)
;; s7's random for reals already returns (0, 1) when n > 0
;; But we need to ensure we never return 0 or 1
(if (zero? r)
0.0000000000000001 ; smallest positive value
r
) ;if
) ;let
) ;lambda
) ;let
) ;lambda
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 unit 参数被验证但从未使用

random-source-make-reals 接受可选的 unit 参数,对其进行了校验(确保在 (0,1) 范围内),但实际生成随机数时完全忽略了它。根据 SRFI-27 规范,unit 用于指定输出浮点数的精度(即生成的实数是 unit 的整数倍),但当前实现始终调用 (random 1.0 state) 而不考虑 unit 值。目前这个参数只是被接受后丢弃,属于逻辑错误。

Comment on lines +44 to +53
; 多次随机化产生不同状态
(let ((s (make-random-source)))
(random-source-randomize! s)
(let ((state1 (random-source-state-ref s)))
(random-source-randomize! s)
(let ((state2 (random-source-state-ref s)))
(check (not (equal? state1 state2)) => #t)
)
)
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 随机化测试存在时间竞争条件(可能是不稳定测试)

"多次随机化产生不同状态"的测试依赖两次 random-source-randomize! 调用之间的纳秒级时间差。若在高速机器或系统时钟精度有限时两次调用恰好在同一纳秒内完成,current-time-nanoseconds 返回值相同,导致 state1 == state2,测试失败。建议改为对比初始状态(seed=0)与随机化后状态。

Comment on lines +42 to +44
(check (>= r 0.0) => #t)
(check (<= r 1.0) => #t)
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 范围验证与文档不一致(使用了闭区间而非开区间)

前面第 30-31 行正确地使用开区间(> 0< 1)验证 SRFI-27 要求的 (0, 1) 范围,但"范围验证"部分改用闭区间 >=<=,允许返回 0.0 或 1.0,与 SRFI-27 规范及上方测试矛盾:

Suggested change
(check (>= r 0.0) => #t)
(check (<= r 1.0) => #t)
)
(check (> r 0.0) => #t)
(check (< r 1.0) => #t)

Comment on lines +99 to +100
(define (make-random-source)
(let ((state (random-state 0))) ; Create initial state with seed 0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 所有新建随机源初始状态相同

make-random-source 总是以 (random-state 0) 作为初始状态。未经过 pseudo-randomize!randomize! 处理,所有新建的随机源都会产生完全相同的随机数序列。建议在文档中明确说明此行为,提示用户需显式随机化才能获得独立序列。

Comment on lines +170 to +173
(if (zero? r)
0.0000000000000001 ; smallest positive value
r
) ;if
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 "最小正值"注释及魔法数字有误

注释声称 0.0000000000000001 是"最小正值",但这并不正确。IEEE 754 双精度浮点的最小正规格化数约为 2.2e-3081e-16 只是一个任意选取的小数。建议修正注释,说明这是一个极小的正实数替代值,而非最小正浮点数。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant