2017-04-11 8 views
3

FloatDoubleで使用できるメソッドを書くのに問題があります。問題は、私のジェネリック型パラメータAに私のメソッド内にDoubleを掛ける必要があるということです。それは次のようなものです:DoubleとFloatの両方で動作するScalaでメソッドを書くことができません

def multiplyWithPi[A](in: A)(implicit num: Numeric[A]) : A = { 
    Math.PI * in // does not compile 
    num.times(Math.PI, in) // does not compile 
    num.times(Math.PI.asInstanceOf[A],in) // does not work (class-cast exception) 
    } 

どうすればいいですか?戻り値の型は入力型と同じであることが重要です

+0

あなたが ''メソッドfromDouble(D:ダブル):でNumeric'を所有して実装します。A'、尖塔を使用し、あなたのbuild.sbtに以下を追加するには

Rumoku

答えて

3

fromIntメソッドを提供しますが、これはおそらくfromDoubleである必要があります。ここでは次のようにどのように見えるかです:

trait MyNumeric[T] { 
    def times(a: T, b: T): T 
    def fromDouble(d: Double): T 
} 

object MyNumeric { 
    implicit val MyNumericInstance4Double = new MyNumeric[Double] { 
    def times(a: Double, b: Double): Double = a * b 
    def fromDouble(d: Double): Double = b 
    } 
    implicit val MyNumericInstance4Float = new MyNumeric[Float] { 
    def times(a: Float, b: Float): Float = a * b 
    def fromDouble(d: Double): Float = b.toFloat 
    } 
} 

def multiplyWithPi[A](in: A)(implicit num: MyNumeric[A]) : A = 
    num.times(num.fromDouble(Math.PI), in) 

あなたはそのタイプのクラスがあなたのニーズに行き過ぎていると感じた場合、あなたはまた、危険なルートを行くことができます:

def multiplyWithPi[A](in: A)(implicit num: Numeric[A]): A = 
    (in match { 
    case i: Float => (i * Math.PI).toFloat 
    case i: Double => (i * Math.PI).toDouble 
    }).asInstanceOf[A] 

あるいは:

def multiplyWithPi(in: Double): Double = in * Math.PI 
def multiplyWithPi(in: Float): Float = (in * Math.PI).toFloat 
3

Math.PIは常にDoubleであり、決してFloatではないため、これは機能しません。その後、あなたは次の操作を行うことができます

trait Pi[A] { def apply():A } 
object Pi { 
    implicit val double:Pi[Double] = new Pi[Double] { def apply() = Math.PI } 
    implicit val float:Pi[Float] = new Pi[Float] { def apply() = Math.PI.toFloat }  
} 

Numeric型クラスでは、追加型クラスを追加する必要がありますパイの値を供給しないので

def multiplyWithPi[A](in: A)(implicit num: MyNumeric[A], pi: Pi[A]) : A = 
    num.times(pi(), in) 
3

に組み込まれていますNumeric[T]型クラススカラはかなり基本的です。スカラーで数学を少し進歩させたい場合は、spire数学ライブラリを使うことをお勧めします。ここで

あなたは尖塔に機能を実装する方法を次のとおりです。Ring[T]型クラスは乗算を許可するタイプのためである:ここでは

import spire.algebra._ // algebraic typeclasses 
import spire.implicits._ // syntax and instances 

def multiplyWithPi[A: Ring: Trig](x: A) : A = { 
    Trig[A].pi * x 
} 

は、それがどのように動作するかです。 Trig[T] typeclassは、三角法を可能にする型です。 sinのような三角関数に加えて、値pieもあります。

ではなくは、不正確な2倍近似からTに変換することに依存しています(Math.PI)。例えば。 spireには正確な算術演算のためのいくつかの数値型があります。それらについては、二重近似からの変換は非常に不正確である。

Trig[T]およびRing[T]を含むすべてのタイプメーター用のインポートです。 spire.implicits._インポートは、FloatDoubleの事前定義されたtypeclassインスタンスを提供します。

libraryDependencies += "org.spire-math" %% "spire" % "0.13.0" 
関連する問題