Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,4 @@ result*
tests/resources/hashlib-test-large-local.txt
tests/function-library-index.json
.claude/settings.local.json
.codex
84 changes: 84 additions & 0 deletions devel/215_18.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# [215_18] 实现 (liii random) 模块

## 任务相关的代码文件
- `goldfish/liii/random.scm` - (liii random) 导出模块
- `goldfish/srfi/srfi-27.scm` - SRFI-27 实现
- `tests/goldfish/liii/random-test.scm` - 测试文件

## 如何测试
```bash
# 1. 构建
xmake b goldfish

# 2. 格式化代码
bin/gf fix goldfish/liii/random.scm
bin/gf fix goldfish/srfi/srfi-27.scm
bin/gf fix tests/goldfish/liii/random-test.scm

# 3. 运行测试
bin/gf tests/goldfish/liii/random-test.scm
```

## 2025-04-03 实现 (liii random) 模块

### What
实现基于 SRFI-27 的随机数生成模块,包括:

1. **创建文件 `goldfish/liii/random.scm`**
- 作为导出模块,导入并重导出 (srfi srfi-27) 的所有功能

2. **创建文件 `goldfish/srfi/srfi-27.scm`**
- 基于 s7.c 内置的 random 函数实现 SRFI-27 规范
- 使用 Sebastian Egner 的版权和许可证(SRFI-27 原始版权)
- 实现 random-source 记录类型
- 实现 SRFI-27 标准函数

3. **创建测试文件 `tests/liii/random-test.scm`**
- 作为函数分类索引和文档说明

4. **创建单个函数测试文件 `tests/liii/random/` 目录**
- `random-integer-test.scm` - random-integer 测试
- `random-real-test.scm` - random-real 测试
- `make-random-source-test.scm` - make-random-source 测试
- `random-source-p-test.scm` - random-source? 测试
- `random-source-state-ref-test.scm` - random-source-state-ref 测试
- `random-source-state-set-test.scm` - random-source-state-set! 测试
- `random-source-randomize-test.scm` - random-source-randomize! 测试
- `random-source-pseudo-randomize-test.scm` - random-source-pseudo-randomize! 测试
- `random-source-make-integers-test.scm` - random-source-make-integers 测试
- `random-source-make-reals-test.scm` - random-source-make-reals 测试
- `reproducibility-test.scm` - 可复现性测试

### Why
Goldfish Scheme 需要标准的随机数生成接口,SRFI-27 是 Scheme 社区广泛接受的标准。
s7.c 内置了 `random` 函数和 `random-state` 类型,基于这些内置功能实现 SRFI-27 可以:
1. 利用 s7.c 的高性能随机数生成器
2. 提供符合标准 SRFI-27 的接口
3. 保持与现有 Scheme 生态系统的兼容性

### How

#### s7.c 内置功能
- `(random n)` - 返回 [0, n) 范围内的随机数
- `(random n state)` - 使用指定的 random-state
- `(random-state seed)` - 创建新的 random-state
- `(random-state? obj)` - 检查是否为 random-state
- `(random-state->list state)` - 将状态转换为列表 `(seed carry)`

#### SRFI-27 与 s7.c 的映射
SRFI-27 的 random-source 是一个记录类型,包含:
- state-ref: 返回状态
- state-set!: 设置状态
- randomize!: 用时间随机化
- pseudo-randomize!: 用索引伪随机化
- make-integers: 创建整数生成器
- make-reals: 创建实数生成器

状态格式:s7.c 的 random-state 可以用 `(random-state->list state)` 获取为 `(seed carry)` 列表

#### 实现要点
1. 使用 `define-record-type` 定义 random-source 类型
2. 使用 s7.c 的 `(random-state seed)` 创建新的状态
3. 使用 `(random-state->list state)` 获取和设置状态
4. 使用 `(random n state)` 生成随机数
5. 用当前时间(纳秒)作为 `random-source-randomize!` 的熵源
50 changes: 50 additions & 0 deletions goldfish/liii/random.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
;
; Copyright (C) 2025 The Goldfish Scheme Authors
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
; http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
; WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
; License for the specific language governing permissions and limitations
; under the License.

