score:0

I'm not sure I understand your distinction between A and B. But since you have f: A => B, I assume they can somehow be converted into each other? Then looking at the code, my impression is that A is the main type, so why not convert all B type things into A instead of the other way around?

Then you can spare any conversions to Double, that seems not a good idea anyway.

/*
* 'f' is a "strictly increasing function" (derivative > 0).
* The sweep gives the value at which it gives 'goal' (within '+-bEps' margins).
*/
object NewtonianSweep {
  def apply[A: Fractional, B: Fractional]( 
    // f: A => B, 
    fDerivate: A => A, 
    goal: B, 
    bEps: B, 
    initialSeed: A, 
    aMin: A, 
    aMax: A 
  )(f: B => A) : A = {

    assert( initialSeed >= aMin && initialSeed <= aMax )

    // 'goal' is supposed to exist within the range (this also checks that
    // the function is increasing - though doesn't (cannot) check "strict increasing",
    // we'll just trust the caller.
    //
    val aGoal = f(goal)
    val aEps  = f(bEps)

    assert(aMin <= aGoal)
    assert(aMax >= aGoal)

    val aType = implicitly[Fractional[A]]

    @tailrec
    def sweep(_seed: A): A = {
      val seed = _seed.max(aMin).min(aMax)   // keep 'seed' within range

      val aDiff = aGoal - seed    // >0 for heading higher, <0 for heading lower

      if (aDiff.abs < aEps) {
        seed                        // done (within margins)
      } else {
        val d = fDerivate(seed)      // slope at the particular position (dy/dx)
        assert(d > aType.zero)
        val prod = d * aDiff
        sweep(seed + prod)
      }
    }

    sweep(initialSeed)
  }
}

Related Query

More Query from same tag