毎晩のようにMATLABを弄り回して遊んでいます。
サクサク動きますし、ヘルプも(それなりに)充実していますし、GUIも細かいところに工夫がありますし、使っていて楽しいです。サクサク動くのはRyzenにアップグレードしたせいかもしれません(笑)。
さて、Simulinkで躓いたのでMATLABに立ち戻って調べた結果、演算における型の扱いが私がなじんでいる言語と違うことがわかりました。自分向けのメモとしてここに記しておきます。
MATLABの演算では整数から浮動小数点への自動型変換がおきない
わかりやすいところから行きましょう。例えば以下の式の結果は納得がいきます。
1/32767 ans = 3.0519e-05
なるほど。”/” 演算子は両辺が整数型であっても浮動小数点演算を行うのですね。
ところで以下の式の値は 32767です。
intmax('int16') ans = 32767
以上を踏まえたうえで、以下の結果に混乱してしまうわけです。
1/intmax('int16') ans = 0
いやぁ、嘘でしょって感じです。
だって整数除算の結果は実数でしたよ。ということでかなり頭を悩ませたのですが、結局これは二つの事実に落ち着きます。
まず、MATLABでは整数表現されるリテラルも実数型です。これはヘルプに書いてありました。
class(65536) ans = 'double'
ですから最初の除算は実数同士の除算だったわけです。一方で、intmax() 関数の戻り値は、引数に与えた型名の型を持ちます。つまり
class(intmax("int16")) ans = 'int16'
とこうなるわけです。整数型で割っているわけです。それはそれで実数 / 整数は実数型になりそうですが
class(1/intmax("int16")) ans = 'int16'
であり、なんと整数型になります。ついでにほかの演算も調べてみましょう。
class(intmax("int16")/1) ans = 'int16'
class(intmax("int16")+1) ans = 'int16'
class(intmax("int16")*1) ans = 'int16'
つまり、MATLABの二項演算子は整数と実数の演算の場合、実数側のオペランドを整数に変換してから演算します。びっくりです。これもよく調べたらヘルプに書いてありました。
ということで、整数型を含む除算を正確に行うには、以下のようにします。
1/double(intmax("int16")) ans = 3.0519e-05
まとめ
まとめるとMATLABでは
- 整数リテラルに見えても数はdouble型。
- intmax()関数の返り値は、引数の型名の型を持つ。
- 整数と実数の2項演算では、実数は整数に変換されてから演算する。
まとめてはみましたが、狐に包まれたような気分です。