投稿者「mod_poppo」のアーカイブ

浮動小数点数の関数とオーバーフロー

大抵のプログラミング言語には指数関数 exp や三角関数 sin, cos, tan などの初等関数が用意されている。これらの関数はよく使うので、標準に用意されているというのは合理的だろう。しかし、初等関数の組み合わせで書けるような関数がわざわざ専用の関数として用意されている場合がある。 続きを読む

LaTeX の数式をターミナルで手軽に MathML に変換する

テキストエディタで HTML 文書を直書きしていて、 MathML で数式を書きたいけど MathML 直書きは嫌だ!という時。Pandoc を使えば、ターミナルで手軽に LaTeX 形式の数式を MathML に変換できる。

例:

$ pandoc -f latex -t html5 --mathml
\(\frac{1}{e^z-1}\)
^D
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mfrac><mn>1</mn><mrow><msup><mi>e</mi><mi>z</mi></msup><mo>−</mo><mn>1</mn></mrow></mfrac><annotation encoding="application/x-tex">\frac{1}{e^z-1}</annotation></semantics></math></p>

太字の部分が自分で入力する部分である。(^D は Control-D の意)

Haskell で高速なプログラムを書くときに注意すること

Haskell は表現力が高いプログラミング言語だが、気をつけないと非効率的なコードが生成されてしまうことがある。では、どういうところに気をつければ高速なコードになるのか。少し調べてみた。

この記事に書くのは、あくまで原則とかそういうやつなので、コンパイラーの最適化(正格性解析、インライン化、自動ボックス化解除)によっては、自前で工夫しても意味がない、つまり、コンパイラーに任せた場合と同じ結果になるかもしれない。どういう場合に早くなるかはケースバイケースなのだ。 続きを読む

Haskell の Num クラスに対する不満

Haskell には Num という型クラスがあって、足し算とか掛け算の基本的な演算はここで定義されている。標準ライブラリで定義されているインスタンスとしては、 Int, Integer, Rational, Complex a などがある。

一言で言えば Num クラスは環っぽいものに対応するのだが、いろいろとアレな点がある。これを設計した人は、インスタンスとして整数、有理数、浮動小数点数、複素数くらいしか想定していないのではないか。 続きを読む

Picked up JAVA_TOOL_OPTIONS: を擬似的に消す

昔話

その昔、Mac OS X で java コマンドを起動するとターミナルが UTF-8 であってもメッセージがシフトJISで出力されて文字化けしてしまうという時代があった。

java コマンドの起動時に -Dfile.encoding=UTF-8 をつければ出力が UTF-8 になるが、毎回指定するのは面倒くさい。

そんな時、人々は JAVA_TOOL_OPTIONS という環境変数を -Dfile.encoding=UTF-8 に設定したものだ。

そうすれば、確かにメッセージは UTF-8 で出力される。されるのだが…。

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8

という余計なメッセージまで出力される。うるさい。

…というのは過去の話で、最近の Java を Mac 環境で使う分には JAVA_TOOL_OPTIONS を指定しなくても出力が UTF-8 になるので、特に問題はない。(確か、環境変数 LANG を読むはず)

2016年の話

残念なことだが、2016年にもなって、コマンドライン環境で UTF-8 以外のマルチバイトエンコーディング(シフトJISとか)が広く使われている環境が存在する。そういう環境に UTF-8 なターミナル(MinTTY とか)を用意してやっても、デフォルトでは java はシフトJISでメッセージを吐いてくる。したがって、そういう環境で java コマンドのメッセージの出力を UTF-8 にしたい場合は、 JAVA_TOOL_OPTIONS-Dfile.encoding=UTF-8 を指定する必要がある。

まあ、 UTF-8 以外のマルチバイトエンコーディングが広く使われている環境が存在するのは仕方がない。受け入れるしかない。しかし、Picked up JAVA_TOOL_OPTIONS: が出てくるのはなんとかしたい。

このメッセージの出力を抑制できないならば、せめて「見えないように」する方法があるのではないか。つまり、 Picked up JAVA_TOOL_OPTIONS: が印字された後に、空白文字で上書きする…!

つまり、こうだ:

JAVA_TOOL_OPTIONS=$'\r-Dfile.encoding=UTF-8\r                            \r'

$'ほにゃらら' というのは、 bash にエスケープ文字を解釈させる文法だ。この記事に関心を持つような人ならば何をやっているか分かるだろう。

キャリッジリターンとか言ってないで ANSI escape を駆使すれば空行すらなくせるかもしれないが、残念ながらそういうのはキャリッジリターン \r と違い、オプション解釈の際に空白として読み飛ばされない。

