-
Notifications
You must be signed in to change notification settings - Fork 35
[215_18] 实现 (liii random) 和 (srfi srfi-27) 随机数模块 #666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
2 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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!` 的熵源 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 | ||
| (%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
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) ;let | ||
| ) ;lambda | ||
| ) ;let | ||
| ) ;lambda | ||
|
Comment on lines
+155
to
+177
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) ;%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 | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
make-random-source总是以(random-state 0)作为初始状态。未经过pseudo-randomize!或randomize!处理,所有新建的随机源都会产生完全相同的随机数序列。建议在文档中明确说明此行为,提示用户需显式随机化才能获得独立序列。