Scala Doubles, and Precision

前端 未结 12 1243
逝去的感伤
逝去的感伤 2020-12-12 21:19

Is there a function that can truncate or round a Double? At one point in my code I would like a number like: 1.23456789 to be rounded to 1.23

相关标签:
12条回答
  • 2020-12-12 22:06

    A bit strange but nice. I use String and not BigDecimal

    def round(x: Double)(p: Int): Double = {
        var A = x.toString().split('.')
        (A(0) + "." + A(1).substring(0, if (p > A(1).length()) A(1).length() else p)).toDouble
    }
    
    0 讨论(0)
  • 2020-12-12 22:08

    You can use scala.math.BigDecimal:

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

    There are a number of other rounding modes, which unfortunately aren't very well documented at present (although their Java equivalents are).

    0 讨论(0)
  • 2020-12-12 22:08

    I wouldn't use BigDecimal if you care about performance. BigDecimal converts numbers to string and then parses it back again:

      /** Constructs a `BigDecimal` using the decimal text representation of `Double` value `d`, rounding if necessary. */
      def decimal(d: Double, mc: MathContext): BigDecimal = new BigDecimal(new BigDec(java.lang.Double.toString(d), mc), mc)
    

    I'm going to stick to math manipulations as Kaito suggested.

    0 讨论(0)
  • 2020-12-12 22:12

    Edit: fixed the problem that @ryryguy pointed out. (Thanks!)

    If you want it to be fast, Kaito has the right idea. math.pow is slow, though. For any standard use you're better off with a recursive function:

    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
      }
    }
    

    This is about 10x faster if you're within the range of Long (i.e 18 digits), so you can round at anywhere between 10^18 and 10^-18.

    0 讨论(0)
  • 2020-12-12 22:12

    You may use implicit classes:

    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))
    }
    
    0 讨论(0)
  • 2020-12-12 22:12

    Recently, I faced similar problem and I solved it using following approach

    def round(value: Either[Double, Float], places: Int) = {
      if (places < 0) 0
      else {
        val factor = Math.pow(10, places)
        value match {
          case Left(d) => (Math.round(d * factor) / factor)
          case Right(f) => (Math.round(f * factor) / factor)
        }
      }
    }
    
    def round(value: Double): Double = round(Left(value), 0)
    def round(value: Double, places: Int): Double = round(Left(value), places)
    def round(value: Float): Double = round(Right(value), 0)
    def round(value: Float, places: Int): Double = round(Right(value), places)
    

    I used this SO issue. I have couple of overloaded functions for both Float\Double and implicit\explicit options. Note that, you need to explicitly mention the return type in case of overloaded functions.

    0 讨论(0)
提交回复
热议问题