2011-01-20 7 views
23

すべての数値型に共通のVectorクラスを作成しようとしています。 私のオリジナルの試みは、このようなすべてのタイプのクラスを作成することでした:Scalaは私がこれを使用することができ、特殊な注釈がすべての数値型すべての数値型に対して汎用クラスを作成するにはどうすればよいですか?

class Vector3[A <: What?](val x:A,val y:A, val z:A) 

が、すべてのために私にこれらのクラスを生成するためにサポートしているため

class Vector3f(val x:Float, val y:Float, val z:Float) 

私は数字のスーパータイプとしてAnyValが見つかりましたが、AnyValは+ - * /をサポートしていません。だから、これを行う正しい方法は何ですか、ボックス化されていない数値型のパフォーマンスを犠牲にすることはありませんか?

+0

この質問をご覧になることをお勧めします。http://stackoverflow.com/questions/4436936/scala-compiler-not-recognizing-a-view-bound/4437336#4437336 – Madoc

答えて

15

あなたがすることはできません。今じゃない。場合によっては、Numericが専門になる場合があります。

は、あなたができるだけ簡単なパラメータ化クラスを取得すると言う:

class Vector3[@specialized T](val x: T, val y: T, val z: T)(implicit num: Numeric[T]) { 
    def +(other: Vector3[T]) = new Vector3(num.plus(x, other.x), num.plus(y, other.y), num.plus(z, other.z)) 
} 

方法+は大体このようなものにコンパイルされます:scalac -optimize -Xprint:jvm出力です

override <specialized> def +$mcD$sp(other: Vector3): Vector3 = new Vector3$mcD$sp(
    scala.Double.unbox(
    Vector3$mcD$sp.this.Vector3$$num.plus(
     scala.Double.box(Vector3$mcD$sp.this.x()), 
     scala.Double.box(other.x$mcD$sp()))), 
    scala.Double.unbox(
    Vector3$mcD$sp.this.Vector3$$num.plus(
     scala.Double.box(Vector3$mcD$sp.this.y()), 
     scala.Double.box(other.y$mcD$sp()))), 
    scala.Double.unbox(
    Vector3$mcD$sp.this.Vector3$$num.plus(
     scala.Double.box(Vector3$mcD$sp.this.z()), 
     scala.Double.box(other.z$mcD$sp()))), 
    Vector3$mcD$sp.this.Vector3$$num); 

。今では、ボックス化なしでVector3を初期化できるように、それぞれの特殊なタイプのサブクラスもありますが、Numericが特殊でない限り、さらに進むことはできません。

まあ...あなた自身でNumericと書くことができますが、それを特化していますが、その時点では、クラスを最初にパラメータ化することで何を得ているのか分かりません。

6

おそらく、ここで説明するように型クラスのパターンを使用する:あなたは間接的に数値形質を使用することによりすることにより使用することができ、http://dcsobral.blogspot.com/2010/06/implicit-tricks-type-class-pattern.html

するか、http://www.scala-lang.org/api/current/scala/math/Numeric.html

+1

この回答にリンクしているブログ記事は、この同じ質問に対するより包括的ではあるが低い得点の回答を提供した人が書いたものです。 :) –

+0

はい私はまた、ブログリンクの 'dcsobral'に気づいており、上記のダニエルの答えをすでに見ていました。 – javadba

8

短い答えは:あなたは完全な性能を得ることができません。少なくとも、私は完全なパフォーマンスを出すものは見つけられていない。 (そして、私はまさにこのユースケースでしばらく試してみました。私はあきらめ、代わりにコードジェネレータを書いて、あなたは一般的にどちらかの異なるベクトルの大きさを扱うことができない、特に以来。)

は、私はに喜んだろうそうでなければ示されていますが、私が試したすべてのものは、実行時に膨大な(900%)小さなもの(30%)を持っています。


編集:ここに私の意図を示すテストがあります。

object Specs { 
    def ptime[T](f: => T): T = { 
    val t0 = System.nanoTime 
    val ans = f 
    printf("Elapsed: %.3f s\n",(System.nanoTime-t0)*1e-9) 
    ans 
    } 
    def lots[T](n: Int, f: => T): T = if (n>1) { f; lots(n-1,f) } else f 

    sealed abstract class SpecNum[@specialized(Int,Double) T] { 
    def plus(a: T, b: T): T 
    } 

    implicit object SpecInt extends SpecNum[Int] { 
    def plus(a: Int, b: Int) = a + b 
    } 

    final class Vek[@specialized(Int,Double) T](val x: T, val y: T) { 
    def +(v: Vek[T])(implicit ev: SpecNum[T]) = new Vek[T](ev.plus(x,v.x), ev.plus(y,v.y)) 
    } 

    final class Uek[@specialized(Int,Double) T](var x: T, var y: T) { 
    def +=(u: Uek[T])(implicit ev: SpecNum[T]) = { x = ev.plus(x,u.x); y = ev.plus(y,u.y); this } 
    } 

    final class Veq(val x: Int, val y: Int) { 
    def +(v: Veq) = new Veq(x + v.x, y + v.y) 
    } 

    final class Ueq(var x: Int, var y: Int) { 
    def +=(u: Ueq) = { x += u.x; y += u.y; this } 
    } 

    def main(args: Array[String]) { 
    for (i <- 1 to 6) { 
     ptime(lots(1000000,{val v = new Vek[Int](3,5); var u = new Vek[Int](0,0); var i=0; while (i<100) { u = (u+v); i += 1 }; u})) 
     ptime(lots(1000000,{val v = new Veq(3,5); var u = new Veq(0,0); var i=0; while (i<100) { u = (u+v); i += 1 }; u})) 
     ptime(lots(1000000,{val v = new Uek[Int](3,5); val u = new Uek[Int](0,0); var i=0; while (i<100) { u += v; i += 1 }; u})) 
     ptime(lots(1000000,{val v = new Ueq(3,5); val u = new Ueq(0,0); var i=0; while (i<100) { u += v; i += 1 }; u})) 
    } 
    } 
} 

と出力:

Elapsed: 0.939 s 
Elapsed: 0.535 s 
Elapsed: 0.077 s 
Elapsed: 0.075 s 
Elapsed: 0.947 s 
Elapsed: 0.352 s 
Elapsed: 0.064 s 
Elapsed: 0.063 s 
Elapsed: 0.804 s 
Elapsed: 0.360 s 
Elapsed: 0.064 s 
Elapsed: 0.062 s 
Elapsed: 0.521 s <- Immutable specialized with custom numeric 
Elapsed: 0.364 s <- Immutable primitive type 
Elapsed: 0.065 s <- Mutable specialized with custom numeric 
Elapsed: 0.065 s <- Mutable primitive type 
... 
+0

独自の特殊なNumericクラスを作成しようとしましたか? –

+0

2.8.1にはありません。それ以前の2.8(遅い2.8。0 RC、IIRC)私はもはや覚えていないいくつかの問題がありました。私はもう一度やり直すべきだと思う。 –

+0

もう一度やり直してください。 Sun JVMでの変更操作は大丈夫ですが、新しいオブジェクトを作成する必要がある場合は、〜2倍のペナルティがあります。 (JRockit JVMは同じ傾向を示していますが、すべてのタイミングは通常2〜3倍悪化しますが、場合によっては変更可能な特殊ケースが動作する場合があります)。 –

関連する問題