Scala 让exp在spire工作

Scala 让exp在spire工作,scala,numeric,spire,Scala,Numeric,Spire,我学习scala是为了科学编程。我正在尝试使用spire编写一些简单的通用代码。我已经有了下面的例子: import spire.algebra._ import spire.math._ import spire.implicits._ object TestSqrt { def testSqrt[T: Numeric](x: T) = { sqrt(x) } def main(args: Array[String]){ val x_d

我学习scala是为了科学编程。我正在尝试使用spire编写一些简单的通用代码。我已经有了下面的例子:

import spire.algebra._
import spire.math._
import spire.implicits._
object TestSqrt {
    def testSqrt[T: Numeric](x: T) = {
        sqrt(x)
    }

    def main(args: Array[String]){
        val x_d: Double = 4.0
        println(testSqrt(x_d))

        val x_i: Int = 4
        println(testSqrt(x_i))
    }
}
这将按预期打印出2.0和2。问题是我不能用exp函数处理同样的事情。以下代码未编译:

import spire.algebra._
import spire.math._
import spire.implicits._
object TestExp {
    def testExp[T: Numeric](x: T) = {
        exp(x)
    }

    def main(args: Array[String]){
        val x_d: Double = 4.0
        println(testExp(x_d))

        val x_i: Int = 4
        println(testExp(x_i))
    }
}
编者说:

... could not find implicit value for parameter t: spire.algebra.Trig[T]
[error]         exp(x)
[error]            ^  
[error] one error found
[error] (compile:compile) Compilation failed
我是否做错了什么,exp是否还不受支持,或者这是一个bug?有谁能提供一个从spire将exp与通用数字类型一起使用的工作示例吗

更新:

我可以使用Trig而不是Numeric使exp工作,如下所示:

import spire.algebra._
import spire.math._
import spire.implicits._
object TestExp {
    def testExp[T: Trig](x: T) = {
        exp(x)
    }

    def main(args: Array[String]){
        val x_d: Double = 1.0
        println(testExp(x_d))

        val x_f: Float = 1.0f
        println(testExp(x_f))
        // val x_i: Int = 4
        // println(testExp(x_i))
    }
}
但是,它不适用于Int,只适用于浮点类型。此外,如果我使用Trig,那么就不能使用sqrt。以下代码未编译:

import spire.algebra._
import spire.math._
import spire.implicits._
object TestExp {
    def testExp[T: Numeric](x: T) = {
        exp(x)
    }

    def main(args: Array[String]){
        val x_d: Double = 4.0
        println(testExp(x_d))

        val x_i: Int = 4
        println(testExp(x_i))
    }
}
}

并给出了错误:

... could not find implicit value for evidence parameter of type spire.algebra.Trig[Int]
[error]         println(testSqrt(x_i))
[error]                         ^
[error] two errors found
[error] (compile:compile) Compilation failed

如果我同时需要exp和sqrt,有没有办法使exp与整数类型一起工作?

类型类被定义为操作数和运算结果的类型相同。也就是说,当您对类型为
a
的值运行
sqrt
时,结果也将是类型为
a

现在,您可能会认为整数上的
sqrt
会为某些特定的输入值生成整数,例如您在示例中使用的4。另一方面,
sqrt(5)
应该返回什么?它似乎将返回小于实际平方根的最大整数:

def testSqrt[T: Numeric](x: T): T = sqrt(x)

scala> testSqrt(5)
res0: Int = 2
这不是你想要的。有趣的是,当您直接调用
sqrt
函数时,它将返回一个
Double

scala> sqrt(5)
res1: Double = 2.23606797749979
原因是,当您导入
spire.math.\ucode>时,会得到一个重载的
sqrt
函数:

final def sqrt(x: Double): Double = Math.sqrt(x)
final def sqrt[A](a: A)(implicit ev: NRoot[A]): A = ev.sqrt(a)
这通过赋予第一个变量优先级来“解决”问题(因为它不需要隐式参数)。在您的示例中,您使用了一个通用签名,因此将调用
sqrt
的第二个版本。
NRoot
参数是间接提供的,因为您说您有一个
Numeric

因此,你必须决定你要做什么,在计算平方根时,你想退回到
Double
,还是采用这种可能会截断结果的非常规方法


现在是指数运算。在
math
中,仍然有
exp
的重载版本,其中包括:

final def exp(n: Double): Double = Math.exp(n)
final def exp[A](a: A)(implicit t: Trig[A]): A = t.exp(a)
sqrt
不同的是,在任何情况下都不会得到
Trig[Int]
。没有什么有意义的方法

让我们定义一个函数,它可以根据类型类调用
sqrt
an
exp

def sqrtAndExp[T: NRoot: Trig](x: T): (T, T) = (sqrt(x), exp(x))
您可以看到,在函数声明中可以使用多个上下文绑定。此语法相当于

def sqrtAndExp[T](x: T)(implicit nroot: NRoot[T], trig: Trig[T]: (T, T) =
  (sqrt(x), exp(x))
对于double,此函数起作用(假设您已导入
spire.implicits.\u
):

但不适用于整数:

scala> sqrtAndExp(5)
<console>:18: error: could not find implicit value for evidence parameter of type
                     spire.algebra.Trig[Int]
              sqrtAndExp(5)
                        ^

非常清楚,解决了我的问题。我不知道您可以使用多个上下文边界。显然,如果希望能够使用整数文本调用它,您还可以添加重载函数
def sqrtAndExp(x:Double):(Double,Double)
scala> sqrtAndExp(5)
<console>:18: error: could not find implicit value for evidence parameter of type
                     spire.algebra.Trig[Int]
              sqrtAndExp(5)
                        ^
scala> sqrtAndExp[Double](5)
res3: (Double, Double) = (2.23606797749979,148.4131591025766)