マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

l3fp の式の演算子の優先順位の仕様の変更の件

某 Forum のコレについてもう少し詳しく調べてみる。

l3fp のどこが変わったのか
  • 「連接による乗算」に高い優先順位を持たせているか否かが違う。
    • TL2013 では「連接による乗算」は「除算(/)」より高い優先順位をもつ。
      1/2mm = 1/(2mm)1/2*mm
    • TL2015 では「連接による乗算」は「通常の乗算(*)」と同じ(従って「除算」とも同じ)優先順位をもつ。
      1/2mm = (1/2)mm = 1/2*mm
(注意: l3fp では mm のような長さ単位は単なる数値の定数(mm = 2.84527)として扱われる。)
仕様は何であるか、何であったか

この動作の変更が本当に「仕様の変更」によるもの(バグではなく)なのかを確認してみよう。

TeX Live 2015 の expl3 のマニュアル((texdoc で開く場合は“expl3”ではなく“interface3”を指定する(texdoc interface3)。ただし現状では“l3fp”でも同じ文書が開かれる。))には l3fp の式の演算子優先順位は次のようになっている。(9.2 節“Precedence of operators”)

  • Function calls (sin, ln, etc).
  • Binary ** and ^ (right associative).
  • Unary +, -, !.
  • Binary *, /, and implicit multiplication by juxtaposition (2pi, 3(4+5), etc).
  • Binary + and -.
(後省略)

これを見ると「連接による乗算」が * と同順位であることが明示されていることが判る。従って、現在の動作は“正しい仕様”である。

ところが、この後を見ると、何やら様子がおかしい。

In particular, those precedences imply that
sin2pi = sin(2π) = 0,
2^2max(3, 4) = 22max(3,4) = 256.

さっき示した規則に従うと、「連接を * に変えても同じ」だから以下のようになるはずである。

  • sin2pi = sin2*pi = (sin2)*pi = 2.85664
  • 2^2max(3, 4) = 2^2*max(3, 4) = (2^2)*max(3, 4) = 16

実際に試してみると、TL2015 では「規則通りの」値になり、一方で TL2013 は「マニュアルに書いてある」値になる。

\typeout{%                     % TL2015     TL2013
  \fp_eval:n{sin2pi}^^J%       %   2.85664   -0.00000
  \fp_eval:n{2^2max(3, 4)}}    %  16        256

ということは、やはり「仕様が変わった」のだと予想される。マニュアルの「規則の記述」は更新したが、その後にある例の記述の修正を忘れているのだろう。

というわけで、実際に TeX Live 2013(最終版)の expl3 のマニュアルを調べてみた。やはり、この時点の仕様では「連接による乗算」に高い優先順位を持たせていたことが判る。

  • Implicit multiplication by juxtaposition (2pi, 3(4+5), etc).
  • Function calls (sin, ln, etc).
  • Binary ** and ^ (right associative).
  • Unary +, -, !.
  • Binary *, / and %.
  • Binary + and -.
(後省略)

ちなみに、TeX Live 2014 の最終版は TeX Live 2015(最新)と全く同じである。だから、2013 最終版と 2014 最終版の間のどこかで、この仕様変更が行われたことになる。

というわけで

l3fp の式での演算子の優先順位の規則は途中(2013 年頃)で変更されている。この事項に限らず、expl3 の仕様はまだ凍結されておらず、実際に“結構”変更が行われている。expl3 を利用したパッケージを作製している開発者はその点に留意すべきである。