2012-12-12 88 views
3

我有一個數值求解功能(Double => Double),我試圖聰明,並使用Numeric[T]保持兩種數字分開。斯卡拉數字問題[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])參數,但未能有兩個這樣的(都爲AB)。

以下是編譯器說的話(斯卡拉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 

感謝您的任何想法。

回答

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.0A類型,則需要從Fractional.one手工組裝,或用Fractional.fromInt

值得指出的另一件事是使用math.Fractional.ImplicitsOrdering.Implicits這將允許你使用普通數學語法(+,<,/等)而不是調用的功能,如plusdiv

+0

準確。謝謝。而且我甚至可以使用正常的操作員!我的原始代碼中有一個錯誤:「 - newStep」應該是「+ newStep」(使得結果更快)。 – akauppi

0

如果你希望編譯器告訴你什麼時候該類型參數AB是不一樣的,只是使用一種類型的參數:

class Sweep[A: Numeric](fDiff: A => A, initialSeed: A, initialStep: A, bEps: A) 
+0

讓我換句話。類型可能相同,但數字意味着不同的事物。所以我希望聽到例如我做'a + b'。爲了使代碼工作,我可以跳過這一切,但我也嘗試瞭解真正的Scala。 :) – akauppi

+1

我不確定我是否理解你。你希望兩種類型是相同的類型:所以使用*一個*類型 –

+0

A類型通常表示秒,B類其他(即速度)。因此,它們對於編譯器來說都是雙精度的,但不能將它們從概念上統計在一起。 – akauppi

0

這個問題似乎是,你使用Double這裏...

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

...儘管你想使用Numeric和實際使用它的下一行的方式。

對於劃分,看看Numeric的亞型IntegralFractional

編譯器沒有找到一個隱含的證據,因爲你明確地傳遞無:

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) 

我不知道的不混合AB的要求,因爲您已經在代碼中的多個位置執行此操作。

我不知道這是你想要的,但下面的代碼工作:

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)) 
} 
+0

是的,但是因爲'Numeric [T]'沒有分割,我不得不去做。從Double到A似乎沒有辦法? – akauppi

+0

你讀過代碼了嗎? – soc