Posted at

Unity の iOS64bit 対応で発生した浮動小数点数の誤差について

More than 3 years have passed since last update.


はじめに

Unity で iOS64bit 対応をした際に、浮動小数点数の演算で 32bitとは異なる誤差がでることを確認しました。

Unity の中の人とやりとりをした情報が誰かの役にたつかもしれないので、残しておきます。


そもそも浮動小数点数の演算は狂う


a) 浮動小数点数の演算に固有の誤差が常に生じる可能性がある。

b) ビルド環境やオプションによって、同一のソースコードでも計算結果が変わる可能性がある。

c) 実行する CPU が変われば、同一の実行モジュールでも計算結果が変わる可能性がある。


こちらから の引用です。

そもそも実行環境などにより浮動小数点数の演算は狂うものなのですが、Unity の iOS64Bit 対応では下記のような現象が発生していました。


起こった現象


環境



  • Unity 4.6.6f2


    • 32bit 版ビルド時の設定


      • Script Backend : Mono(2.x)



    • 64bit 版ビルド時の設定


      • Script Backend : IL2CPP

      • Architecture : Universal





  • 確認機種は iPhone 5S



ソースコード

float test_function(float min, float max, float key)

{
return min + (max - min) * key;
}

上記の関数を呼んだ際に、戻り値 float の値が異なっていました。

引数と 32bit時64bit時それぞれの戻り値の値は以下の通りになりました。

min
max
key
32bit 版戻り値
64bit 版戻り値

-20.0f
20.0f
0.4813481f
0.7460761
0.7460766

-20.0f
20.0f
0.6628235f
6.51294
6.512939


発生理由

これはどのような理由で発生したのか Unity の中の方に伺いました。


  • Mono 上での動作が、IL2CPP 上での動作より、精度をあげる方向で最適化が働いている。

  • そもそも C++/C# 浮動小数点演算の精度は型で定義される桁まで担保されており、それよりも精度が低下することはないが、それよりも高い精度へ勝手に上げてしまうことは任意に許されている。1

  • Mono の JIT/AOT で実行した場合、途中の演算が省かれる形での最適化が行われる模様。


おわりに

ということで、浮動小数点演算を使用する限りは仕方のないことのようです。

ご相談のっていただいた Unity の方々、ありがとうございました。