编写 BigDecimal 计算,就好像它只是 Scala 中常见的四次算术运算
Write BigDecimal calculation as if it's just a usual Four arithmetic operations in Scala
我目前正在研究 Scala,并且对它的出色表现感到惊讶。
我认为最重要的一点是它如何处理 BigDecimal
type.Once 定义 BigDecimal
您几乎可以像使用 Int
或 Double
val foo:BigDecimal = 0.1
println(foo + 0.2) // 0.3
无需使用 .multiply()
或 .add()
,只需使用 +
或 *
即可处理 BigDecimal 计算(我假设 BigDecimal
的 +
/*
虽然最终会在其中调用它们)。即使计算变得复杂,它也很容易阅读,除了你必须将第一个计算值声明为 BigDecimal
。
println(0.3 * (BigDecimal(0.1) + 0.2))
我的问题是,我怎样才能像这样编写上面的代码?
println(0.3 * (0.1 + 0.2))
我假设这需要覆盖数字类型文字。
提前致谢。
我认为您无法覆盖数字文字。您可以做的是使用字符串插值或向 Double
.
添加方法来稍微简化语法
// With string interpolation
implicit class BigDecimalStringContext(private val sc: StringContext) extends AnyVal {
def d(args: Any*): BigDecimal = {
val stringRepr = sc.s(args: _*)
BigDecimal(stringRepr)
}
}
println(d"0.3" * (d"0.1" + d"0.2"))
println(0.3 * (d"0.1" + 0.2))
// Pimp my library
implicit class DoubleOps(private val d: Double) extends AnyVal {
def bd = BigDecimal(d)
}
println(0.3.bd * (0.1.bd + 0.2.bd))
println(0.3 * (0.1.bd + 0.2))
第一种方法比较安全,因为第二种方法试图转换一个Double
,因此可能会丢失精度:
scala> 0.123456789012345678901234567890.bd * (0.1.bd + 0.2.bd)
res1: scala.math.BigDecimal = 0.037037036703703704
scala> d"0.123456789012345678901234567890" * (d"0.1" + d"0.2")
res2: scala.math.BigDecimal = 0.0370370367037037036703703703670
不幸的是,Scala 不允许覆盖文字。
你可以在适当的语言中轻松地做一件事,那就是提供你自己的 StringContext
for string interpolation:
implicit class BigDecimalStringContext(val sc: StringContext) extends AnyVal {
def d() = BigDecimal(sc.parts.head)
}
val test = d"0.1"
// => test: scala.math.BigDecimal = 0.1
我相信 Macros 不允许您覆盖文字。
Scala-Virtualized 是 Scala 的一个分支,其中(几乎)所有内容(包括控制结构和对象构造)都转换为方法调用,因此可以重载。不幸的是,几乎一切都不包括重载文字。
但是,您可以使用编译器插件做一些事情。
我目前正在研究 Scala,并且对它的出色表现感到惊讶。
我认为最重要的一点是它如何处理 BigDecimal
type.Once 定义 BigDecimal
您几乎可以像使用 Int
或 Double
val foo:BigDecimal = 0.1
println(foo + 0.2) // 0.3
无需使用 .multiply()
或 .add()
,只需使用 +
或 *
即可处理 BigDecimal 计算(我假设 BigDecimal
的 +
/*
虽然最终会在其中调用它们)。即使计算变得复杂,它也很容易阅读,除了你必须将第一个计算值声明为 BigDecimal
。
println(0.3 * (BigDecimal(0.1) + 0.2))
我的问题是,我怎样才能像这样编写上面的代码?
println(0.3 * (0.1 + 0.2))
我假设这需要覆盖数字类型文字。
提前致谢。
我认为您无法覆盖数字文字。您可以做的是使用字符串插值或向 Double
.
// With string interpolation
implicit class BigDecimalStringContext(private val sc: StringContext) extends AnyVal {
def d(args: Any*): BigDecimal = {
val stringRepr = sc.s(args: _*)
BigDecimal(stringRepr)
}
}
println(d"0.3" * (d"0.1" + d"0.2"))
println(0.3 * (d"0.1" + 0.2))
// Pimp my library
implicit class DoubleOps(private val d: Double) extends AnyVal {
def bd = BigDecimal(d)
}
println(0.3.bd * (0.1.bd + 0.2.bd))
println(0.3 * (0.1.bd + 0.2))
第一种方法比较安全,因为第二种方法试图转换一个Double
,因此可能会丢失精度:
scala> 0.123456789012345678901234567890.bd * (0.1.bd + 0.2.bd)
res1: scala.math.BigDecimal = 0.037037036703703704
scala> d"0.123456789012345678901234567890" * (d"0.1" + d"0.2")
res2: scala.math.BigDecimal = 0.0370370367037037036703703703670
不幸的是,Scala 不允许覆盖文字。
你可以在适当的语言中轻松地做一件事,那就是提供你自己的 StringContext
for string interpolation:
implicit class BigDecimalStringContext(val sc: StringContext) extends AnyVal {
def d() = BigDecimal(sc.parts.head)
}
val test = d"0.1"
// => test: scala.math.BigDecimal = 0.1
我相信 Macros 不允许您覆盖文字。
Scala-Virtualized 是 Scala 的一个分支,其中(几乎)所有内容(包括控制结构和对象构造)都转换为方法调用,因此可以重载。不幸的是,几乎一切都不包括重载文字。
但是,您可以使用编译器插件做一些事情。