;;
;; (liii random) - Random number generation
;;
;; This module exports the SRFI-27 interface for random number generation.
;; It re-exports all symbols from (srfi srfi-27).
;;
;; Exported functions:
;; random-integer - Generate random integer in [0, n-1]
;; random-real - Generate random real in (0, 1)
;; default-random-source - The default random source
;; make-random-source - Create a new random source
;; random-source? - Check if object is a random source
;; random-source-state-ref - Get the state of a random source
;; random-source-state-set!- Set the state of a random source
;; random-source-randomize!- Randomize a source with current time
;; random-source-pseudo-randomize! - Deterministically set source state
;; random-source-make-integers - Create integer generator from source
;; random-source-make-reals - Create real generator from source

(define-library (liii random)
(import (srfi srfi-27))
(export
random-integer
random-real
default-random-source
make-random-source
random-source?
random-source-state-ref
random-source-state-set!
random-source-randomize!
random-source-pseudo-randomize!
random-source-make-integers
random-source-make-reals
) ;export
) ;define-library
247 changes: 247 additions & 0 deletions goldfish/srfi/srfi-27.scm
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
;; SRFI-27 Implementation for Goldfish Scheme
;;
;; This is an implementation of SRFI-27 "Sources of Random Bits".
;; It is based on s7.c's built-in random functions.
;;
;; Copyright (C) Sebastian Egner (2002). All Rights Reserved.
;;
;; Permission is hereby granted, free of charge, to any person obtaining
;; a copy of this software and associated documentation files (the
;; "Software"), to deal in the Software without restriction, including
;; without limitation the rights to use, copy, modify, merge, publish,
;; distribute, sublicense, and/or sell copies of the Software, and to
;; permit persons to whom the Software is furnished to do so, subject to
;; the following conditions:
;;
;; The above copyright notice and this permission notice shall be
;; included in all copies or substantial portions of the Software.
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
;; LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
;; OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
;; WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

