2 个版本
0.6.1 | 2023年5月31日 |
---|---|
0.6.0 | 2023年5月29日 |
#1029 in 数学
每月 25 次下载
10KB
60 行
➗ FRACTRAN_rs
➗
因为为什么不呢?
📜 语言
每个 FRACTRAN 程序由一个有限有序的正有理数(分数)元组组成。它接受一个自然数作为输入,并输出另一个自然数或不停止。为此,取输入数 n
并依次将其与每个分数 f
进行比较。如果 nf
是一个整数,则将此数字作为输入重新启动程序。如果我们到达分数列表的末尾而始终没有整数,则停止。
例如,以下是一个接收数字并输出其最大奇数因子的程序。
1/2
另一方面,这个程序接收形式为 2a3b 的输入并输出 5a+b。
5/2 5/3
我们可以将此视为加法程序的程序。同样,单个指令 5 / 6
将 2a3b 转换为 5max(a,b)。
最著名的 FRACTRAN 程序示例是 PRIMEGAME
17/91 78/85 19/51 23/38 29/33 77/29 95/23 77/19 1/17 11/13 13/11 15/2 1/7 55/1
给定输入 2,该程序永远不会停止,但每次它到达 2 的幂时,都是以 2p 的形式,p 是连续的素数。
🦄 使用 FRACTRAN_rs
有关使用示例,请参阅 examples
文件夹。可以使用 fractran!
宏构建简单的程序
#[macro_use]
use fractran_rs::*;
let program : FractranProgram<usize, usize> = fractran!(5/2 5/3);
let result = program.run(24);
另一方面,您可能希望为任意数据类型提供自然数的编码和解码。例如,这里我们考虑一个假设的“在数组中查找”程序
#[macro_use]
use fractran_rs::*;
struct Input<'a>(usize, &'a [usize]);
impl<'a> Into<usize> for Input<'a> {
fn into(self) -> usize { todo!() }
}
struct Output(Option<usize>);
impl From<usize> for Output {
fn from(_: usize) -> Self { todo!() }
}
fn main() {
let program : FractranProgram<Input, Output> = fractran!(/* ... */);
let input = Input(3, &[2, 3, 5, 7, 11]);
let result = program.run(input);
}
您还可以“逐步执行”您的程序。为此,请对程序调用 start
,然后调用 next
#[macro_use]
use fractran_rs::*;
let primegame : FractranProgram<usize, usize> = fractran!(/* ... */);
let mut program_run = primegame.start(2);
program_run.next(); // Some(15)
program_run.next(); // Some(825)
// etc.
这作为迭代器接口实现,因此您可以使用以下方式运行整个程序
#[macro_use]
use fractran_rs::*;
let program : FractranProgram = fractran!(/* ... */);
for intermediate_result in program.start(3) {
// ...
}
🎨 相关技术和替代方案
如果您想编写Fractran并将其编译为机器码,可能会对fractran
和fractran_macros
感兴趣。这两个库在内部使用数的素数分解表示。
我强烈推荐阅读Michael Malis写的关于编写一个目标 FRACTRAN的编译器的优秀文章:Building FizzBuzz in FRACTRAN。
🚨 局限性
目前,FRACTRAN_rs
仅限于使用usize
作为分数的分子和分母。这是为了将代码库控制在100行以内。此外,截至编写时间,64位应该对任何人来说都足够了。
由于当前的经济环境,所有FRACTRAN_rs
程序必须是有限的。
👩🏼💻 贡献
FRACTRAN_rs已经被作者认为是功能完善的。然而,欢迎提交修复错误或建议新功能的拉取请求。