3

数値解法関数 ( ) があり、2 種類の数値を区別Double => Doubleするために巧妙に使用しようとしました。Numeric[T]

これは簡単なことではありませんでした。残りの問題は次のとおりです。

  • 割り算のやり方; Numeric[T]プラス、マイナスなどの演算子のみがあります。
  • コンパイラが関数を見つけられない理由implicit evidence$1: Numeric[Double](以下のコンパイラ出力を参照)

理想的には、「ABは両方Doubleですが、それらを混ぜ合わせたら教えてください」と言いたいです。

コードは次のとおりです。

import scala.annotation.tailrec

class Sweep[A: Numeric, B: Numeric]( fDiff: A => B, initialSeed: A, initialStep: A, bEps: B )
{
  val anum= evidence$1
  val bnum= evidence$2

  assert( anum.signum(initialStep) > 0 )
  assert( bnum.lt( fDiff(initialSeed), fDiff( anum.plus(initialSeed,initialStep) )) )   // check that it's an increasing function

  @tailrec
  private def sweep( seed: A, step: A ): A = {
    val bDiff= fDiff(seed)

    if ( bnum.lt( bnum.abs(bDiff), bEps) ) {  // done
      seed
    } else if ( bnum.signum(bDiff) != anum.signum(step) ) {
      sweep( anum.plus(seed,step), step )   // continue, same step and direction ('bDiff' should go smaller)
    } else {
      val newStep = anum.toDouble(step) / -2.0
      sweep( anum.minus(seed,newStep), newStep )    // reverse, smaller step
    }
  }

  // Make sure we take the initial step in the right direction
  //  
  private lazy val stepSign= -bnum.signum( fDiff(initialSeed) )

  def apply: A = sweep( initialSeed, stepSign * initialStep )
}

object TestX extends App {

  val t= new Sweep( (a: Double) => (a*a)-2, 1.0, 0.5, 1e-3 )()

  println( t, math.sqrt(2.0) )
}

(implicit anum: Numeric[A])古いパラメーターでも試してみましたが、そのような2つ( forAとの両方B)を持つことができませんでした。

コンパイラが言うことは次のとおりです(Scala 2.9):

fsc -deprecation -d out-make -unchecked src/xxx.scala
src/xxx.scala:25: error: type mismatch;
 found   : newStep.type (with underlying type Double)
 required: A
      sweep( anum.minus(seed,newStep), newStep )    // reverse, smaller step
                             ^
src/xxx.scala:33: error: overloaded method value * with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Long <and>
  (x: Int)Int <and>
  (x: Char)Int <and>
  (x: Short)Int <and>
  (x: Byte)Int
 cannot be applied to (A)
  def apply: A = sweep( initialSeed, stepSign * initialStep )
                                              ^
src/xxx.scala:38: error: not enough arguments for constructor Sweep: (implicit evidence$1: Numeric[Double], implicit evidence$2: Numeric[Double])Sweep[Double,Double].
Unspecified value parameters evidence$1, evidence$2.
  val t= new Sweep( (a: Double) => (a*a)-2, 1.0, 0.5, 1e-3 )()
         ^
three errors found

アイデアをありがとう。

4

3 に答える 3

3

Fractionalの代わりに作業したいNumeric。以下は私のためにコンパイルされます:

import scala.annotation.tailrec
import math.Fractional.Implicits._
import Ordering.Implicits._

class Sweep[A: Fractional, B: Fractional](fDiff: A => B, initialSeed: A, initialStep: A, bEps: B) {
  val aFractional = implicitly[Fractional[A]]

  assert(initialStep.signum > 0)
  assert(fDiff(initialSeed) < fDiff(initialSeed + initialStep))

  @tailrec
  private def sweep(seed: A, step: A): A = {
    val bDiff = fDiff(seed)
    if (bDiff.abs < bEps) {
      seed
    } else if (bDiff.signum != step.signum) {
      sweep(seed + step, step)
    } else {
      val one = aFractional.one
      val newStep = step / aFractional.fromInt(-2)
      sweep(seed - newStep, newStep)
    }
  }

  private lazy val stepSign = aFractional.fromInt(-fDiff(initialSeed).signum)
  def apply: A = sweep(initialSeed, stepSign * initialStep)
}