真面目な話

ドヤ顔でキャリッジリターンとか書いてみたものの、実際に使ってみると表示が崩れる場合が散見されるので、常用するのはやめたほうがよさそうである。

総合的に考えると、次のようなシェル関数を書いて対応するのがベストかと思われる。(シェルで単独で java を叩いた場合は Picked up … が表示されず、間接的に起動された場合は Picked up … が表示される。)あるいは、シェルスクリプトでラップしてやるという手も考えられる。

export JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF-8
function java() {
    env JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS/-Dfile.encoding=UTF-8/}" java -Df
ile.encoding=UTF-8 "$@"
}
function javac() {
    env JAVA_TOOL_OPTIONS="${JAVA_TOOL_OPTIONS/-Dfile.encoding=UTF-8/}" "${JDK_P
ATH}/javac" -J-Dfile.encoding=UTF-8 "$@"
}

何をやっているかというと、 java という名前のシェル関数で、「環境変数 JAVA_TOOL_OPTIONS から “-Dfile.encoding=UTF-8” という文字列を削除」「java コマンドに -Dfile.encoding=UTF-8 オプションを渡す」ということをやっている。bash 以外のシェルでは違う書き方が必要になるだろう。

余談

余談だが、ドットネット系のプログラムは、コマンドプロンプトで chcp 65001 をすると出力が UTF-8 になるようだ。UTF-8 なターミナルから MSBuild とか csc とかを叩くときに覚えておくと良いだろう。(Windows の Java も GetConsoleOutputCP で出力文字コードを判断してくれれば良かったのだが…)

\mathfrak と打つのがだるい

数学の一部の分野では、フラクトゥールが多用される。数式中でフラクトゥールな文字をLaTeXで書く際は \mathfrak{a} とか書くわけだが、たくさん出てくると入力するのがだるい。

短い名前をつける

幸い、LaTeXにはマクロ機能があるので、 \mathfrak のコマンド名が長いと思ったら、短い名前を与えてやれば良い。

\newcommand\mf{\mathfrak}
\mf{a} % → \mathfrak{a} になる
\mf a % → 上に同じ。コマンドの引数が1文字の場合は { } を省略できる

個々の文字にコマンドを割り当てるという手もある。

\newcommand\a{\mathfrak{a}}
\a % → \mathfrak{a} になる…はず

が、しかし、 \a という名前のコマンドは LaTeX によってすでに定義されているようで、 \newcommand でエラーが出る。\renewcommand を使えば定義を上書きできるが、副作用が怖い。

別の名前を試してみよう。

\newcommand\aa{\mathfrak{aa}}
\aa % → \mathfrak{a} になる…はず

が、しかし、\aa という名前のコマンドも LaTeX によってすでに定義されているのであった。

このように、「短い名前をつける」という戦略は「名前の衝突」によって阻まれる可能性がある。\renewcommand や、TeX primitive の \def によって上書きすることはできるが、既存のコマンドの不具合(副作用)を引き起こす可能性は否定できない。

ただ、上書きするスコープを限定してやれば、副作用を引き起こす可能性は小さくできるかもしれない。

{ % スコープを作る
\renewcommand\aa{\mathfrak{a}}
$\aa$ % → \mathfrak{a} になる
} % スコープを閉じる

\aa % → 元の意味(å)になる

\begin{center} % \begin{} 〜 \end{} は一つのスコープになる
\renewcommand\aa{\mathfrak{a}}
$\aa$ % → \mathfrak{a} になる
\end{center}

\aa % → 元の意味(å)になる

毎回 \renewcommand\aa{\mathfrak{a}} と打つのが面倒だったら、これもマクロにすると良いだろう。

\newcommand\UseMathFrak{%
  \renewcommand\aa{\mathfrak{a}}%
}

{ % スコープを作る
\UseMathFrak
$\aa$ % → \mathfrak{a} になる
} % スコープを閉じる

\aa % → 元の意味(å)になる

\begin{center} % \begin{} 〜 \end{} は一つのスコープになる
\UseMathFrak
$\aa$ % → \mathfrak{a} になる
\end{center}

\aa % → 元の意味(å)になる

短い名前をつける(亜種)

普通のコマンド名はバックスラッシュ \ から始まるが、コマンド名として使えるものはこれだけではない。TeX 標準では、半角チルダ ~ を単独で(バックスラッシュなしに)コマンド名として使うことができる。

知っての通り、半角チルダ ~ は標準では「改行しない空白」という意味を持つが、そこは\renewcommand で上書きしてやる。

