- PR -

Java2D の API に float と double の両方がある理由は?

1
投稿者投稿内容
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-10-25 09:39
unibon です。こんにちわ。

#「小さな円を描画するといびつになる(Java2D の Ellipse2D や Component の createImage の使用時)」
#http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=6992&forum=12
#に間接的に関係するのですが。

Java2D の API には、引数に float 型を持つメソッドと、
double 型を持つメソッドの両方がありますが、
これはなぜなのでしょうか。
double だけあれば良いと思うのですが、float もある理由はなぜでしょうか。
処理速度のためなのでしょうか。
それとも状態を維持するためのメモリ量の削減のためでしょうか。

たとえば Ellipse2D クラスは、
Ellipse2D.Float と Ellipse2D.Double の両方が備わっています。
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/awt/geom/Ellipse2D.html

2つあるだけなら、使う分には、
どちらか片方を選んで使うだけで良いのですが(でもどっちを使えば良いのかは迷うのですが)、
たとえば PathIterator インターフェースは、currentSegment メソッドが、
引数が float のものと double のものが両方あるので、
これの実装クラスを作るときは、同じようなことを2回書かなければならず面倒です。
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/awt/geom/PathIterator.html
たとえば、EllipseIterator クラスも currentSegment メソッドを2回書いています。
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-10-27 14:15
こんにちは、さくらばです。

引用:

unibonさんの書き込み (2003-10-25 09:39) より:

Java2D の API には、引数に float 型を持つメソッドと、
double 型を持つメソッドの両方がありますが、
これはなぜなのでしょうか。
double だけあれば良いと思うのですが、float もある理由はなぜでしょうか。
処理速度のためなのでしょうか。
それとも状態を維持するためのメモリ量の削減のためでしょうか。




グラフィックの品質とパフォーマンスとのトレードオフなのではないでしょうか。
通常はそれほど品質は要求されないので float で高速、品質が要求される場合は
パフォーマンスは犠牲にして double にするということなのだと思います。

# ちまたでは GPU のシェーダを 32 bit にするか (GeForce)、24 bit にするか (RADEON)
# でパフォーマンスの違いが出ていますけど、それと同じようなことなのだと思います。

どこらへんで使い分ければいいかはよく分かりません。私はほとんど float を
使っています。
かずくん
ぬし
会議室デビュー日: 2003/01/08
投稿数: 759
お住まい・勤務地: 太陽系第三惑星
投稿日時: 2003-10-27 17:26
CPUで浮動小数展演算用のレジスタはdouble精度を持つため、float精度の数値を渡すとまずdoubleにキャストし、演算後、再びfloatにキャストするため、逆に処理効率が悪いというのを、聞いた事があります。
# 多分出所は、Cプログラミング診断室。

このため私は、floatは使用せず、常にdoubleを使用しています。別にサイズを気にするほど貧弱な環境を使用しているわけではないですし。
# 今のCPUは違うのかな?

GPUだと逆にfloatレジスタが用意されているのでしょうか?それ故、floatの方が効率が良いのでしょうか?
# 実際の所、Javaコンパイラや、JVMがよきに計らっているので、気にする必要はないのかな?

よっぽど使用できるリソースが限られているような環境(組込み系とか?)でないかぎりfloatいらないように思えるのですが、これは言い過ぎですか?
# J2MEにfloat/doubleって、あったっけ?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-10-28 11:33
unibon です。こんにちわ。

引用:

かずくんさんの書き込み (2003-10-27 17:26) より:
CPUで浮動小数展演算用のレジスタはdouble精度を持つため、float精度の数値を渡すとまずdoubleにキャストし、演算後、再びfloatにキャストするため、逆に処理効率が悪いというのを、聞いた事があります。


私も、大枠はそう思っていました。native な環境ならばたぶんそうなのだと思います。
しかし、ちなみに、大概の Java 実行環境では、
float のほうが double よりは数割ほど速いことが多かったと記憶しています。
Java で、double のほうが float より速いことは、
まず、なかったような(あいまいですが)。
#反例があればどなたかご指摘ください。

