Scala 双精度和精度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11106886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 04:15:31  来源:igfitidea点击:

Scala Doubles, and Precision

scaladoubletruncaterounding

提问by richsoni

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

是否有可以截断或舍入 Double 的函数?在我的代码中,我想要一个数字,例如:1.23456789四舍五入到1.23

回答by Travis Brown

You can use scala.math.BigDecimal:

您可以使用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).

还有许多其他的舍入模式,遗憾的是目前还没有很好的记录(尽管它们的 Java 等效项是)。

回答by Kaito

Here's another solution without BigDecimals

这是另一个没有 BigDecimals 的解决方案

Truncate:

截短:

(math floor 1.23456789 * 100) / 100

Round:

圆形的:

(math rint 1.23456789 * 100) / 100

Or for any double n and precision p:

或者对于任何双精度 n 和精度 p:

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

Similar can be done for the rounding function, this time using currying:

可以对舍入函数进行类似操作,这次使用柯里化:

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

which is more reusable, e.g. when rounding money amounts the following could be used:

这是更可重用的,例如,当四舍五入金额时,可以使用以下内容:

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

回答by akauppi

Since no-one mentioned the %operator yet, here comes. It only does truncation, and you cannot rely on the return value not to have floating point inaccuracies, but sometimes it's handy:

由于还没有人提到%运营商,所以来了。它只进行截断,您不能依赖返回值来避免浮点数不准确,但有时它很方便:

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

回答by blue-sky

How about :

怎么样 :

 val value = 1.4142135623730951

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

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

回答by Rex Kerr

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

编辑:修复了@ryryguy 指出的问题。(谢谢!)

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

如果你想快点,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
  }
}

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.

如果您在 范围内Long(即 18 位数字),这大约快 10 倍,因此您可以在 10^18 和 10^-18 之间的任何位置取整。

回答by Mitrakov Artem

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

回答by cevaris

For those how are interested, here are some times for the suggested solutions...

对于那些有兴趣的人,这里有一些建议的解决方案......

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

Truncation
Scala custom Formatter: Elapsed Time: 3 

Truncation is the fastest, followed by BigDecimal. Keep in mind these test were done running norma scala execution, not using any benchmarking tools.

截断是最快的,其次是 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())
      }
    }
  }

}

回答by Khalid Saifullah

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 thisSO 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.

我使用了这个SO 问题。我有两个 Float\Double 和隐式\显式选项的重载函数。请注意,在重载函数的情况下,您需要明确提及返回类型。

回答by bigonazzi

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

如果您关心性能,我不会使用 BigDecimal。BigDecimal 将数字转换为字符串,然后再次解析它:

  /** 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 Kaitosuggested.

我将坚持使用Kaito建议的数学操作。

回答by R Sun

It's actually very easy to handle using Scala finterpolator - https://docs.scala-lang.org/overviews/core/string-interpolation.html

使用 Scalaf插值器实际上很容易处理- https://docs.scala-lang.org/overviews/core/string-interpolation.html

Suppose we want to round till 2 decimal places:

假设我们要四舍五入到小数点后两位:

scala> val sum = 1 + 1/4D + 1/7D + 1/10D + 1/13D
sum: Double = 1.5697802197802198

scala> println(f"$sum%1.2f")
1.57