\renewcommand~{\mathfrak}
~a % → \mathfrak a と等価

既存のコマンドを上書きすると副作用が怖い、とか、元のコマンドが使えなくなる、という場合は、スコープの中で \renewcommand することによって影響範囲を小さくできる。

Unicode の文字を使う

Unicode には、様々な字体の「数式用アルファベット」が用意されている。その中には、フラクトゥールもある。これらを LaTeX ソース中に直接記述すれば、\mathfrak といちいち書かなくても良くなるのではないか。

スクリーンショット 0028-05-26 19.24.28

unicode-math パッケージを使うと、 Unicode の数式用アルファベットで書いたものを LaTeX\mathfrak 等で書いたものと等価にしてくれる。

ただし、 unicode-math パッケージを使うには LuaTeXXeTeX が必要である(e-upTeX や pdfTeXでは使えない)。

注意点として、 unicode-math を使うと Unicode の数式用アルファベットのカテゴリーコードが変わるようだ。unicode-math を使わなければカテゴリーコード11 (letter) だが、unicode-math を使うとカテゴリーコード12 (other) になる。どう影響するかというと、 例えば

𝔞\to𝔟     % ← \to の後に空白がない

と書いた時に、 unicode-math を使わないと「文字 “𝔞”」「コマンド名 “\to𝔟”」として解釈されるのが、 unicode-math を使うと「文字 “𝔞”」「コマンド名 “\to”」「文字 “𝔟”」として解釈されるようになる。普通は前者の挙動の方が望まれるとは思うが。

unicode-math を使わない(使えない)場合、 Unicode の数式用アルファベットのカテゴリーコードを13 (active) にしてマクロを定義するという手がある。

\catcode`𝔞=\active % “𝔞” という文字を単独でコマンド名として使えるようにする
\newcommand{𝔞}{\mathfrak{a}}
𝔞 % → \mathfrak{a} に展開される

いずれにせよ、TeX エンジンの側で Unicode に対応している必要がある。

Unicode の数式用アルファベットを使う方法ならば、「短い名前をつける」方法にあった「コマンド名がかぶる」という問題は存在しない。ただし、デメリットとして、 Unicode の数式用アルファベットを入力するのは面倒くさいということが挙げられる。

結論

エディター側で入力支援的なものが欲しい。

Windows で JDK のインストール先を取得

Windows に JDK を入れた時のインスートル先のディレクトリというのは、バージョンによって変わる。これを機械的に取得したい。

環境変数の類は設定されない(公式のマニュアルに、手動で設定する方法が書かれてるくらいだし)ようだが、レジストリを見ればパスを取得できる。

Stack Overflow の質問には reg コマンドを使った回答が付いているが、Windows の場合こういうのはバッチファイルで書くよりも WSH を使った方が文字列処理等がすっきりするだろう。

というわけで書いてみた。

var WshShell = WScript.CreateObject("WScript.Shell");
var JDKKey = "HKLM\\SOFTWARE\\JavaSoft\\Java Development Kit\\";
var CurrentVersion = WshShell.RegRead(JDKKey + "CurrentVersion");
var JavaHome = WshShell.RegRead(JDKKey + CurrentVersion + "\\JavaHome");
var JDKBin = JavaHome + "\\bin";
WScript.Echo(JDKBin);

このファイルを例えば showjdkpath.js という名前で保存して、 CScript /nologo showjdkpath.js と実行すれば、標準出力に javac の場所が出てくる。

Haxe の正規表現のターゲット環境による違い

Haxe で正規表現を使う際には、次のような問題点がある。

  • ターゲット環境によって正規表現の細かい文法が違う。
  • ターゲット環境によっては、Unicode の code point 単位ではなく、 UTF-16 の code unit 単位で正規表現のマッチングを行うものがある。JavaScript とか JavaScript とか ECMAScript 5 とか
    • この場合、 [\uD800-\uDBFF][\uDC00-\uDFFF] というようなパターンを書くなどして、サロゲートペアを自前で処理しないといけない。

また、Haxe に限らなくても、文字列で正規表現のパターンを記述するのには、次のような問題点がある。

  • 複雑な正規表現を文字列の形で直接ソースコードに書くのは、コードの読みやすさ的によろしくない。
  • 正規表現の文字列を動的に構築する場合も考えると、いろいろカオスになりそう。

そこで、正規表現のパターン文字列を構築する Haxe のライブラリを作ることを考える。ライブラリ側で環境の違いも吸収することにすれば良い。 続きを読む