【问题标题】:Calculate average of array in Scala - Result truncated计算Scala中数组的平均值 - 结果被截断
【发布时间】:2021-01-13 23:43:25
【问题描述】:

我已经用 TDD 学习了几天的 Scala,所以我有以下单元测试:

test("CalcStats.calculateAverage should return average") {
    assert(CalcStats.calculateAverage(Array(6, 9, 15, -2, 92, 11)) === 21.833333)
  }

据我所知,以下应该可以通过:

def calculateAverage(values: Array[Int]): Float = {
    values.sum / values.size
  }

但是,我得到的是 21.0 而不是 21.833333,所以单元测试会失败❌

Expected :21.833333
Actual   :21.0

只要我指定结果将是一个浮点数,我认为这就足够了,但绝对不是。我应该怎么做才能避免结果被截断?

提前致谢。

【问题讨论】:

  • 记住浮点运算在计算机中并不精确。所以,有两个建议。 1 使用 Double 而不是 Float。 2. 与错误比较,Scalatest 提供像 foo shouldBe x +/-0.01 这样的语法,或者如果你不喜欢花哨的语法,你可以只使用 math.abs(expected - result) < 0.01 - 最后,我建议你不要使用普通的 Arrays,而是具体的真实集合,例如 ListVectorArraySeq
  • 确实,Double 效果更好,谢谢!如果足够了,为什么不使用普通数组? (越简单越好)
  • 因为普通的 Arrays 是:可变的、不变的并且不是真正的集合,所以你不能在接受诸如 Seq 之类的方法中使用它们>IterableOnce。数组是 JVM 的原语,可用于与平台原生代码(例如 Java 或 JS) 或性能敏感代码的互操作。在所有其他情况下,最好使用普通的不可变集合。

标签: scala stream average


【解决方案1】:

这个方法应该可以工作 - 只是一个简单的递归方法来添加列表中的所有值,当为空时,除以列表的总大小。

def getAverage(list: List[Double]): Double = {
  def loop(list: List[Double], acc: Double = 0): Double = {
    list match {
      case Nil => acc / list.size
      case element :: tail => loop(tail, acc + element)
    }  
  }

  loop(list)
}

【讨论】:

    【解决方案2】:

    def calculateAverage(values: Array[Int]): Float = {
    values.sum / values.size}
    

    基础结果 values.sum / values.size 具有类型 Int (21) 因此,编译器将其扩展为Float。 请尝试以下操作:

    def calculateAverage(values: Array[Int]): Float = {
    values.sum.toFloat / values.size  }
    

    【讨论】:

    • 奥列格的一次非常好的接球!仅作记录,并遵循@Luis Miguel Mejia Suarez 的建议,我意识到它与 Double 一起使用效果更好。干杯!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-25
    • 2014-05-14
    相关资源
    最近更新 更多