現在, 携帯電話のアプリ開発に使われている Java 2 Micro Edition (J2ME)の CLDC1.0 には, float や double などの(浮動)小数型が含まれていません. クラス Float や Double も含まれていません. (一部のキャリアの独自拡張にはこれらを含むものがあります. 下記参照) したがって, 当然 sin, cos, tan, asin, atan, exp, log, pow なども使えません. 不便ですね…やりたいことによっては.
ここでは, 固定小数点小数を使用できるようにする MathFP クラスライブラリの使い方を紹介します これを使ったアプリの例はこちらで紹介しています. そのうちのひとつのサンプルプログラムのソースを公開しています. ほぼ共通のソースからiアプリ/Vアプリ/EZアプリ用のソースを生成していますので, (MathFPとは限らない)アプリの別キャリアへの移植をしようとしている人にも役立つかもしれません.
(2004/11/18 Thu 追記) 2004.11 にリリースされた NTT DoCoMo 901i シリーズ の DoJa4.0 は J2ME CLDC1.1 に基づいています. CLDC1.1 では, double, float, およびこれを扱うための Math クラスがサポートされています. したがって, 901i専用のアプリを作る場合には, このページの扱っている問題は存在しなくなりました. よかった…
(2007-05-29 Tue 追記) Vladimir Roubtsov さんにより, 携帯で使用可能なradix 10000な浮動小数点ライブラリー dfpが公開されています. hiroto inoue 様から情報をいただきました. ありがとうございます.
(2007-05-29 Tue 追記) 3キャリアポータブルな固定小数点ライブラリMFPの開発について 報告されています.
携帯電話やPDA の Java である J2ME (DoJa=DoCoMoのiアプリ, MIDP=auのEZアプリ(Java),VodafoneのVアプリ,MIDP on Palm) では, 小数計算が "できません." というのも, これらの携帯 Java の採用しているバージョンの Java 2 Micro Edition(J2ME) では, 標準で double, float 型がサポートされていないからです(int はあります).
もちろん, int だけを使って 独自に固定小数点実数を実装する (三角関数とかはテーブルを持つか, テイラー展開を利用. 例参照) ことにより, 小数計算を行なうことはできます. しかし, 正直面倒くさいです.
キャリアもこの問題(特に, 3次元グラフィックスを用いる際には深刻になります)を認識しており, 独自に固定小数点実数を実装するのを助ける独自拡張を提供しています. たとえば, au の KDDI Profile Phase3 の com.jblend.graphics.util.Calc, com.jblend.graphics.m3d.Point3D, Vodafone の com.j_phone.amuse.j3d.Util3D, com.j_phone.amuse.j3d.Vector3D, NTT DoCoMo の DoJa2.0 の com.nttdocomo.opt.ui.j3d.Math, com.nttdocomo.opt.ui.j3d.Vector3D などです. ただし, 端末に依存する場合があります.
さらに進んで, 固定小数点クラスが提供されている場合もあります. Vodafone の Vアプリ P4,P5型の com.j_phone.util.FixedPoint, NTT DoCoMo の DoJa 2.0 以降で導入された com.nttdocomo.opt.ui.j3d2.C3DMath などです.
しかし, これらの独自拡張を利用して作成したプログラムにはキャリア間の portability がありません. また, 古い端末では走らなくなってしまいます. 最新の端末で CPU パワーを絞り出すようなアプリ以外では, これらの独自拡張を利用することには躊躇します.
なお, 次のバージョン J2ME CLDC1.1 では, double, float, およびこれを扱うための Math クラスがサポートされており, この問題は解消することが期待されます. (2004/11/18 Thu 追記. 2004.11 にリリースされた NTT DoCoMo 901i シリーズ DoJa4.0 で J2ME CLDC1.1 がサポートされました)
J2MEで小数計算をするにはOnno Hommesさんの作られたクラスライブラリ MathFP を使うと便利です.
ちなみに, 浮動小数点でなく固定小数点というのは, 指数部( 1.234 ×10n の ×10n の 部分)を使わない表現方法ということです. Hommes さんは, 携帯だし計算速度が十分じゃないから, Float クラスを作ったりせずに, 固定小数点整数を利用して実装したのだと思うのですが, 誰か浮動小数点実数を作ってくれるともっとハッピーかも > 自分)
小数計算は, (ゲームの, または物理用の)物理シミュレーションには必須です. 樋口は, 物理の授業用デモを作る過程で, 実数(小数)を扱う必要に迫られました. 樋口が MathFP をもちいて作成した物理の授業用デモがありますので, ご参考までにごらんください.
MathFP は, ソース(.java)でなくクラスファイル(.class)の形で配布されています. キャリアなどの配布している標準的なグラフィカルな開発環境
なお, 文末に挙げたページ, ファイル, 書籍がたいへん勉強になりました. 著者のみなさまありがとうございます.
以下で説明しているのは, MathFP のインストールと, 開発の手順です. MathFP クラスのメソッドの説明, プログラムの書き方の説明はしていません. それについては, MathFP 付属の javadoc (英語) を参照してください. また, Web 上に 日本語の文書もあるようです. 例えば Soukou さんのページ. MathFP についての記述がある, 日本語で書かれた書籍として, Java による Palm プログラミング入門 があります.
下で説明する方法の意味は, compie -> prevery -> packaging(jar化) -> 必要なら JAM, ADF などの作成, KJX 化, CRC 付加 という通常の手順を理解しているとよりよく理解できるかもしれません. が, 手順だけは理解できるように書いたつもりです.
mathfp-2.0.6/bin/ (Palm の MIDP用 および WABA 用デモプログラム) mathfp-2.0.6/docs/* ドキュメント(Javadoc) mathfp-2.0.6/classes/net/jscience/math/MathFP.class (MIDP用64ビット *2) mathfp-2.0.6/classes/net/jscience/math/waba/MathFP.class (WABA用32ビット) mathfp-2.0.6/classes/net/jscience/math/kvm/MathFP.class (KVM用32ビット *1) mathfp-2.0.6/classes/calcMathFP.class (J2SE 用デモプログラム) mathfp-2.0.6/classes/j2seMathFP.class (J2SE 用デモプログラム) mathfp-2.0.6/classes/midpMathFP$midpCanvas.class (デモプログラム用のクラス) mathfp-2.0.6/classes/midpMathFP.class (MIDP 用デモプログラム) mathfp-2.0.6/classes/wabaMathFP.class (WABA 用デモプログラム) mathfp-2.0.6/README
ドキュメントを除けば, 携帯 Java の開発に必要なのは *1 (とその上の階層構造)だけです. なぜなら, 現在の携帯 Java はすべて J2ME CLDC を用いており, 使用する Java VM は KVM に限られる CLDC でない J2ME において, long 型を用いて64ビット固定小数点計算を行なうためのクラスが *2 です.
なお, WABA とは, Wabasoft社の, Palm, PocketPC 用のプログラミングプラットフォームです.
樋口はやったことはないのですが, 原理的には, クラスライブラリとして配布されていても, JADなどの逆コンパイラを使って 逆コンパイルしてしまえば, 自分で書いたソースと同様に扱えます. すると, i-appli development tool などで開発できます. Eclipse + DoJa-3.5 eclipse plugin の組みあわせでも開発できます.
SkyArts の開発ツール MIDP Builder, DoJa Builder では, MathFP のような 外部ライブラリ を指定できます. \apps\(プロジェクト名)\libclasses\net\jscience\math\kvm\MathFP.class という位置に MathFP.class を置くだけです(プロジェクトの数だけコピーしなくちゃいけないけど). Preverify, jar へのパッケージングも自動でやってくれます. classpath に上の path を追加する必要はありません.
J2ME Wireless SDK for DoJa をインストールします (以下は, これに含まれる build.bat, run.bat を参考にさせていただいています). J2SE をインストールします. これらの開発環境の path を示す環境変数が
set JAVA_HOME=C:\jdk1.3.1_06 set KVEM_HOME=C:\J2MEWSDK4DOJAと設定されているとします.
次にプロジェクトのディレクトリとして, 次のようなディレクトリ構造を考えます.
カレント-+ src Class1.java Class2.java などのソースが置かれる. + tmpclasses preverify 前のクラスファイルが置かれる一時ディレクトリ + tmpclasses - net - jscience - math - kvm - MathFP.class + classes preverify 後のクラスファイルが置かれる + bin 最終的な jar が置かれる.MathFP を, ディレクトリ階層構造を保ってインストールします. classes\net\jscience\math\kvm\MathFP.class だけを tmpclasses\net\jscience\math\kvm\MathFP.class としてインストールします(preverify しておく必要はありません). この段階では, tmpclasses, classes, bin は (MathFP.class は除いて)空にしてあるとします.
ソースを作ります. import 文は
import net.jscience.math.kvm.MathFP;となります.
次にコンパイルします. 得られた class ファイルは tmpclasses に置かれます(-d).
%JAVA_HOME%\bin\javac -g:none -encoding SJIS_i -J-Xbootclasspath/a:%KVEM_HOME%\lib\dojaconv.jar -bootclasspath %KVEM_HOME%\lib\dojaapi.jar -sourcepath src -classpath src;tmpclasses -d tmpclasses src/Class1.java ... Class2.java などに対しても繰り返す.classpath に tmpclasses を含めているため, ここに置いてある MathFP.class が 参照されます.
次にディレクトリ tmpclasses の中の class ファイルを事前検証(preverify)して, classes ディレクトリに出力します(実機でなく, i-JADE Light で実行するだけならこのステップは不要です)
%KVEM_HOME%\bin\preverify.exe -classpath tmpclasses;%KVEM_HOME%\lib\dojaapi.jar -d classes tmpclasses
Jar ファイルにパッケージします.
%JAVA_HOME%\bin\jar cMf bin\vector.jar -C classes .
jam ファイルを記述します. 特に vector.jar のサイズを, jam ファイルに反映させます.
start notepad ..\bin\vector.jam何度も手で直すのが面倒だったら, jam.template のようなものをプロジェクト(Vector)ごとに作っておいて, ディレクトリ bin 内で
copy jam.template vector.jam echo PackageURL= Vector.jar >> vector.jam date +"LastModified= %a, %d %b %Y %T" >> vector.jam echo AppSize= `wc --bytes Vector.jar | cut -c 1,2,3,4,5,6,7` >> vector.jamのようにすれば自動化できます. ただし, date, wc, cut などは標準ではついてないので, cygwin などからもってくる必要があります.
エミュレータで実行してみます.
%JAVA_HOME%\bin\java -classpath %KVEM_HOME%\lib\dojatest.zip;%KVEM_HOME%\lib\kenv.zip -Dkvem.home=%KVEM_HOME% com.nttdocomo.dojaemu.tests.Tester jam phone1color
なお, 上の手順では, (内容の変化しない) MathFP.class を何度も preverify し直していることになります. 大した CPU 時間ではありませんが, これを避けるには, あらかじめ preverify した MathFP.class をディレクトリ class に置いておくということが考えられます. Preverify するには, MathFP のアーカイブを展開したディレクトリ classes をカレントとして,
%KVEM_HOME%\bin\preverify -classpath %KVEM_HOME%\lib\dojaapi.jar -d preverified .のようにします. また, この場合, コンパイル時には, classpath で MathFP を指しておく必要があります. たとえば, net 以下を階層構造を保って zip ファイルにしたものを mathfp.zip などとして %KVEM_HOME%\lib においたとすると, classpath に
%KVEM_HOME%\lib\mathfp.zipを追加します.
以上は Windows 上での手順です. Linux 上でもとりあえず, なお, Zentek technology の i-JADE Light のクラスライブラリを使うと, コンパイルとエミュレータでの実行はできます (preverify ができないので, 携帯用の jar は作れませんが). そのための Makefile を書いてみました. あるディレクトリに, ソースVector.java と, MathFP のディレクトリ net (preverifyしてなくてよい)を置いてるとして, そこで make します. Makefile jam.template
Unix(Linux)で開発したい人にとっては, 増井俊之さんのezplusのUnix風開発環境構築がたいへん勉強になります. ezplus という表題ですが, J2ME に共通する内容もあります.
J2ME Wireless Toolkit をインストールします (以下は, これに含まれる make.bat を参考にさせていただいています). ezPlus Tools もインストールします. J2SE もインストールします. これらの開発環境の path を示す環境変数が
set JAVA_HOME=C:\jdk1.3.1_06 set KVEM_HOME=C:\WTK104 set EZ_HOME=C:\ezplusToolsと設定されているとします.
次にプロジェクトのディレクトリとして, 次のようなディレクトリ構造を考えます.
カレント-+ src Class1.java Class2.java などのソースが置かれる. + tmpclasses preverify 前のクラスファイルが置かれる一時ディレクトリ + tmpclasses - net - jscience - math - kvm - MathFP.class + classes preverify 後のクラスファイルが置かれる + bin 最終的な jar が置かれる.MathFP を, ディレクトリ階層構造を保ってインストールします. classes\net\jscience\math\kvm\MathFP.class だけを tmpclasses\net\jscience\math\kvm\MathFP.class としてインストールします(preverify しておく必要はありません). この段階では, tmpclasses, classes, bin は (MathFP.class は除いて)空にしてあるとします.
ソースを作ります. 上に記した DoJa の場合と同様です.
コンパイルします. 得られた class ファイルは tmpclasses に置かれます(-d).
%JAVA_HOME%\bin\javac -encoding SJIS -g:none -bootclasspath %KVEM_HOME%\lib\midpapi.zip -classpath tmpclasses -sourcepath src -d tmpclasses src/Class1.java ... Class2.java などに対しても繰り返す.classpath に tmpclasses を含めているため, ここに置いてある MathFP.class が 参照されます. もし, J-Phone や AU の拡張クラスを使うなら, この段階で, classpath にセミコロンで区切って追加します.
次にディレクトリ tmpclasses の中の class ファイルを事前検証(preverify)して, classes ディレクトリに出力します.
%KVEM_HOME%\bin\preverify.exe -classpath %KVEM_HOME%\lib\midpapi.zip -d classes tmpclasses
Jar ファイルにパッケージします.
%JAVA_HOME%\bin\jar cmf bin\Vector.jar bin\MANIFEST.MF -C classes .ここで, MANIFEST.MF はプロジェクトに応じて
MIDlet-1: Vector, Vector.png , Vector MIDlet-Name: Vector MIDlet-Vendor: Saburo HIGUCHI MIDlet-Version: 1.0 MicroEdition-Configuration: CLDC-1.0 MicroEdition-Profile: MIDP-1.0のような感じで bin 内に用意しておきます.
jad ファイルを記述します. 特に Vector.jar のサイズを, jad ファイルに反映させます.
start notepad ..\bin\vector.jad何度も手で直すのが面倒だったら, bin をカレントにして
copy MANIFEST.MF Vector.jad echo MIDlet-Jar-URL: Vector.jar >> Vector.jad echo -n MIDlet-Jar-Size: >> Vector.jad wc --bytes Vector.jar | cut -c "1,2,3,4,5,6,7" >> Vector.jadを実行し, MANIFEST.MF から自動的に生成してもいいでしょう. ただし, echo, date, wc, cut などは cygwin などからもってくる必要があります.
なお, J-Phone の場合, jad と jar だけがあればいいので, これで完成です. エミュレータによる実行に飛びましょう. Palm の場合, この後 prc ファイルに変換する必要があります. この辺のことは, 書籍 MIDP Java ゲームプログラミング に大変詳しく書いてあります.
EZアプリの場合, まだ続きがあります. まず, KJX ファイルにパッケージします.
%JAVA_HOME%\bin\java -jar %EZ_HOME%\Tools\CmdTool\KJXArchiver.jar -c bin\Vector.jad bin\Vector.jar bin\Vector.kjx
エミュレータで実行してみます.
EZアプリの場合で, download cgi を用いて実機にダウンロードする場合には, あらかじめ kjx に CRC を付加しておく必要があります.
%JAVA_HOME%\bin\java -classpath .;%EZ_HOME%\Tools\CRC CRC bin\Vector.kjx
Unix(Linux)で開発したい人にとっては, 増井俊之さんのezplusのUnix風開発環境構築がたいへん勉強になります. ezplus という表題ですが, J2ME に共通する内容もあります.