概要
文字として与えられた数式を解析し、計算します。
以前作った数学パズルゲームで使っていたものを、ライブラリ化した感じです。
double result = "1+2*3/(4-5)".AsSpan().Calculate(); // -5
Pythonとかだとこんな関数がありますが…
result = eval("1+2*3/(4-5)")
- C#ではこの機能がない
- そもそもこの関数自体、処理が重くて汎用的ではない
という問題点があり、自分で作ろう、と思い立ちました。
GitHub
こちら (FormulaCalculator) です。
README に詳しいドキュメントを記載しているので、良ければ日本語翻訳して読んでみてください。
この記事では、それらをいい感じに要約して説明していきます!
🔰 セットアップ方法(初心者向け)
- Unity 上でパッケージマネージャーを開きます。
- Git URL からインポートします。(以下のURLをコピペしてインポートする)
https://github.com/foriver4725/FormulaCalculator.git?path=Assets/foriver4725/FormulaCalculator
- スクリプト上部で、以下を追記します。
using foriver4725.FormulaCalculator;
- エラーが出なければ成功!!
使い方
基本形はこうです。(再掲)
拡張メソッドとして使うことができ、計算に失敗したら double.NaN
が返ってきます。
double result = "1+2*3/(4-5)".AsSpan().Calculate();
計算処理の最初では、「数式が正しい形式であるか」チェックされます。
これは大事な工程ですが、数式が正しい形式であることを保証できているなら、パフォーマンス的には良くありません。
この場合、 doSkipValidation
フラグを true
に変更することで、上記のチェックがスキップされます。安全性とのトレードオフになるので、自分の使い方に合っている方を選択してください。
double result = "1+2*3/(4-5)".AsSpan().Calculate(doSkipValidation: true);
いい感じに使い分けよう
double result = "1+2*3/(4-5)".AsSpan().Calculate();
double result = "1+2*3/(4-5)".AsSpan().Calculate(doSkipValidation: true);
パフォーマンス
パフォーマンスは大事です!
100万回実行したプロファイリング結果がこちらです。
doSkipValidation フラグ |
GC Alloc | Time ms | Self ms |
---|---|---|---|
false (デフォルト) |
0 B | 674.12 | 674.12 |
true (より高速) |
0 B | 465.79 | 465.79 |
ケースによりますが、 doSkipValidation
フラグの有無で、実行時間が 30% 変わります。
また、内部計算では全て Span
を用いており、 GC.Alloc は一切ありません。
必要に応じて、計算結果をキャッシュするなどの工夫もしてみてください!(このライブラリからは削ぎ落としました)
計算の流れ
括弧の中を再帰計算します。
意外とこれだけで、詳しくは README を読んでもらえればと思います。
まとめ
初心者の頃、作っているゲームでこのような機能を使いたかったのですが、当時は実力不足で断念しました。
ネットの解説も難しいし…。
このライブラリが、そんな方々を助ける一助になれば嬉しいです。