はじめに
電卓のようなものを作りたいとき、数式をプログラムに認識させる必要があります。数式をコードとして書く場合、いちいち、止めて、再実行する必要があり面倒です。しかし、実行中に、数式を認識させるには、数字や演算記号やカッコを認識させる必要があり、これも面倒。
で、evalという便利な関数を見つけましたが、javascriptやpythonでは実装されているものの、java,Processingにはありません。ですが、いいライブラリがあったので、メモします。
環境
Mac OSX 11.6
Processing 3.5.4
ライブラリ(Processingの管理ツールからインストール)
ControlP5 2.2.6
Jasmine 1.1
jasmine開発者サイト
http://www.lagers.org.uk/jasmine/index.html
実装例
テキストボックスに数式を書いてエンターで、その式の結果を表示します。基本的な算術関数も全て網羅されているので、困ることはないでしょう。変数表記も使えます。
驚いたことに、このControlP5のテキストボックスは履歴が遡れます。カーソルキーの上を押すと履歴が出るので、Unixのコマンドラインのような使い方ができて、自前実装する手間が省けました。
import controlP5.*;
import org.quark.jasmine.*;
ControlP5 cp5;
PFont font;
void setup() {
background(0);
size(400, 300);
font = createFont("Arial", 24);
cp5 = new ControlP5(this);
cp5.addTextfield("input")
.setFont(font)
.setSize(200, 24);
textFont(font);
}
void draw() {
}
void keyPressed() {
if (key == ENTER) {
background(0);
String s = cp5.get(Textfield.class, "input").getText();
text(s, 20, 100);
//eval
Expression e = Compile.expression(s, false);
float f = e.eval().answer().toFloat();
text(f, 20, 150);
}
}
変数ありの方程式
x,yの2変数がある式の場合、eval(2,3)のように値を受け渡す。
import org.quark.jasmine.*;
String s = "x^2+y^2";
Expression e = Compile.expression(s, false);
float f = e.eval(2, 3).answer().toFloat();
print(f); //13.0
おまけ
このライブラリで「1/3*3」を計算したところ、0.999ではなく、1と出ました。優秀です。
愚かな自分へのメモ
また、同じ調べ物をしてしまった。
2021年10月28日にこれを投稿したのを忘れて、再度、evalについて調べ直していた。そして、自分の記事にたどり着いた。2023年9月19日
追加で得た情報をメモする
javaからjavascriptを呼び出す方法がある。
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("js");
try {
double ans = (Double)engine.eval("1.1*1.1");
print(ans);
}
catch (ScriptException e) {
e.printStackTrace();
}
ただし、processing4では動かず、processing3では動く。
processing3はjava8
processing4はjava17
であることが原因。
jsの部分をNashorn,Graal.js,v8,ChakraCoreに変えてみてもp4では全部ダメ。
コードの互換性として、不安が残る。
また、sqrtとかpowとか^は使えない。
「jasmineライブラリはsqrtとかpowとか^とか使える」
素晴らしい。
同じ作者が作る別のライブラリ「QScript」を見つけた。
こちらは、VBのようなスクリプトを書いておき、processingプログラム実行中に、スクリプトを編集できるようなシロモノ。
その他、python modeでevalを使い、コマンドラインで引数を渡そうと思ったけど、コンパイルできそうにないので、却下。
jasminで複素数は扱えない
log(-1)はNan(非数)になる。
print(log(-1)); //NaN
jasminでlog(-1)を計算すると、やはりNaNになる。
import org.quark.jasmine.*;
String s = "log(-1)";
Expression e = Compile.expression(s, false);
println(e.eval().answer().toFloat()); //NaN
複素数を使いたいときは、complexnumberライブラリを使う
import complexnumbers.*;
Complex z = new Complex(-1,0);
z=z.ln();
println(z); //3.141592653589793i
double r = z.re; //0.0
double i = z.im; //3.141592653589793
println(r,i);
import java.io.*;
// write
try{
OutputStream os = createOutput("out.dat");
DataOutputStream dos = new DataOutputStream(os);
dos.writeDouble(r);
dos.writeDouble(i);
dos.flush();
dos.close();
}catch(IOException e){
e.printStackTrace();
}
// load
try{
InputStream is = createInput("out.dat");
DataInputStream dis = new DataInputStream(is);
double r2 = dis.readDouble();
double i2 = dis.readDouble();
dis.close();
println(r2,i2);
}catch(IOException e){
e.printStackTrace();
}