Compare commits
38 Commits
7b29b36a0c
...
v4
Author | SHA1 | Date | |
---|---|---|---|
de3da1f6a1 | |||
3d7c9c9048 | |||
b32ef1d348 | |||
bb453aba6b | |||
bab3afd790 | |||
17df20a502 | |||
51fa440e02 | |||
245acb784e | |||
baa447e054 | |||
b595629042 | |||
08a1cc5b30 | |||
81fbd200a8 | |||
6ef107b199 | |||
b3646b2c71 | |||
0eba0d32f6 | |||
e4d9573ffb | |||
101d6203a3 | |||
a5e33b30b3 | |||
43da672850 | |||
3d4c6fcf5c | |||
c81997e527 | |||
cbe09d0852 | |||
160db1948f | |||
011edf7bed | |||
aa71637fe6 | |||
3dbbb6da30 | |||
bcfb639da7 | |||
23b72c51ab | |||
f0d85878da | |||
9ceccfeec5 | |||
9ceda0f1a1 | |||
a47cd93b67 | |||
94b001fab7 | |||
af28f3cb21 | |||
dc6b7f7d0f | |||
c789053832 | |||
01d5fbac96 | |||
5ccf09c98f |
23
content/Entity Component System.md
Normal file
23
content/Entity Component System.md
Normal file
@@ -0,0 +1,23 @@
|
||||
#programming
|
||||
|
||||
|
||||
主にゲームエンジンなどで採用されるプログラミングのパラダイム。
|
||||
|
||||
最近のUnityでも内部的に採用されている。
|
||||
|
||||
[[Rust]]だと[[Bevy]]が有名。
|
||||
|
||||
[[オブジェクト指向]]と比べると、データのメモリ分布が、オブジェクトごとに並ぶのではなく個別のメンバー変数ごとに並ぶことになり、CPUのメモリキャッシュに乗りやすいなどの利点がある。
|
||||
|
||||
[\[Rust\] ECSアーキテクチャ \[bevy\_ecs\] | DevelopersIO](https://dev.classmethod.jp/articles/ecs-rust-bevy/)
|
||||
|
||||
[Intro to ECS - Unofficial Bevy Cheat Book](https://bevy-cheatbook.github.io/programming/ecs-intro.html)
|
||||
|
||||
## データのモデリング方法としてなにがうれしいのか
|
||||
|
||||
オブジェクト指向と比べた時の利点が基本的にさっきのような、パフォーマンス面での利点が強調されることが多い。ただ、何かパフォーマンスのためにせっかくプログラミング言語が用意してくれたデータのモデリング技法を犠牲にしているような気がしてならず、あんまり旨味がよくわからなかった。
|
||||
|
||||
ただ、Bevyの設計をいろいろ読んでいると、モデリングとしての核心は、「集合の中から特定の要素を持つもの部分集合を指定して挙動を個別に操作する(依存性がない操作同士はどういう順番で実行してもいい)」ということかなと思った。
|
||||
|
||||
|
||||
|
7
content/Gluon.md
Normal file
7
content/Gluon.md
Normal file
@@ -0,0 +1,7 @@
|
||||
#programming-language
|
||||
|
||||
[[Rust]]で書かれた、[[Lua]]のような埋め込みを想定しつつ静的型付けの言語。
|
||||
|
||||
モジュールの読み込みの文法とか複雑な型情報をRustと相互でやり取りする時のやりかたとか、参考になる
|
||||
|
||||
[Gluon](https://gluon-lang.org/)
|
9
content/Hackett.md
Normal file
9
content/Hackett.md
Normal file
@@ -0,0 +1,9 @@
|
||||
#programming-language
|
||||
|
||||
[[Racket]]上で実装された、静的型付けなうえで、型安全なマクロシステムを搭載したプログラミング言語
|
||||
|
||||
[1 The Hackett Guide](https://lexi-lambda.github.io/hackett/guide.html)
|
||||
|
||||
["Hackett: a metaprogrammable Haskell" by Alexis King - YouTube](https://www.youtube.com/watch?v=5QQdI3P7MdY)
|
||||
|
||||
|
@@ -4,3 +4,9 @@ date: 2024-10-04 13:31
|
||||
#person
|
||||
|
||||
[[Not Art&Tech - On the role of Media Theory at Universities of Applied Art, Technology and Art and Technology.]]
|
||||
|
||||
---
|
||||
|
||||
[Turing Complete User](https://contemporary-home-computing.org/turing-complete-user/)
|
||||
|
||||
[[橋本麦]]さんによる試訳 [『チューリング完全ユーザー』試訳 - baku](https://scrapbox.io/glisp/%E3%80%8E%E3%83%81%E3%83%A5%E3%83%BC%E3%83%AA%E3%83%B3%E3%82%B0%E5%AE%8C%E5%85%A8%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%80%8F%E8%A9%A6%E8%A8%B3)
|
||||
|
13
content/Red Green Syntax Tree.md
Normal file
13
content/Red Green Syntax Tree.md
Normal file
@@ -0,0 +1,13 @@
|
||||
#compiler-design
|
||||
|
||||
[Red-Green Trees: an Overview. Six months ago I dug into Roslyn’s… | by Bayastan | Jun, 2025 | Medium](https://medium.com/@krendelia2021/red-green-trees-an-overview-17bae2d84e8c)
|
||||
|
||||
[[抽象構文木]]というか[[具象構文木]]の実装方法の一つ。
|
||||
|
||||
構文の途中で差し込まれたコメントなどのトリビアなどを保持して、完全なソースコードに戻せるけど実行効率などをよくしたままにできるやり方。
|
||||
|
||||
部分的に構文木を書き換えたりするとソースコードのロケーション情報がずれたりするので、文字幅とオフセットを別々に持たせるというやり方をしている
|
||||
|
||||
ながいけどこれがわかりやすい
|
||||
|
||||
[Ruby Parser開発日誌 (19) - 最高の構文木の設計 2024年版 - かねこにっき](https://yui-knk.hatenablog.com/entry/2024/08/23/113543)
|
9
content/Rune.md
Normal file
9
content/Rune.md
Normal file
@@ -0,0 +1,9 @@
|
||||
#programming-language
|
||||
|
||||
[The Rune Programming Language](https://rune-rs.github.io/)
|
||||
|
||||
[[Rust]]で書かれた埋め込みプログラミング言語。
|
||||
|
||||
Rustの文法ほぼそのままに動的型付けの言語をつくるとこうなる、みたいな感じ
|
||||
|
||||
[[Moonbit]]とか[[Rhai]]も近い感じ(Rhaiは直接影響を受けたとのこと)
|
@@ -21,6 +21,7 @@ https://github.com/mimium-org/mimium-rs
|
||||
### 理論
|
||||
|
||||
- [[mimiumの部分的DSP更新とFaustのondemand]]
|
||||
- [[mimiumでのIOパラメーター]]
|
||||
|
||||
### 中間表現について
|
||||
|
||||
@@ -29,7 +30,12 @@ https://github.com/mimium-org/mimium-rs
|
||||
- [[mimiumのMIRコンパイル過程を真面目に考える]]
|
||||
- [[lambda-mmm(実用版)]]
|
||||
- [[mimiumグローバル環境評価について]]
|
||||
- [[多段階計算を命令型VMインストラクションで表現したい]]
|
||||
|
||||
|
||||
## マクロ
|
||||
|
||||
- [[mimiumと多段階計算]]
|
||||
|
||||
|
||||
### ランタイム周りについて
|
||||
|
||||
@@ -45,6 +51,13 @@ https://github.com/mimium-org/mimium-rs
|
||||
|
||||
ふと思ったけど、[[SuperCollider]]や[[PureData]]と比べると、これらの言語は組み込みに使おうと思うとLinuxが動く環境を想定することになる([[Heavy]]はそれを全く別の処理系作ることで対応してたけど)。シーケンサとかスケジューラーがあるような、[[Faust]]だと難しいタイプのプログラムを[[Arduino]]とかに持っていくには向いているのではないか([[Extempore]]だって仕組み的に言えばそうかもしれないけど)
|
||||
|
||||
- できれば教育用途とかに持ち込めるのが一番いい
|
||||
- ブートストラップできるといい
|
||||
- いろいろな人がmimiumで拡張やライブラリを書けるようになってからが本当の本番
|
||||
- 言語自体の拡張機能をその言語上でたくさん作れるとよい
|
||||
- しかし、極端に自由度が高いとそれはそれで参入障壁が高い
|
||||
|
||||
|
||||
[[mimiumでのシーケンサ]]
|
||||
|
||||
[[mimiumでのライブコーディングエンジン]]
|
||||
@@ -57,7 +70,8 @@ https://github.com/mimium-org/mimium-rs
|
||||
[mimium-rs/Roadmap.md at dev · mimium-org/mimium-rs · GitHub](https://github.com/mimium-org/mimium-rs/blob/dev/Roadmap.md)
|
||||
|
||||
- 多段階計算:大変そう。コンパイラドライバをユーザーコードから叩けるようにするのが先か。
|
||||
- [レコード型](https://github.com/mimium-org/mimium-rs/issues/99):要件定義はほぼできたし、他の機能への依存も特になし。デフォルト引数の実装を無視すればとりあえず進められそう
|
||||
- [[mimiumのレコード型|レコード型]]:要件定義はほぼできたし、他の機能への依存も特になし。デフォルト引数の実装を無視すればとりあえず進められそう
|
||||
- [[mimiumでのバリアント]]:やっぱり必要、だが分割コンパイルを先にやらないとダメかも
|
||||
- モジュールシステム:名前空間のCライブラリレベルでのマングリングとか考える必要ありそう。
|
||||
- 配列型の実装:GC問題片付けばなんとか?固定長と可変長の切り替えをどうするかを考えたい。
|
||||
- OSCの実装
|
||||
|
128
content/mimiumでのIOパラメーター.md
Normal file
128
content/mimiumでのIOパラメーター.md
Normal file
@@ -0,0 +1,128 @@
|
||||
---
|
||||
date: 2025-07-01 18:43
|
||||
---
|
||||
#mimium
|
||||
|
||||
マルチスレッド前提の場合、Shared State全般がRwLockとかで包まれることになってしまう
|
||||
|
||||
しかし、大概の場合グローバルな状態共有はAtomicな単一パラメーターで済む
|
||||
|
||||
あくまで、普通のグローバル変数宣言はスレッドローカルな扱いにして、メインスレッドと協調しないといけない場合は"shared"みたいなキーワードをつけるようにするとか(構文増やしたくないけど)
|
||||
|
||||
だし、これだと結局OSC送るサーバークライアント構成と実質的に変わらないかも
|
||||
|
||||
```rust
|
||||
let hoge = 100;
|
||||
```
|
||||
|
||||
みたいなのの代わりに、別のキーワードを持たせる
|
||||
|
||||
```rust
|
||||
global hoge = 100
|
||||
```
|
||||
|
||||
プリミティブな型であれば、Atomicな書き換えでOK。hogeへの書き込みをオーディオコンテキストの中でやると毎サンプル実行される保証がない、みたいな仕様?
|
||||
|
||||
タプルとか合成型だと、マルチスレッドで書き換えたときに片方のパラメーターが更新されてない時に読み取られる可能性が厳密にはある
|
||||
|
||||
グローバルに宣言された配列型とか、合成型をどうやって扱う?
|
||||
|
||||
単に、グローバルな値への書き込みがいつ行われるか保証はされませんよ、という仕様にするならそれでも十分か
|
||||
|
||||
もしくは、
|
||||
|
||||
```rust
|
||||
let hoge = param(100)
|
||||
```
|
||||
|
||||
みたいなラップの仕方を考える。hogeは`Param<Number>`型をもち、Number型に自動キャストできる。
|
||||
|
||||
パラメトリックフィルタ複製で、個々の周波数を外側からコントロールしたいとするとどうなるか
|
||||
|
||||
```rust
|
||||
fn replicate(n,gen){
|
||||
let g = gen(n, n*100)
|
||||
if (n>0.0){
|
||||
let c = replicate(n - 1.0,gen)
|
||||
| | g() + c()
|
||||
}else{
|
||||
| | g()
|
||||
}
|
||||
}
|
||||
fn mygen(freq){
|
||||
osc(freq)
|
||||
}
|
||||
fn gen(n,init_f){
|
||||
let channel = param("freq_%n",init_f);
|
||||
| | mygen(channel)
|
||||
}
|
||||
let myfilter = replicate(5,gen)
|
||||
fn dsp(){
|
||||
myfilter()
|
||||
}
|
||||
```
|
||||
|
||||
まあこうなるか 自動グループ化みたいなのできるか?実行してる関数の深さ的に`global::replicate::gen::(args)`で自動ネーミング自体は不可能ではなさそうだが/自動グループをやりたければ、`Param<T>`の中身をレコード型にすればいいのか
|
||||
|
||||
paramがジェネリックな関数`T->Param<T>`であることが重要になってくる。範囲の制限とかはRanged型みたいなのをmimium側で定義すればよくなる・・・はずまあIO周りは結局命令型になるのかなあ
|
||||
|
||||
|
||||
|
||||
```rust
|
||||
let channel = param("freq_%n",init_f);
|
||||
set_param("freq_%n",1000.0)
|
||||
channel = 1000;//
|
||||
```
|
||||
|
||||
最後の行のように、普通にAssign書き込むのもできるようにしておきたい。これできるようにするには、Assignをオーバーロードできるような型システムが必要なのかな`param(コンストラクタ)`と`get_param_name`、`get_param`、`set_param`の4種類があれば十分か
|
||||
|
||||
|
||||
|
||||
[[mimiumのレコード型]]のデフォルト実装、関数のデフォルト引数の組み合わせに対して自動でパラメーターが作られるようにしたい
|
||||
|
||||
```rust
|
||||
fn gen_synthesizer(){
|
||||
let s = |gate = 0,freq=1000,gain = 1.0|{
|
||||
...
|
||||
}
|
||||
s({..})
|
||||
}
|
||||
let mysynth = gen_synthesizer();
|
||||
|
||||
fn dsp(){
|
||||
mysynth()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
これを実行すると、隠れレコード構造体定義とグローバルなデフォルト引数が作られる
|
||||
|
||||
```rust
|
||||
...
|
||||
type defaultarg = {
|
||||
"gate":number = 0,
|
||||
"freq":number = 1000,
|
||||
"gain":number = 1.0
|
||||
}
|
||||
let default_arg_for_mysynth = param("mysynth",defaultarg::default());
|
||||
fn dsp(){
|
||||
mysynth()
|
||||
}
|
||||
```
|
||||
|
||||
dsp内で`mysynth({..})`と実行してしまうと、これがグローバルなコンテキストで作られない可能性がある・・のか?いや、でも基本的に書き換えられる心配はないからいいのかな
|
||||
|
||||
デフォルト引数構造体のインスタンスは必ずグローバル評価で行う、だとパラメトリックな生成はできないし問題起きそう
|
||||
|
||||
```rust
|
||||
//自動キャストとジェネリクスの組み合わせさえうまくいけばこのくらいのことはできそう
|
||||
let p = param({..});
|
||||
fn dsp(){
|
||||
p |>
|
||||
|gate = 0,freq = 1000,gain = 1.0|{
|
||||
...//do something
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
ということは、とりあえず雑にParamを実装して
|
38
content/mimiumでのバリアント.md
Normal file
38
content/mimiumでのバリアント.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
date: 2025-07-03 18:34
|
||||
---
|
||||
#memo
|
||||
|
||||
幽霊型含む、カスタムのコンストラクターを書こうとすると名前空間の問題が出てくる
|
||||
|
||||
二重インクルードの問題とかもあるので、先に分割コンパイルの仕組みを整える方がいい?
|
||||
|
||||
型の環境の中に変数解決が必要になってくる
|
||||
|
||||
内部的には幽霊、Opaque、バリアントで分かれててもいいかもな
|
||||
|
||||
```rust
|
||||
enum Variant{
|
||||
Phantom(Symbol),
|
||||
Opaque(Symbol,TypeNodeId),
|
||||
Union(Box<Self>,Box<Self>)
|
||||
}
|
||||
enum Type{
|
||||
...
|
||||
|
||||
Variant(Variant)
|
||||
}
|
||||
```
|
||||
|
||||
Foldでネストするくらいなら`Vec<Box<Self>>`に収められるかな?
|
||||
|
||||
パーサーとASTとしてはmatch節も加えないと意味ない
|
||||
|
||||
で、型推論に加えなきゃいけないコードは、
|
||||
|
||||
- 型コンストラクタを関数として使えるように型→値環境に追加し、App式の評価で使えるように
|
||||
- match式の型推論
|
||||
|
||||
matchのコード生成がジャンプテーブルとか出てくるとめんどくさいんだよなあ
|
||||
|
||||
|
@@ -19,3 +19,6 @@ ChucKではエフェクトのテールが更新時にぶちぎれる問題があ
|
||||
|
||||
各トラックごとのエフェクトのライブ切り替えとかも実現しようと思えばできるかな
|
||||
|
||||
...これ、結局[[SuperCollider]]のJITLibと同じことかもな
|
||||
|
||||
[jitlib\_basic\_concepts\_01 \| SuperCollider 3.14.0-dev Help](https://doc.sccode.org/Tutorials/JITLib/jitlib_basic_concepts_01.html)
|
||||
|
71
content/mimiumと多段階計算.md
Normal file
71
content/mimiumと多段階計算.md
Normal file
@@ -0,0 +1,71 @@
|
||||
#memo #mimium
|
||||
|
||||
|
||||
|
||||
- [[多段階計算を命令型VMインストラクションで表現したい]]
|
||||
- 一時期考えていたが、あんまり筋が良くないのでやめた
|
||||
|
||||
|
||||
[Implement multi-stage computation intepreter by tomoyanonymous · Pull Request #136 · mimium-org/mimium-rs · GitHub](https://github.com/mimium-org/mimium-rs/pull/136)
|
||||
|
||||
シンプルに構文木レベルでのインタプリタを別途作ることで実現できそう。
|
||||
|
||||
|
||||
## 課題
|
||||
|
||||
- 組み込みの関数の型情報がマクロ用(レベル0)とVM用(レベル1)で分かれているので、両方にあることを別々に宣言しなければならない
|
||||
- 逆に、ベクターのappend・removeや文字列操作など、メモリを確保する操作はレベル0でのみ利用できる組み込み関数として制限すると、便利かもしれない
|
||||
- 逆に、`self`や`delay`はレベル1でのみ利用できる関数とする
|
||||
- レベル0,1両方で利用できるpersistentなモジュールは、上記2種類のいずれも使わず、かつescapeとBracketも利用しないものであればよい、ということになる
|
||||
- もともとディレイの最大サイズはリテラルで指定しなければいけないという問題があったが、これを`make_delay(size:float)-> <(float,float)->float>`(レベル0で最大時間を指定すると、入力と遅延時間をとる関数のコードを返すという関数)にできるかも
|
||||
- ただ、これやるとディレイが絡む関数はすべてレベル0定義になるのかな
|
||||
- なんかそれよりは、[[数値プリミティブ型に常に範囲をつける]]とかのほうが筋がいいかも
|
||||
|
||||
```rust
|
||||
fn fbdelay(max_time){
|
||||
`|input,time,fb| {
|
||||
(input + self*fb, time) |> make_delay!(max_time)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- こういうfbdelayを2個以上つかうときのコードはどうなるのかな
|
||||
- というか、fbdelayで生成されたコードをMIRに持ってくときにどうなるのか?
|
||||
- Value型を単なるCodeじゃなくてDelayとして特別な値にリダクションすればいいのかな
|
||||
|
||||
[[otopoiesis]]でパラメーターを生成するのにも使える?
|
||||
|
||||
```rust
|
||||
fn synth(freq,gate){
|
||||
osc(freq)*gate
|
||||
}
|
||||
|
||||
fn synth_module(freq:()->float,gate:()->float){
|
||||
`||{ synth(freq(),gate()) }
|
||||
}
|
||||
```
|
||||
|
||||
これのモジュールを評価すると、freq,gateがUIに現れるという感じでできるのかな(そして、ここでUIの範囲制限をするためにも数値型が範囲を持っていた方がいいということになりそう)
|
||||
|
||||
うーん、サンクを手動で使わず表現できるような何かが欲しいなあ
|
||||
|
||||
```rust
|
||||
fn wrap_module(param:Param, synth:(Param)->float ){
|
||||
`{ | | synth(param |> invoke) }
|
||||
}
|
||||
```
|
||||
Param型はinvokeでuiからの値を取れる、サンクをアンラップするようなメソッドを持つ型クラスに属している、という感じで、ジェネリクスが実装出来たらいけそうね
|
||||
|
||||
|
||||
## マクロを提供するプラグイン
|
||||
|
||||
プラグインも、各関数が返す型と同時にどのレベルでその関数が使えるかをコンパイラに渡す必要がある
|
||||
|
||||
|
||||
### ファイル読み込みはどうなる?
|
||||
|
||||
[[mimiumのファイルIO]]の話。マクロの展開より先に型の評価が行われるので、例えばファイルを読み込んでからチャンネル数が分かる、みたいな場合型情報を読み込む段階でファイルを読みこまなければならない、がその評価のためにはマクロを実行して文字列の値を受け取らなければならない、、、ということで、結局[[依存型]]がないと多段階計算でも対応できない。
|
||||
|
||||
結局、読み込んで返す値として次元数の値を持つ配列を返すしかないのかも
|
||||
|
||||
|
@@ -60,116 +60,4 @@ fn repl_001(){
|
||||
|
||||
シングルスレッドの場合、REPLで実行されたものは必ずオーディオドライバのブロック頭で消化
|
||||
|
||||
マルチスレッド前提の場合、Shared State全般がRwLockとかで包まれることになってしまう
|
||||
|
||||
しかし、大概の場合グローバルな状態共有はAtomicな単一パラメーターで済む
|
||||
|
||||
あくまで、普通のグローバル変数宣言はスレッドローカルな扱いにして、メインスレッドと協調しないといけない場合は"shared"みたいなキーワードをつけるようにするとか(構文増やしたくないけど)
|
||||
|
||||
だし、これだと結局OSC送るサーバークライアント構成と実質的に変わらないかも
|
||||
|
||||
```rust
|
||||
let hoge = 100;
|
||||
```
|
||||
|
||||
みたいなのの代わりに、別のキーワードを持たせる
|
||||
|
||||
```rust
|
||||
global hoge = 100
|
||||
```
|
||||
|
||||
プリミティブな型であれば、Atomicな書き換えでOK。hogeへの書き込みをオーディオコンテキストの中でやると毎サンプル実行される保証がない、みたいな仕様?
|
||||
|
||||
タプルとか合成型だと、マルチスレッドで書き換えたときに片方のパラメーターが更新されてない時に読み取られる可能性が厳密にはある
|
||||
|
||||
グローバルに宣言された配列型とか、合成型をどうやって扱う?
|
||||
|
||||
単に、グローバルな値への書き込みがいつ行われるか保証はされませんよ、という仕様にするならそれでも十分か
|
||||
|
||||
もしくは、
|
||||
|
||||
```rust
|
||||
let hoge = param(100)
|
||||
```
|
||||
|
||||
みたいなラップの仕方を考える。hogeは`Param<Number>`型をもち、Number型に自動キャストできる。
|
||||
|
||||
パラメトリックフィルタ複製で、個々の周波数を外側からコントロールしたいとするとどうなるか
|
||||
|
||||
```rust
|
||||
fn replicate(n,gen){
|
||||
let g = gen(n, n*100)
|
||||
if (n>0.0){
|
||||
let c = replicate(n - 1.0,gen)
|
||||
| | g() + c()
|
||||
}else{
|
||||
| | g()
|
||||
}
|
||||
}
|
||||
fn mygen(freq){
|
||||
osc(freq)
|
||||
}
|
||||
fn gen(n,init_f){
|
||||
let channel = param("freq_%n",init_f);
|
||||
| | mygen(channel)
|
||||
}
|
||||
let myfilter = replicate(5,gen)
|
||||
fn dsp(){
|
||||
myfilter()
|
||||
}
|
||||
```
|
||||
|
||||
まあこうなるか 自動グループ化みたいなのできるか?実行してる関数の深さ的に`global::replicate::gen::(args)`で自動ネーミング自体は不可能ではなさそうだが/自動グループをやりたければ、`Param<T>`の中身をレコード型にすればいいのか
|
||||
|
||||
paramがジェネリックな関数`T->Param<T>`であることが重要になってくる。範囲の制限とかはRanged型みたいなのをmimium側で定義すればよくなる・・・はずまあIO周りは結局命令型になるのかなあ
|
||||
|
||||
|
||||
|
||||
```rust
|
||||
let channel = param("freq_%n",init_f);
|
||||
set_param("freq_%n",1000.0)
|
||||
channel = 1000;//
|
||||
```
|
||||
|
||||
最後の行のように、普通にAssign書き込むのもできるようにしておきたい。これできるようにするには、Assignをオーバーロードできるような型システムが必要なのかな`param(コンストラクタ)`と`get_param_name`、`get_param`、`set_param`の4種類があれば十分か
|
||||
|
||||
|
||||
|
||||
[[mimiumのレコード型]]のデフォルト実装、関数のデフォルト引数の組み合わせに対して自動でパラメーターが作られるようにしたい
|
||||
|
||||
```rust
|
||||
fn gen_synthesizer(){
|
||||
let s = |gate = 0,freq=1000,gain = 1.0|{
|
||||
...
|
||||
}
|
||||
s({..})
|
||||
}
|
||||
let mysynth = gen_synthesizer();
|
||||
|
||||
fn dsp(){
|
||||
mysynth()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
これを実行すると、隠れレコード構造体定義とグローバルなデフォルト引数が作られる
|
||||
|
||||
```rust
|
||||
...
|
||||
type defaultarg = {
|
||||
"gate":number = 0,
|
||||
"freq":number = 1000,
|
||||
"gain":number = 1.0
|
||||
}
|
||||
let default_arg_for_mysynth = param("mysynth",defaultarg::default());
|
||||
fn dsp(){
|
||||
mysynth()
|
||||
}
|
||||
```
|
||||
|
||||
dsp内で`mysynth({..})`と実行してしまうと、これがグローバルなコンテキストで作られない可能性がある・・のか?いや、でも基本的に書き換えられる心配はないからいいのかな
|
||||
|
||||
デフォルト引数構造体のインスタンスはグローバル評価で行われて、
|
||||
|
||||
|
||||
ということは、とりあえず雑にParamを実装して
|
||||
[[mimiumでのIOパラメーター]]
|
223
content/mimiumのレコード型.md
Normal file
223
content/mimiumのレコード型.md
Normal file
@@ -0,0 +1,223 @@
|
||||
---
|
||||
date: 2025-07-02 11:40
|
||||
---
|
||||
#memo
|
||||
|
||||
[Proposal: Record Syntax · Issue #99 · mimium-org/mimium-rs · GitHub](https://github.com/mimium-org/mimium-rs/issues/99)
|
||||
|
||||
古い v0.4.0 では実験的なレコード(struct)型があったが、新たなレコード型の構文を実装する。
|
||||
|
||||
新構文のデザインは、名前ごとにデータをグルーピングすることで、プログラマの意図をより直接的にコードに反映できるようにするとともに、デフォルト値を設定することで記述量を減らすことを目指す。
|
||||
|
||||
また、タプル型で考案されているパラメータパックとデフォルト値付きレコード型を組み合わせることで、「UGen as 関数」という概念を型安全性を保ちながら直接表現でき、かつデフォルト引数付き関数にありがちな引数の数に関する混乱を回避できそう。
|
||||
|
||||
## 基本構文
|
||||
|
||||
構文のベースは [Elm](https://elm-lang.org/docs/records) である。小竹は Rust 風にはしない。
|
||||
|
||||
匿名レコード型を正の文脈で使う。
|
||||
|
||||
|
||||
```rust
|
||||
let myadsr_param = { attack = 100.0, decay = 200.0, sustain:float = 0.6, // let 式同様に型注釈は省略可能だ release = 2000.0, // 末尾のカンマも許可されるべきだ } let singlerecord = { value = 100, // フィールドが1つだけのレコードは、ブロックや代入構文と区別するために末尾カンマが必須だ }
|
||||
```
|
||||
|
||||
後で実装予定だが、型エイリアス/新規型宣言の中でもデフォルト値を設定できる。宣言内のデフォルト値はリテラルである必要がある。
|
||||
|
||||
|
||||
```rust
|
||||
type alias ADSR = { attack:float = 100.0,
|
||||
decay:float = 200.0,
|
||||
sustain:float = 0.6,
|
||||
release:float = 2000.0, }
|
||||
```
|
||||
|
||||
各要素へはドット演算子でアクセスするか、let パターンで展開できる。
|
||||
|
||||
```rust
|
||||
let myattack = myadsr_param.attack let { attack .. } = myadsr_param // 変数名はレコード型宣言に依存する
|
||||
```
|
||||
|
||||
アンダースコアを使った部分適用の構文糖衣を使えば、こんなコードでもたぶん動作する。
|
||||
|
||||
|
||||
```rust
|
||||
let myattack = myadsr_param |> _.attack // 型は正しく推論される
|
||||
```
|
||||
|
||||
|
||||
Elm 由来の「update」構文も加える。ただし区切りにはパイプではなく左アローを使う。
|
||||
|
||||
|
||||
```rust
|
||||
let newadsr = { myadsr_param <- attack = 4000.0, decay = 2000.0 } // attack フィールドのみ上書きして新しいレコードを生成
|
||||
```
|
||||
|
||||
これは以下のような構文糖衣として実装できる。
|
||||
|
||||
```rust
|
||||
let newadsr = { attack = 4000.0,
|
||||
decay = myadsr_param.decay,
|
||||
sustain = myadsr_param.sustain,
|
||||
release = myadsr_param.release, }
|
||||
```
|
||||
|
||||
|
||||
この展開は型推論後にのみ行える。実装は mirgen 側で行えばいいはず。
|
||||
|
||||
## 関数宣言での引数デフォルト値
|
||||
|
||||
|
||||
```rust
|
||||
fn adsr(attack = 100, decay = 200, sustain:float = 0.7, release = 1000.0) -> float {
|
||||
// 実装…
|
||||
}
|
||||
// もちろんこれは動作する
|
||||
adsr(200,400,0.5,200)
|
||||
// 以下は許可しない。次のパラメータパックの説明参照
|
||||
adsr()
|
||||
adsr(attack = 200)
|
||||
adsr(200)
|
||||
```
|
||||
|
||||
## レコード型を使った自動パラメータパック
|
||||
|
||||
引数が 2 つを超える関数呼び出しでは、
|
||||
|
||||
1. 宣言と同じ数の引数
|
||||
2. 型の統一ルールに合致する単一のレコード引数
|
||||
|
||||
のいずれも許可される。というか、多パラメーター関数は実質的に単一レコード引数関数のエイリアスになる。
|
||||
|
||||
|
||||
```rust
|
||||
// もちろんOK
|
||||
adsr(myadsr_param)
|
||||
// デフォルト引数ですべて評価する
|
||||
adsr({ .. })
|
||||
// オールデフォルトの場合はこれも許して良さそう
|
||||
adsr(..)
|
||||
```
|
||||
|
||||
|
||||
デフォルトパラメーターに対する部分更新構文も許したい。デフォルト値付きと未設定引数を混在させた関数の場合とか。
|
||||
|
||||
|
||||
```rust
|
||||
fn myugen(freq, phase = 0.0, amp = 1.0) { // freq は必須
|
||||
//実装…
|
||||
}
|
||||
myugen({ freq = 200.0 .. }) // これは許可されるはず
|
||||
myugen({ phase = 0.05 .. }) // freq がないのでエラー
|
||||
```
|
||||
|
||||
右辺値で使う `{ key = val .. }` 構文は、`let` パターン展開と同様に `IncompleteRecord` AST ノードを生成し、その型は `IncompleteRecord` となる。この `IncompleteRecord` 式は、部分適用のアンダースコア同様、引数としてのみ使える想定。
|
||||
|
||||
型システムレベルでは、`Record` 型は各フィールドにデフォルト値があるかどうかの情報だけを持ち、値自体は持たない。
|
||||
|
||||
型推論では以下のように `Record` と `IncompleteRecord` が統一(unify)される。
|
||||
|
||||
|
||||
```rust
|
||||
// 疑似コード
|
||||
Record{ [(key:"freq", type:float, default_v:false),
|
||||
(key:"phase", type:float, default_v:true),
|
||||
(key:"amp", type:float, default_v:true)]
|
||||
}
|
||||
IncompleteRecord{ [(key:"freq", type:float)] }
|
||||
=== unify ===>
|
||||
Record{ [(key:"freq", type:float, default_v:true),
|
||||
(key:"phase", type:float, default_v:true),
|
||||
(key:"amp", type:float, default_v:true)] }
|
||||
```
|
||||
|
||||
|
||||
型推論の最後まで `IncompleteRecord` が残っているとコンパイルエラーとする?。
|
||||
|
||||
そして、単一の `IncompleteRecord` 引数が与えられた場合(ケース2)、mirgen 前の構文糖衣アンラップフェーズで、以下のように更新構文を用いた AST 展開を行う。
|
||||
|
||||
```rust
|
||||
let default_v = { freq = 0.0, phase = 0.0, amp = 1.0 }
|
||||
// "myugen" の型情報をもとに生成。freq は上書きされるので何でもよい。
|
||||
myugen({ default_v <- freq = 200.0 })
|
||||
```
|
||||
|
||||
|
||||
デフォルト値生成のロジックは、Rust の `Default` トレイトのような制限付き型クラス(インターフェース)を模したものになると思われる。
|
||||
|
||||
---
|
||||
|
||||
## 部分型と[[型クラス]]
|
||||
|
||||
[[構造的部分型]]を採用するつもり。
|
||||
|
||||
つまり、
|
||||
|
||||
```rust
|
||||
fn mysynth(freq,amp,gate){
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
みたいな関数に対して
|
||||
|
||||
```rust
|
||||
let param = {
|
||||
freq:1000,
|
||||
amp:1.0,
|
||||
gate: 1.0,
|
||||
phase: 0.0, //余計なパラメーター
|
||||
}
|
||||
param |> mysynth //でも、部分型になるのでOK
|
||||
```
|
||||
|
||||
ということができる。
|
||||
|
||||
そして、レコード型のメンバーに関数型を許せば、結局これは型クラスを作ってるのに等しいことになるはず
|
||||
|
||||
例えばデフォルト値が次の型クラスの実装となっているとすると
|
||||
|
||||
```
|
||||
type ADSR = {
|
||||
attack:float,
|
||||
decay: float,
|
||||
sustain: float,
|
||||
release: float
|
||||
}
|
||||
trait Default{
|
||||
fn default()->Self
|
||||
}
|
||||
impl Default for ADSR{
|
||||
fn default()->Self{
|
||||
{
|
||||
attack:100,
|
||||
decay: 100,
|
||||
sustain: 0.7,
|
||||
release: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```
|
||||
type alias Default<T>{
|
||||
default: ()->T
|
||||
}
|
||||
|
||||
let adsr:ADSR = {..}//これが
|
||||
let adsr = Default<ADSR>::default() //こうなる
|
||||
|
||||
```
|
||||
|
||||
隠れ引数として実装されれば、定数畳み込みはできそう
|
||||
|
||||
```
|
||||
fn default(typeid, parama,paramb)->T{
|
||||
match typeid{
|
||||
...
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
@@ -123,6 +123,26 @@ fn reverse(origin:Region)->Region{
|
||||
- 再生前(prepareToPlay)
|
||||
- 信号再生時(process)
|
||||
|
||||
## 多段階計算と組み合わせる
|
||||
|
||||
[[mimiumと多段階計算]]で、それなりに多段階計算の実装が間に合ってきた。
|
||||
|
||||
FadeinOutのようなリージョン→リージョンの関数はステージ0の計算と考えることができる。
|
||||
|
||||
また、Generator系も、基本的には周波数や音量といったUIパラメーターは、ステージ0での評価時にUIを生成して値を受け取るチャンネルを作り、ステージ1=再生中にそのUIからの値を受け取るという方式で捉えられる
|
||||
|
||||
```rust
|
||||
fn audiofx(param1=100,param2=200){
|
||||
`|input|{... }
|
||||
}
|
||||
|
||||
fn gen_component(){
|
||||
Param{..} |> sinosc
|
||||
}
|
||||
```
|
||||
`Param`はジェネリックな
|
||||
|
||||
|
||||
---
|
||||
以下は昔に考えていたこと
|
||||
|
||||
|
Submodule content/private updated: 752cb78643...d677e5ed96
8
content/お菓子くん.md
Normal file
8
content/お菓子くん.md
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
date: 2025-07-05 15:45
|
||||
---
|
||||
#research
|
||||
|
||||
会議が煮詰まってくると、机にお菓子を投げ込んでくれるデバイス
|
||||
|
||||
https://ipsj.ixsq.nii.ac.jp/records/183464
|
10
content/コンパイラを書く時の悩みについて.md
Normal file
10
content/コンパイラを書く時の悩みについて.md
Normal file
@@ -0,0 +1,10 @@
|
||||
#compiler-design
|
||||
|
||||
- ある程度コンパイラのコードベースが大きくなってくると、認知負荷がでかくなってくる
|
||||
- かといって、コードをコンパクトに保とうとすると、一箇所の変更がしづらくなっていく
|
||||
- かといって、頑張ってインターフェースを切って分離性を高めていくと、全体の把握はしづらくなる
|
||||
- そりゃ全体を把握しなくいても継続的に開発できるようにするのが目的なのでそうなんだけど
|
||||
- 例えば、シンタックスツリーに[[Red Green Syntax Tree]]をあとから使おうとすると、さすがに書き換えが大変
|
||||
- だが、Language Serverを作ろうと思ったらいつかは必要
|
||||
- これをインクリメンタルに開発するのは無理だよなあ
|
||||
-
|
41
content/コードフォーマッター.md
Normal file
41
content/コードフォーマッター.md
Normal file
@@ -0,0 +1,41 @@
|
||||
---
|
||||
date: 2025-07-22 17:00
|
||||
---
|
||||
#programming-language
|
||||
|
||||
一般的なコードフォーマッターの実装について。
|
||||
|
||||
[How to write a code formatter](https://yorickpeterse.com/articles/how-to-write-a-code-formatter/)
|
||||
|
||||
1行当たり最大文字数がこのくらい、としたときに、どういう戦略で折り返すかは結構難しい問題。
|
||||
|
||||
文字列→トークン→ASTという順番で変換されるので、この逆順が良いのかとも思ったが、
|
||||
|
||||
AST→フォーマッタ用の専用の木構造みたいな中間表現を一度挟んだほうが賢いのかもしれない
|
||||
|
||||
[[Rust]]の[pretty](https://docs.rs/pretty/latest/pretty/)クレートがコンビネーターとして定義してあるやつ
|
||||
|
||||
[[Tree-sitter]]を使った汎用フォーマッター[Topiary](https://topiary.tweag.io/)とかいうのもある
|
||||
|
||||
---
|
||||
|
||||
Exprの途中に差し込まれたトリビア(主にコメント)をどうやって抽出するか
|
||||
|
||||
ExprNodeIdに対するSecondary MapがSpanに対して作れているのだから、Trailng Triviaとしてコメントを保持するのは一応できるか?
|
||||
|
||||
パーサコンビネータでどうにか処理できるもんか?
|
||||
|
||||
```rust
|
||||
fn parse_expr_top<Output>()->impl Parser<Token,Output,Error>{
|
||||
not(comment()).padded_by(comment().repeated())
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[Parser in chumsky - Rust](https://docs.rs/chumsky/latest/chumsky/trait.Parser.html#method.map_with)
|
||||
|
||||
`map_with`使えばいけるかしら
|
||||
|
||||
Stateにトリビアを書き込んでおけばいいのか
|
||||
|
||||
|
@@ -33,4 +33,11 @@ date: 2025-06-14 19:46
|
||||
[Home \| Arduino-FOC](https://docs.simplefoc.com/)
|
||||
|
||||
|
||||
Dan bauというベトナムとか中国のモノコードがこれっぽいな
|
||||
|
||||
[DAN BAU SELF LEARNING-Tu hoc DAN BAU(DVD+Book)獨弦琴 - YouTube](https://www.youtube.com/watch?v=mqWm2_gOq18)
|
||||
|
||||
確かに、気合でフレットが移動するよりも弦のテンションを変える方が楽かもな、、、長さが固定の分倍音制御を特定のフレットの位置でやればいいから
|
||||
|
||||
|
||||
|
||||
|
14
content/パッケージマネージャー.md
Normal file
14
content/パッケージマネージャー.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
date: 2025-07-09 19:14
|
||||
---
|
||||
#programming-language
|
||||
|
||||
言語のライブラリなどをリモートリポジトリから取得、管理する仕組み。
|
||||
|
||||
バージョンの依存性解決なども機能のうちに含む。
|
||||
|
||||
|
||||
[[Suwa Takashi]]さんの記事がパッケージマネージャとは何かをよく解説してくれている
|
||||
|
||||
[パッケージマネージャを自作するときに考えること - gfnweb](https://gfngfn.github.io/ja/posts/2023-02-15-on-creating-package-managers/)
|
||||
|
15
content/型クラス.md
Normal file
15
content/型クラス.md
Normal file
@@ -0,0 +1,15 @@
|
||||
#programming-language
|
||||
|
||||
[[Rust]]におけるTraitとかに近いもの
|
||||
|
||||
あるメソッド群を持つジェネリックな型の分類
|
||||
|
||||
パラメトリックなジェネリクスに対して、対象が広すぎるものを、アドホック多相的に制限する
|
||||
|
||||
["Hackett: a metaprogrammable Haskell" by Alexis King - YouTube](https://youtu.be/5QQdI3P7MdY)
|
||||
|
||||
この動画の説明わかりやすかった(12:10~)
|
||||
|
||||
式をもとに型を生成するのが[[型推論]]、型情報をもとに式を生成するのがジェネリクスというループ
|
||||
|
||||
[[Hackett]]
|
@@ -32,9 +32,18 @@ http://www.cs.tsukuba.ac.jp/~kam/lecture/gairon2-2012/gairon2.pdf
|
||||
|
||||
λ○□:両方を統合
|
||||
|
||||
[[SATySFi]]:組版言語だが、マクロのシステムとして多段階計算が導入されている。
|
||||
|
||||
[多段階計算の型システムの基礎 - gfnweb](https://gfngfn.github.io/ja/posts/2022-05-12-slides-type-system-matsuri-2020/)([[Suwa Takashi]])
|
||||
|
||||
[SATySFi の多段階計算入門](https://sankantsu.hatenablog.com/entry/2022/08/19/215024)
|
||||
|
||||
## 用語
|
||||
|
||||
**Cross-Stage Persistence**:基本的にステージ0/1でのコードはそれぞれステージ0/1の中でしか使えない。何らかの方法で両方のステージで跨いで使える仕組みを作れると便利
|
||||
|
||||
**Run**プリミティブ:
|
||||
|
||||
## [[依存型]]との組み合わせ
|
||||
|
||||
[A Dependently Typed Multi-Stage Calculus](https://arxiv.org/abs/1908.02035)
|
||||
|
@@ -18,9 +18,9 @@ VMは最初、マクロ評価時に自分の現在の評価ステージを0と
|
||||
|
||||
VMは、命令記録モードと実行モードの2種類で、現在の評価ステージが0のときに実行モードになる
|
||||
|
||||
mainプログラムの先頭はマクロ展開のため必ずincl_levelからスタート=命令記録モードから開始
|
||||
mainプログラムの先頭はマクロ展開のため必ずincr_levelからスタート=命令記録モードから開始
|
||||
|
||||
命令記録モードでは、decl_levelがでてくるまでバッファに実行した命令をコピーし続ける
|
||||
命令記録モードでは、decr_levelがでてくるまでバッファに実行した命令をコピーし続ける
|
||||
decl_levelでレベル0になったら...うーん
|
||||
|
||||
```ocaml
|
||||
@@ -62,3 +62,7 @@ endescape
|
||||
ret 1
|
||||
```
|
||||
|
||||
|
||||
VMの構造にメタプログラミングを埋め込むよりも、MIR生成段階でなにかしらのサンクを呼び出すということにして一時的に空にしておく、みたいなやり方のほうが素直かもな
|
||||
|
||||
|
||||
|
122
content/小数から近い分数を求める.md
Normal file
122
content/小数から近い分数を求める.md
Normal file
@@ -0,0 +1,122 @@
|
||||
---
|
||||
date: 2025-07-24 17:54
|
||||
---
|
||||
#memo #mathematics
|
||||
|
||||
例えば、[[双方向プログラミング]]的なもので、数値をスライダーで調整できるようになっていた場合、実際のところは5/7とかわかりやすい有理数だったりとか、整数に近い値を表したいのにめちゃくちゃ長い小数点の数値が残ったりする。
|
||||
|
||||
これを、適当なグリッドにスナップするUIの一つとして、許容できる誤差範囲と整数の複雑さを指定して分数に変換するのが良いのではないか。
|
||||
|
||||
ChatGPTに聞いた。[[連分数展開]]というのを使うと良いらしい。[[Rust]]のコードを書いてもらった。
|
||||
|
||||
```rust
|
||||
/// 任意の実数 x を近似する収束分数・半収束分数を求める
|
||||
/// x: 近似したい実数
|
||||
/// eps: 絶対誤差許容値
|
||||
/// max_den: 分母の上限
|
||||
/// max_num: 分子の上限
|
||||
fn rational_approx(
|
||||
x: f64,
|
||||
eps: f64,
|
||||
max_den: u64,
|
||||
max_num: u64,
|
||||
) -> Vec<(u64, u64)> {
|
||||
// 連分数展開の a_k リストを構築
|
||||
let mut a: Vec<u64> = Vec::new();
|
||||
let mut r = x;
|
||||
for _ in 0..64 {
|
||||
let ak = r.floor() as u64;
|
||||
a.push(ak);
|
||||
let frac = r - (ak as f64);
|
||||
if frac.abs() < f64::EPSILON {
|
||||
break;
|
||||
}
|
||||
r = 1.0 / frac;
|
||||
}
|
||||
|
||||
let mut candidates: Vec<(u64, u64)> = Vec::with_capacity(a.len());
|
||||
let (mut p_nm2, mut q_nm2) = (0u128, 1u128);
|
||||
let (mut p_nm1, mut q_nm1) = (1u128, 0u128);
|
||||
|
||||
for &ak in &a {
|
||||
// 収束分数
|
||||
let p = ak as u128 * p_nm1 + p_nm2;
|
||||
let q = ak as u128 * q_nm1 + q_nm2;
|
||||
if q > max_den as u128 { break; }
|
||||
let num = p as u64;
|
||||
let den = q as u64;
|
||||
if num <= max_num {
|
||||
let approx = (num as f64) / (den as f64);
|
||||
if (x - approx).abs() <= eps {
|
||||
candidates.push((num, den));
|
||||
}
|
||||
}
|
||||
// 半収束分数
|
||||
for d in 1..=(ak / 2) {
|
||||
let ap = ak - d;
|
||||
let p2 = ap as u128 * p_nm1 + p_nm2;
|
||||
let q2 = ap as u128 * q_nm1 + q_nm2;
|
||||
if q2 <= max_den as u128 && p2 <= max_num as u128 {
|
||||
let num2 = p2 as u64;
|
||||
let den2 = q2 as u64;
|
||||
let approx2 = (num2 as f64) / (den2 as f64);
|
||||
if (x - approx2).abs() <= eps {
|
||||
candidates.push((num2, den2));
|
||||
}
|
||||
}
|
||||
}
|
||||
p_nm2 = p_nm1;
|
||||
q_nm2 = q_nm1;
|
||||
p_nm1 = p;
|
||||
q_nm1 = q;
|
||||
}
|
||||
|
||||
candidates.sort_by(|&(p1, q1), &(p2, q2)| {
|
||||
let e1 = (x - (p1 as f64)/(q1 as f64)).abs();
|
||||
let e2 = (x - (p2 as f64)/(q2 as f64)).abs();
|
||||
e1.partial_cmp(&e2).unwrap()
|
||||
});
|
||||
candidates.dedup();
|
||||
candidates
|
||||
}
|
||||
|
||||
/// x を percent% 精度で近似するラッパー
|
||||
/// x: 近似したい実数
|
||||
/// percent: 相対誤差許容値(%)
|
||||
/// max_num: 分母、分子の上限
|
||||
fn rational_approx_pct(
|
||||
x: f64,
|
||||
percent: f64,
|
||||
max_num: u64,
|
||||
) -> Vec<(u64, u64)> {
|
||||
let eps = (percent / 100.0) * x.abs();
|
||||
rational_approx(x, eps, max_num, max_num)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = 2.7182818284;
|
||||
let percent = 1.0; // 1%
|
||||
let max_num = 500;
|
||||
let results = rational_approx_pct(x, percent, max_num);
|
||||
println!("近似候補(percent={}%):", percent);
|
||||
for (p, q) in results {
|
||||
let approx = p as f64 / q as f64;
|
||||
let err = (x - approx).abs();
|
||||
println!("{}/{} = {:.8}, 誤差 {} ({:.4}%差)",
|
||||
p, q, approx, err, err / x.abs() * 100.0);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
```
|
||||
近似候補(percent=1%):
|
||||
193/71 = 2.71830986, 誤差 0.00002803075492963103 (0.0010%差)
|
||||
106/39 = 2.71794872, 誤差 0.00033311045128181505 (0.0123%差)
|
||||
87/32 = 2.71875000, 誤差 0.00046817160000012237 (0.0172%差)
|
||||
68/25 = 2.72000000, 誤差 0.0017181716000003178 (0.0632%差)
|
||||
49/18 = 2.72222222, 誤差 0.003940393822222443 (0.1450%差)
|
||||
19/7 = 2.71428571, 誤差 0.003996114114285465 (0.1470%差)
|
||||
```
|
||||
|
||||
悪くなさそう(ここから5個ぐらいまでを提示するとして、)
|
Reference in New Issue
Block a user