val sweep = new Sweep((a: Double) => (a*a)-2, 1.0, 0.5, 1e-3)
println(sweep.apply, math.sqrt(2.0))

-2.0in typeAのようなものを取得するには、 から手動でアセンブルするFractional.oneか、 を使用する必要があることに注意してくださいFractional.fromInt

指摘する価値のあるもう 1 つの点は、 and の使用ですmath.Fractional.Implicits。これにより、 andのOrdering.Implicitsような関数を呼び出す代わりに、通常の数学構文 (+、<、/ など) を使用できます。plusdiv

于 2012-12-12T12:33:46.623 に答える
0

A型パラメーターとBが同じでない場合にコンパイラーに通知させたい場合は、型パラメーターを 1 つだけ使用します。

class Sweep[A: Numeric]( fDiff: A => A, initialSeed: A, initialStep: A, bEps: A )
于 2012-12-12T11:58:29.667 に答える
0

問題は、Doubleここで使用しているようです...

val newStep = anum.toDouble(step) / -2.0

...使用したいのですがNumeric、実際には次の行でそのように使用します。

除算については、NumericのサブタイプIntegralと を見てくださいFractional

明示的に何も渡さないため、コンパイラは暗黙の証拠を検出しません。

new Sweep((a: Double) => (a*a)-2, 1.0, 0.5, 1e-3)()

明示的な空のパラメーター リストを削除すると、次のことが修正されます。

new Sweep((a: Double) => (a*a)-2, 1.0, 0.5, 1e-3)

Aとを混在させないという要件についてはB、コード内の複数の場所で既に行っているため、よくわかりません。

これがあなたの望むものかどうかはわかりませんが、次のコードが機能します。

import scala.annotation.tailrec

class Sweep[A: Fractional](fDiff: A => A, initialSeed: A, initialStep: A, bEps: A) {
  val num = implicitly[Fractional[A]]

  assert(num.signum(initialStep) > 0)
  assert(num.lt(fDiff(initialSeed), fDiff(num.plus(initialSeed, initialStep)))) // check that it's an increasing function

  @tailrec
  private def sweep(seed: A, step: A): A = {
    val bDiff = fDiff(seed)

    if (num.lt(num.abs(bDiff), bEps)) { // done
      seed
    } else if (num.signum(bDiff) != num.signum(step)) {
      sweeimport scala.annotation.tailrec

class Sweep[A: Fractional](fDiff: A => A, initialSeed: A, initialStep: A, bEps: A) {
  val num = implicitly[Fractional[A]]

  assert(num.signum(initialStep) > 0)
  assert(num.lt(fDiff(initialSeed), fDiff(num.plus(initialSeed, initialStep)))) // check that it's an increasing function

  @tailrec
  private def sweep(seed: A, step: A): A = {
    val bDiff = fDiff(seed)

    if (num.lt(num.abs(bDiff), bEps)) { // done
      seed
    } else if (num.signum(bDiff) != num.signum(step)) {
      sweep(num.plus(seed, step), step) // continue, same step and direction ('bDiff' should go smaller)
    } else {
      val newStep = num.div(step, num.fromInt(-2))
      sweep(num.minus(seed, newStep), newStep) // reverse, smaller step
    }
  }

  // Make sure we take the initial step in the right direction
  private lazy val stepSign = -num.signum(fDiff(initialSeed))

  def apply: A = sweep(initialSeed, num.times(num.fromInt(stepSign), initialStep))
}

object TestX extends App {

  val t = new Sweep((a: Double) => (a * a) - 2, 1.0, 0.5, 1e-3)

  println(t, math.sqrt(2.0))
}

p(num.plus(seed, step), step) // continue, same step and direction ('bDiff' should go smaller)
    } else {
      val newStep = num.div(step, num.fromInt(-2))
      sweep(num.minus(seed, newStep), newStep) // reverse, smaller step
    }
  }

  // Make sure we take the initial step in the right direction
  private lazy val stepSign = -num.signum(fDiff(initialSeed))

  def apply: A = sweep(initialSeed, num.times(num.fromInt(stepSign), initialStep))
}

object TestX extends App {

  val t = new Sweep((a: Double) => (a * a) - 2, 1.0, 0.5, 1e-3)

  println(t, math.sqrt(2.0))
}
于 2012-12-12T12:06:20.763 に答える