回答:
使用できますscala.math.BigDecimal
:
BigDecimal(1.23456789).setScale(2, BigDecimal.RoundingMode.HALF_UP).toDouble
他にも多くの丸めモードがありますが、残念ながら現在のところ十分に文書化されていません(Javaでの同等物はですが)。
"%.2f".format(x).toDouble
その場合にお勧めします。速度が2倍遅く、すでに知っているライブラリを使用するだけで済みます。
scala> "%.2f".format(0.714999999999).toDouble
res13: Double = 0.71
しかしscala> "%.2f".format(0.715).toDouble
res14: Double = 0.72
。
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 }
丸め関数についても同様ですが、今回はカリーを使用します。
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)
NaN
ではありませんか?
floor
は、truncateAt(1.23456789, 8)
が正しい値を返す1.23456788
一方roundAt(1.23456789, 8)
で、1.23456789
誰も%
まだオペレーターに言及していないので、ここに来ます。これは切り捨てを行うだけであり、戻り値を使用して浮動小数点が不正確にならないようにすることはできませんが、便利な場合があります。
scala> 1.23456789 - (1.23456789 % 0.01)
res4: Double = 1.23
26.257391515826225 - 0.057391515826223094 = 26.200000000000003
どのように:
val value = 1.4142135623730951
//3 decimal places
println((value * 1000).round / 1000.toDouble)
//4 decimal places
println((value * 10000).round / 10000.toDouble)
((1.949 * 1000).toInt - ((1.949 * 1000).toInt % 10)) / 1000.toDouble
それをあまりテストしませんでした。このコードは小数点以下2桁を実行します。
編集:@ryryguyが指摘した問題を修正しました。(ありがとう!)
あなたがそれを速くしたいなら、カイトは正しい考えを持っています。 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の間の任意の場所で丸めることができます。
scala> def r5(x:Double) = math.round(x*100000)*0.000001; r5(0.23515)
==> として確実に表現できない可能性があるため、確実に機能しませんres12: Double = 0.023514999999999998
。代わりに意義除算:math.round(x*100000)/100000.0
p10
関数を配列ルックアップに置き換えると便利な場合があります。配列によってメモリ消費量が約200バイト増加しますが、呼び出しごとに数回の繰り返しを節約できます。
暗黙のクラスを使用できます。
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が続きます。これらのテストは、ベンチマークツールを使用せずに、標準の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())
}
}
}
}
...truncate or round a Double
。
doubleParts.tail
文字列 "。"と連結します。そしてdoubleParts. head
、解析して2倍にします。
toString.split(".")
とdoubleParts.head/tail
提案は、余分な配列割り当てと文字列連結の影響を受ける可能性があります。確認するためにテストする必要があります。
最近、私は同様の問題に直面し、次のアプローチを使用してそれを解決しました
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)
私はこの SOの問題を使用しました。Float \ Doubleオプションとimplicit \ explicitオプションの両方にオーバーロードされた関数がいくつかあります。関数がオーバーロードされている場合は、戻り値の型を明示的に言及する必要があることに注意してください。
Scala f
インターポレーターを使用して処理するのは実際には非常に簡単です-レーター -https://docs.scala-lang.org/overviews/core/string-interpolation.html
小数点第2位まで四捨五入したいとします。
scala> val sum = 1 + 1/4D + 1/7D + 1/10D + 1/13D
sum: Double = 1.5697802197802198
scala> println(f"$sum%1.2f")
1.57
パフォーマンスを重視する場合は、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)
Kaitoが提案したように、私は数学の操作に固執します。
あなたができること:Math.round(<double precision value> * 100.0) / 100.0
しかし、Math.roundは最速ですが、小数点以下の桁数が非常に多い(例:round(1000.0d、17))または大きな整数部分(例:round(90080070060.1d、9)のいずれかが多いコーナーケースでは、うまく機能しません。)。
Bigdecimalを使用します。値を文字列に変換するため少し効率が悪くなりますが、より安全です。
BigDecimal(<value>).setScale(<places>, RoundingMode.HALF_UP).doubleValue()
使用します。です。丸めモードの設定を使用してください。