単精度浮動小数点

ソサ(マジックユーザ)の謎の加算値

昨日の日記に書いたことについてもう一度整理してみる。

  • Lv 4 ~ Lv 17までは、謎の加算値は、 0.4*(Lv+30) という式で表せると、かなり高い確信を持って言える。
  • クニペックスさんのデータを分析すると40ソサでは28、76ソサでは42.4と推測できるけれど、これもやはり0.4*(Lv+30)という式とマッチしている。
  • ところが Lv 18では、0.4*(18+30)=19.2 とならずに、これよりわずかに大きい値であるという結論になってしまった。

今日はこの理由について考えてみる。

結論

すごく話が長く、込み入ってしまったので、結論を先に。

  • これは、多分バグ(の一種)
  • ロードスで扱われる数値は、有効数字は7桁程度しかないと思った方が良い。

昨日の測定

昨日の日記で、Lv 18 での謎の加算値が19.2より大きいという結論に至ったのは、こんな測定からだった。

知力: 11
基礎倍率: 0.7*(1+0.06*11)=1.162
基礎攻撃力: 31
武器習熟: +2
武器攻撃力: 66
攻撃力増: 15% + 19.8%
スキル攻撃力上昇: 3

という状態で、イグニッション(Lv6) (スキル倍率 4.25) の攻撃力を測定する。

もし謎の加算値が 19.2 ならば、イグニッションの攻撃力を表す式は

4.25*1.162*((31+2+66+19.2)*(1+0.15+0.198)+2*3) = 816.4999836

となり、これを四捨五入して 816 となるはず。ところが、実際に調べてみると 817 だった。
それなので、昨日は「謎の加算値は19.2より大きくなければならない」と結論付けた。

考え方を変える

けれど、今日は「本来は816のはずが、バグで817になってしまった」と考えてみる。
そうすると、いろいろなことがつじつまが合ってくる。

単精度浮動小数

コンピュータで小数を表す方法はいくつかあり、その中の一つに「単精度浮動小数点」と呼ばれるものがある。これはieee 754で規格が定められており、この方法で816.4999836
という値を表そうとすると、実は丸められて816.5になってしまう。
そのカラクリはこんな感じ: wikipedia
単精度浮動小数点数 - Wikipedia
ここの説明通り2進展開を考えてみると

816.4999836 = 1.1001100000111111111111110.... * 2^9

となる。ここで後ろに1が14個続くのがポイント。ieeeの規格によって、この2進展開の青い部分までしか保持できず、はみ出た部分を「0捨1入」する。すると

= 1.1001100001 * 2^9

という値になる。これが実は、816.5という値

そして、ロードスのスキル攻撃力のルールにより、この値を四捨五入したもの、すなわち817が最終的な攻撃力になる。

つまり、計算の途中でieee 754による丸め処理があったと仮定すると、イグニッションの攻撃力が817となった理由が説明できたことになる。

丸め処理を2回行う

結局これは、丸め処理を2回行ったことで生じた弊害と言える。丸め処理を2回行うとおかしなことになるのは例えば

12.45

という値があったとして、小数点以下第二位で四捨五入して

12.5

としてから、さらにこれを四捨五入すると

13

となってしまうという例でも分かる。本来12.45を正しく四捨五入すると12になるはずが値が1ずれてしまう。

まとめ

まとめるとこんな感じ

「謎の加算値が19.2なら、イグニッションの攻撃力は816となるはずなのに、実際には817になっていた」

という前提があり

  • 昨日は「謎の加算値は19.2より大きくなければいけない」という結論に至った
  • 今日は「ロードスの開発者が単精度浮動小数点を使って、丸め処理を2回行うというミスを犯したと仮定すると、謎の加算値が19.2であったとしてもつじつまが合う」という結論に至った

バグかバグではないのか

「丸め処理を2回行う」というのは、厳密な結果が求められるプログラムでは決してやってはいけないこと。けれど、ロードスはゲームなので、その辺はさほど気にせずにプログラムされたのかもしれない。

なので「初めに設計された通りに動いていない」という意味ではバグの一種だけれど
「厳密に初めの設計通りでなくてもゲーム性を損なわなければOK」という考え方をすればバグではないとも言える。

また、仮にバグと呼ぶにしても、他に数多ある致命的なバグに比べれば、大部分の人にとってどうでもいい類とも言える。

しかし、ごく一部、このゲームの内部を知ろうとする調査兵団にとっては、このバグは意識せざるを得ない存在であり、今回の事は重要な教訓となった。それは、どんな教訓で、その教訓から何が分かるのか、という話はまた後日。