[scala] Scala Doubles 및 정밀도

Double을 자르거나 반올림 할 수있는 함수가 있습니까? :처럼 내 코드의 한 시점에서 나는 수를 싶습니다 1.23456789반올림 할1.23



답변

다음을 사용할 수 있습니다 scala.math.BigDecimal.

BigDecimal(1.23456789).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble

다른 많은 반올림 모드가 있습니다 . 불행히도 현재 문서화가 잘되어 있지 않습니다 ( 자바에 해당하는 것은 ).


답변

BigDecimals가없는 또 다른 솔루션이 있습니다.

자르기 :

(math floor 1.23456789 * 100) / 100

일주:

(math rint 1.23456789 * 100) / 100

또는 double n 및 정밀도 p의 경우 :

def truncateAt(n: Double, p: Int): Double = { val s = math pow (10, p); (math floor n * s) / s }

이번에는 currying을 사용하여 반올림 함수에 대해서도 유사하게 수행 할 수 있습니다.

def roundAt(p: Int)(n: Double): Double = { val s = math pow (10, p); (math round n * s) / s }

예를 들어 돈을 반올림 할 때 다음을 사용할 수 있습니다.

def roundAt2(n: Double) = roundAt(2)(n)


답변

%아직 아무도 운영자를 언급 하지 않았으므로 여기에옵니다. 자르기 만 수행하며 부동 소수점 부정확성을 갖지 않기 위해 반환 값에 의존 할 수는 없지만 때로는 편리합니다.

scala> 1.23456789 - (1.23456789 % 0.01)
res4: Double = 1.23


답변

어때 :

 val value = 1.4142135623730951

//3 decimal places
println((value * 1000).round / 1000.toDouble)

//4 decimal places
println((value * 10000).round / 10000.toDouble)


답변

편집 : @ryryguy가 지적한 문제를 수정했습니다. (감사!)

빠른 속도를 원한다면 Kaito는 올바른 아이디어를 가지고 있습니다. math.pow하지만 느립니다. 모든 표준 사용의 경우 재귀 함수를 사용하는 것이 좋습니다.

def trunc(x: Double, n: Int) = {
  def p10(n: Int, pow: Long = 10): Long = if (n==0) pow else p10(n-1,pow*10)
  if (n < 0) {
    val m = p10(-n).toDouble
    math.round(x/m) * m
  }
  else {
    val m = p10(n).toDouble
    math.round(x*m) / m
  }
}

범위 Long(예 : 18 자리) 내에있는 경우 약 10 배 더 빠르 므로 10 ^ 18에서 10 ^ -18 사이에서 반올림 할 수 있습니다.


답변

암시 적 클래스를 사용할 수 있습니다.

import scala.math._

object ExtNumber extends App {
  implicit class ExtendedDouble(n: Double) {
    def rounded(x: Int) = {
      val w = pow(10, x)
      (n * w).toLong.toDouble / w
    }
  }

  // usage
  val a = 1.23456789
  println(a.rounded(2))
}


답변

관심이있는 분들을 위해 제안 된 솔루션에 대한 몇 가지 시간이 있습니다.

Rounding
Java Formatter: Elapsed Time: 105
Scala Formatter: Elapsed Time: 167
BigDecimal Formatter: Elapsed Time: 27

Truncation
Scala custom Formatter: Elapsed Time: 3 

잘림이 가장 빠르고 BigDecimal이 그 뒤를 따릅니다. 이 테스트는 벤치마킹 도구를 사용하지 않고 norma scala 실행을 실행하여 수행되었습니다.

object TestFormatters {

  val r = scala.util.Random

  def textFormatter(x: Double) = new java.text.DecimalFormat("0.##").format(x)

  def scalaFormatter(x: Double) = "$pi%1.2f".format(x)

  def bigDecimalFormatter(x: Double) = BigDecimal(x).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble

  def scalaCustom(x: Double) = {
    val roundBy = 2
    val w = math.pow(10, roundBy)
    (x * w).toLong.toDouble / w
  }

  def timed(f: => Unit) = {
    val start = System.currentTimeMillis()
    f
    val end = System.currentTimeMillis()
    println("Elapsed Time: " + (end - start))
  }

  def main(args: Array[String]): Unit = {

    print("Java Formatter: ")
    val iters = 10000
    timed {
      (0 until iters) foreach { _ =>
        textFormatter(r.nextDouble())
      }
    }

    print("Scala Formatter: ")
    timed {
      (0 until iters) foreach { _ =>
        scalaFormatter(r.nextDouble())
      }
    }

    print("BigDecimal Formatter: ")
    timed {
      (0 until iters) foreach { _ =>
        bigDecimalFormatter(r.nextDouble())
      }
    }

    print("Scala custom Formatter (truncation): ")
    timed {
      (0 until iters) foreach { _ =>
        scalaCustom(r.nextDouble())
      }
    }
  }

}