(define-library (srfi srfi-27)
(import (scheme base)
(srfi srfi-19)
(liii error)
) ;import
(export
random-integer
random-real
default-random-source
make-random-source
random-source?
random-source-state-ref
random-source-state-set!
random-source-randomize!
random-source-pseudo-randomize!
random-source-make-integers
random-source-make-reals
) ;export
(begin

;; ====================
;; Random Source Record Type
;; ====================
;; A random-source is a record containing:
;; - state: the underlying s7 random-state object
;; - state-ref: thunk to get the state as external representation
;; - state-set!: procedure to set state from external representation
;; - randomize!: procedure to randomize state
;; - pseudo-randomize!: procedure to pseudo-randomize with indices
;; - make-integers: procedure returning a random-integer generator
;; - make-reals: procedure returning a random-real generator

(define-record-type <random-source>
(%make-random-source state state-ref state-set! randomize! pseudo-randomize! make-integers make-reals)
random-source?
(state random-source-internal-state)
(state-ref random-source-state-ref-proc)
(state-set! random-source-state-set-proc)
(randomize! random-source-randomize-proc)
(pseudo-randomize! random-source-pseudo-randomize-proc)
(make-integers random-source-make-integers-proc)
(make-reals random-source-make-reals-proc)
) ;define-record-type

;; ====================
;; Internal Helpers
;; ====================

;; Get current time in nanoseconds as integer
;; Used for randomization
(define (current-time-nanoseconds)
(let ((t (current-time TIME-UTC)))
(+ (* (time-second t) 1000000000)
(time-nanosecond t)
) ;+
) ;let
) ;define

;; Create a new s7 random-state with given seed and carry
(define (make-s7-random-state seed carry)
(random-state seed carry)
) ;define

;; Get state as list (seed carry)
(define (get-s7-state state)
(random-state->list state)
) ;define

;; ====================
;; Random Source Operations
;; ====================

(define (make-random-source)
(let ((state (random-state 0))) ; Create initial state with seed 0
Comment on lines +99 to +100
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! 处理,所有新建的随机源都会产生完全相同的随机数序列。建议在文档中明确说明此行为,提示用户需显式随机化才能获得独立序列。

(%make-random-source
state
;; state-ref: return external representation
(lambda ()
(cons 'random-source-state (random-state->list state))
) ;lambda
;; state-set!: set state from external representation
(lambda (new-state)
(unless (and (pair? new-state)
(eq? (car new-state) 'random-source-state)
(= (length new-state) 3))
(error 'wrong-type-arg "invalid random source state" new-state)
) ;unless
(let ((seed (cadr new-state))
(carry (caddr new-state)))
(set! state (random-state seed carry))
) ;let
) ;lambda
;; randomize!: use current time to randomize
(lambda ()
(let ((ns (current-time-nanoseconds)))
;; Use nanoseconds to create a pseudo-random seed
(let ((seed (modulo ns 4294967296))
(carry (modulo (quotient ns 4294967296) 4294967296)))
(set! state (random-state seed carry))
) ;let
) ;let
) ;lambda
;; pseudo-randomize!: use i, j indices
(lambda (i j)
(unless (and (integer? i) (exact? i) (>= i 0))
(error 'wrong-type-arg "pseudo-randomize! i must be a non-negative exact integer" i)
) ;unless
(unless (and (integer? j) (exact? j) (>= j 0))
(error 'wrong-type-arg "pseudo-randomize! j must be a non-negative exact integer" j)
) ;unless
;; Create a deterministic state based on i and j
;; Using a simple hash of i and j to create seed and carry
(let ((seed (modulo (+ (* i 12345) j) 4294967296))
(carry (modulo (+ (* j 54321) i) 4294967296)))
(set! state (random-state seed carry))
) ;let
) ;lambda
;; make-integers: return a procedure that generates random integers
(lambda ()
(lambda (n)
(unless (and (integer? n) (exact? n) (positive? n))
(error 'wrong-type-arg "random-integer: n must be a positive exact integer" n)
) ;unless
;; s7's random returns [0, n), we need [0, n-1] which is the same
(random n state)
) ;lambda
) ;lambda
;; make-reals: return a procedure that generates random reals
(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
Comment on lines +170 to +173
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 只是一个任意选取的小数。建议修正注释,说明这是一个极小的正实数替代值,而非最小正浮点数。

) ;let
) ;lambda
) ;let
) ;lambda
Comment on lines +155 to +177
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 值。目前这个参数只是被接受后丢弃,属于逻辑错误。

) ;%make-random-source
) ;let
) ;define

;; ====================
;; Standard Interface
;; ====================

(define default-random-source (make-random-source))

(define (random-integer n)
((random-source-make-integers default-random-source) n)
) ;define

(define (random-real)
((random-source-make-reals default-random-source))
) ;define

;; ====================
;; Random Source State Operations
;; ====================

(define (random-source-state-ref s)
(unless (random-source? s)
(error 'wrong-type-arg "random-source-state-ref: expected random-source" s)
) ;unless
((random-source-state-ref-proc s))
) ;define

(define (random-source-state-set! s new-state)
(unless (random-source? s)
(error 'wrong-type-arg "random-source-state-set!: expected random-source" s)
) ;unless
((random-source-state-set-proc s) new-state)
) ;define

(define (random-source-randomize! s)
(unless (random-source? s)
(error 'wrong-type-arg "random-source-randomize!: expected random-source" s)
) ;unless
((random-source-randomize-proc s))
) ;define

(define (random-source-pseudo-randomize! s i j)
(unless (random-source? s)
(error 'wrong-type-arg "random-source-pseudo-randomize!: expected random-source" s)
) ;unless
((random-source-pseudo-randomize-proc s) i j)
) ;define

;; ====================
;; Random Source Generator Creation
;; ====================

(define (random-source-make-integers s)
(unless (random-source? s)
(error 'wrong-type-arg "random-source-make-integers: expected random-source" s)
) ;unless
((random-source-make-integers-proc s))
) ;define

(define (random-source-make-reals s . unit)
(unless (random-source? s)
(error 'wrong-type-arg "random-source-make-reals: expected random-source" s)
) ;unless
(apply (random-source-make-reals-proc s) unit)
) ;define

) ;begin
) ;define-library
Loading
Loading