スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

--.--.-- | スポンサー広告

[Lua] Luaの数値型の精度の問題

こないだSquirrelの記事で予告したので、忘れないうちに書くことにします。
Luaの公式メーリングリストでもかなり何度も話題になっている()ところですが、
Luaの数値型の精度について、特にDirectX等と一緒に使う場合には注意しなければなりません。

ゲームなどの用途では、色(RGBA)を表すのに32bitの整数で表現することがよくありますが、このような値をLua変数に代入し、演算した場合に化けてしまう場合があります。(ちなみに、Lua5.1からは0xFFのような形式で数値を書けるようになりました)

Luaでは変数に数値を入れることができますが、数値を扱うための「数値型」という型がひとつあるのみで、整数型や浮動小数点型というものはありません。整数だろうが浮動小数点だろうが、おかまいなくこの「数値型」の値として同じ(C言語における)型の変数で扱われます。この数値型の実装には、デフォルトではC言語でのdouble型が使われます。

では、デフォルト状態で、Luaの変数は32bitの整数を完全に表現できるでしょうか?

これは通常はOKです。double型は、整数を扱う場合には53ビット分の精度がありますので、32bitのint型の役割を十分に果たします。整数と整数の四則演算(値が小数になるような割り算を除いて)では、誤差が発生することもありません。このため通常は特に問題はないところです。

しかし、これがうまく機能しなくなる場合というのがあります。


・DirectXなど一部のライブラリと一緒にLuaを使う場合

DirectXでは、FPU(浮動小数点演算ユニット)の演算精度を落とすことで速度を上げる、という小技が使われています。このため、Luaを使用するプログラムでDirectXをリンクして使用している場合、数値の演算精度がfloatなみに落ちてしまいます。こうなると、整数の演算では24ビットより大きい値については不正確な結果になってしまいます。

この場合の解決策としては、DirectXの場合、CreateDeviceの呼び出し時に D3DCREATE_FPU_PRESERVE をセットすることでこれらの問題を回避することができます。ただし1~数%程度の速度の低下を招く場合があります。現状では、このフラグを使ったほうが得策かもしれません。

DirectXだけでなく、このようにFPUの精度を落とすライブラリが他にもあるかもしれないので注意が必要です。

また、単にLua変数に値を代入、または取り出すだけであれば、DirectX等によりFPUの演算精度が下がっている場合でも、問題なさそうに見えますよね。ですが、Luaから整数値を取り出すために lua_tointeger() を使う場合など、double→intの変換の高速化を図っているために、ここで値が化けてしまいますので注意が必要です。(Windowsのみ)

代入に関しては、lua_tointeger()を使わずlua_tonumber()を使用するか、lua_number2intの実装を修正すれば問題なくなります。(この件に関しては近々修正が入りそうな感じです。)


・double型が使えない・または使わない場合

環境の都合でdouble型を使わないほうが良い場合というものがあります。たとえばPS2などではfloat型を使った場合との速度差がかなりあるらしいです。この場合、float型で整数を扱う場合の精度は24ビット(-1677215~1677215)ですので、32bitのint型は入りません。大きい値を代入すると値が変化してしまいます。24bitより大きい整数に関しては精度が落ちることを覚悟して使うしかありません。

・ライトユーザーデータによる回避方法

数値型の精度が足りないならば、なにか他の型で代用できないでしょうか?

Luaには、C側での値をLuaに持ち込むための型として、メモリブロックに相当するユーザーデータ(userdata)型と、ポインタに相当するライトユーザーデータ(lightuserdata)型があります。後者のlightuserdata型にはCのポインタ、つまり通常32bitの整数値を入れることができます。
ならば、整数値の変数の代用品として使うことができそうですよね。しかしながら、そのままではLuaからこの値を数値として参照できませんので、関数を経由して値を取得するなど、多少のトリックが必要です。
とりあえず代入と取得のところだけ以下に書いてみます。


// ライトユーザーデータに数値をセット。
// 値は数値または文字列またはライトユーザーデータで指定
int create_lightuserdata(lua_State *L)
{
int value = 0;
switch ( lua_type(L, 1) ) {
case LUA_TNUMBER:
value = lua_tonumber(L,1);
break;
case LUA_TSTRING:
sscanf(lua_tostring(L,1), "%lx", &value );
break;
case LUA_TLIGHTUSERDATA:
value = (int)lua_topointer(L,1);
break;
default:
break;
}
lua_pushlightuserdata(L, (void *)value);
return 1;
}

// 引数はlightuserdata1個のみ
int print_lightuserdata(lua_State *L)
{
int value = (int)lua_topointer(L,1);
printf("print_lightuserdata value:%8x\n", value);
return 0;
}


// 登録部分
lua_register(L, "print_lightuserdata", print_lightuserdata );
lua_register(L, "create_lightuserdata", create_lightuserdata );

上記の関数を登録すれば、以下のような感じでluaで32bitの整数値を指定することができます。

udata = create_lightuserdata("7fffffff")
print_lightuserdata(udata)

テスト用ということでsscanfとか使ってかなり横着してるので、マトモに使う場合は工夫してくださいね^^;



整数パッチによる回避方法

Luaの数値型としてfloat等を設定している場合でも、値が整数の場合には自動的にintが使われるようにするパッチがあります。

http://lua-users.org/wiki/LuaPowerPatches
Integer optimization (non-FPU) patch, revised to Lua 5.1 (rc4)

Luaスクリプトの互換性を保ちつつ精度を補完できるということで、すばらしいアイデアだとは思うのですが・・・・・・そもそもサーバーが行方不明でパッチを取得できませんでした・・・。作者氏に問い合わせたほうがいいでしょうかね?また、手に入ったとしてもLua本体と違って十分テストされているとはいえないので注意が必要でしょう。


以上、Squirrelが整数型と浮動小数点型を持っているということで、いいなぁと思ったのはこういうわけです。
スポンサーサイト

テーマ:プログラミング - ジャンル:コンピュータ

2006.03.24 | Comments(1) | Trackback(2) | Lua

コメント

微修正

精度のビット数を微修正しました。

2006-03-24 金 07:07:00 | URL | はむ! #sqCyeZqA [ 編集]

コメントの投稿


秘密にする

トラックバック

http://hammm.blog21.fc2.com/tb.php/52-7114071b
この記事にトラックバックする(FC2ブログユーザー)

FPUについて

FPUFPU(Floating-Point-number-processing-Unit、浮動小数点演算装置)とは、浮動小数点演算を専門に行う処理装置のこと。単独では動作せず、主装置であるCPUから利用されるため、コプロセッサ(co-processor, 副処理装置)と呼ばれる。また、AMDではAm

2007.03.21 | CGの基礎知識

-

管理人の承認後に表示されます

2011.07.21 |

新しい記事へ <<  | HOME |  >> 古い記事へ

広告:

カテゴリ展開メニュー

  • 未分類(13)
  • Lua(38)
  • プログラミング(11)
  • 食べ物(3)
  • SPAM(2)
  • ゲーム開発(4)
  • GIS/GPS/GoogleMaps(2)
  • スポーツ(1)
  • Skype API(1)
  • AR(1)

はてブ ランキング

ブログ全体: このWikiのはてなブックマーク数

プロフィール

はむ!

Author:はむ!
よく使う言語・環境:
C++,C,Lua,java,VBA,DB
たまにPHPとかjavascript
血液型:O型

メール: lua%ham.nifty.jp
(%を@に変えてください)
ついったー: @hammmm

Lua関連アンテナ

ブロとも申請フォーム

この人とブロともになる

全記事表示リンク

全ての記事を表示する

ブログ内検索


上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。