引用:

かずくんさんの書き込み (2003-10-27 17:26) より:
GPUだと逆にfloatレジスタが用意されているのでしょうか?それ故、floatの方が効率が良いのでしょうか?
# 実際の所、Javaコンパイラや、JVMがよきに計らっているので、気にする必要はないのかな?


GPU は良く知らないのですが、たとえばつぎのような疑問を持っています。
もし GPU が float のほうが効率が良いとしても、
Java の側で double で持っていて、それを GPU に渡す(転送する)際に
double から float に切り詰めるだけで良いのではないでしょうか。
Java の側ですでに float で持つ必要性が分かりません。
しかし、最初の質問のように、
Java2D には float と double の両方のインターフェースがある、なぜ?
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-10-28 11:40
unibon です。追加します。

引用:

unibonさんの書き込み (2003-10-28 11:33) より:
もし GPU が float のほうが効率が良いとしても、
Java の側で double で持っていて、それを GPU に渡す(転送する)際に
double から float に切り詰めるだけで良いのではないでしょうか。
Java の側ですでに float で持つ必要性が分かりません。


GPU に対して、処理を double ではなく float でおこなうことを明示的に指示するためには、
double と float を区別できる API が必要だとは思います。
でも、そのような指示は、Shape の具象クラス(Ellipse2D.Double/Ellipse2D.Float)や
配列データ(double[]/float[])などの引数の型で指定しなくても、
レンダリングヒントのようなものでも指定できるような気がします。
たとえば、
http://java.sun.com/j2se/1.4/ja/docs/ja/api/java/awt/Graphics2D.html#getRenderingHint(java.awt.RenderingHints.Key)
に類似のやりかたで。
ほむら
ぬし
会議室デビュー日: 2003/02/28
投稿数: 583
お住まい・勤務地: 東京都
投稿日時: 2003-10-28 12:18
ほむらです。
シロート考えに思ったことがあるのですが。。。
------------
以前Javaでは型のbit配列は決まっていると聞いたことがあります。。。
とすれば、変数とアドレス空間は結びつかないのでさくらば氏の言うように
精度の関係のためだけにあるのではないでしょうか?

# あとGPUってあくまでCPU経由で命令を出すだけじゃないんですか?
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-10-28 14:44
JVM のコード眺めていたら、パフォーマンスは全然関係なくて単に精度の問題だけ
のような気がしてきました。Shape の intersects とか contains やアフィン変換
とかなどの精度です。

というのも、ネイティブコードの部分では Shape から得られた座標は float で表
されているからです。Windows の場合は Win32Renderer.cpp の doShape
メソッドの中で使われています。

こんなコードです。

コード:
    jbyte *types = (jbyte *) env->GetPrimitiveArrayCritical(typesarray,
							    NULL);
    jfloat *coords = (jfloat *) env->GetPrimitiveArrayCritical(coordsarray,
							       NULL);
        ... 略 ...

	switch (types[i]) {
             ... 略 ...

	case java_awt_geom_PathIterator_SEG_LINETO:
	    if (index + 2 <= maxcoords) {
		x1 = transX + (int) coords[index++];
		y1 = transY + (int) coords[index++];
		::LineTo(hdc, x1, y1);
	    } else {
		ok = FALSE;
	    }
	    break;

             ... 続く ...



LineTo は Windows の GDI のメソッドです。

# coords をキャストで int にしないで、四捨五入してくれれば
# 円がいびつにならないのに...
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2003-10-28 18:05
unibon です。こんにちわ。

引用:

さくらばさんの書き込み (2003-10-28 14:44) より:
# coords をキャストで int にしないで、四捨五入してくれれば
# 円がいびつにならないのに...


ありがとうございます。
見てみたら、確証は持てないのですが、そのメソッド内の他の箇所で、
int にしてしまってから中間点を求めているような感じもして、
float/double の問題以前のような感じが...


#あとで引用を間違えたので修正。

[ メッセージ編集済み 編集者: unibon 編集日時 2003-10-28 18:07 ]
1

スキルアップ/キャリアアップ(JOB@IT)