Scala和Java BigDecimal

gee*_*jay 28 java math groovy scala bigdecimal

我想在我的应用程序中从Java切换到基于Math的模块的脚本语言.这是由于Java的可读性和功能限制.

例如,在Java中我有这个:

BigDecimal x = new BigDecimal("1.1");
BigDecimal y = new BigDecimal("1.1");
BigDecimal z = x.multiply(y.exp(new BigDecimal("2"));
Run Code Online (Sandbox Code Playgroud)

如您所见,如果没有BigDecimal运算符重载,简单的公式会很快变得复杂.

有了双打,看起来很好,但我需要精确度.

我希望Scala能做到这一点:

var x = 1.1;
var y = 0.1;
print(x + y);
Run Code Online (Sandbox Code Playgroud)

默认情况下,我会得到类似十进制的行为,唉,Scala默认情况下不使用十进制计算.

然后我在Scala中这样做:

var x = BigDecimal(1.1);
var y = BigDecimal(0.1);
println(x + y);
Run Code Online (Sandbox Code Playgroud)

我仍然得到一个不精确的结果.

在Scala中我有什么不对的吗?

也许我应该使用Groovy来最大化可读性(它默认使用小数)?

Joa*_*uer 38

我不知道Scala,但是在Java 中用值new BigDecimal(1.1)初始化它,因此它不完全等于1.1.在Java中,您必须使用.也许这对Scala也有帮助.BigDecimaldoublenew BigDecimal("1.1")

  • @mcv正在发生的事情是,在`BigDecimal(1.1)`中,表达式1.1被解析为double,甚至在`BigDecimal`得到它的值之前.所以你需要`BigDecimal("1.1")`以便`BigDecimal`可以负责决定"1.1"的含义.这是一个普遍的问题(在任何语言的BigDecimal或等价物中)AFAICT只能用不自动读取数字文字作为浮点值的语言来解决(我一直以为这会节省很多混乱),但是我我不知道任何以这种方式做事的语言. (2认同)

Jes*_*per 31

将您的Scala代码更改为:

var x = BigDecimal("1.1");   // note the double quotes
var y = BigDecimal("0.1");
println(x + y);
Run Code Online (Sandbox Code Playgroud)

它会像在Java中一样工作.

  • 请注意,不带 new 的 BigDecimal("1.0") 是 BigDecimal.apply("1.0") 的简写 - 它调用 BigDecimal 类的伴生对象 BigDecimal 的 apply 方法。“apply”方法是一个工厂方法。 (2认同)
  • 请参阅对象[`scala.math.BigDecimal`]的API文档(http://www.scala-lang.org/api/current/index.html#scala.math.BigDecimal$)."BigDecimal(...)"与"BigDecimal.apply(...)"相同的符号是Scala编译器魔法. (2认同)

Kev*_*ght 13

在这方面,Scala绝对与Java相同.

根据约阿希姆的回答,写作 val x = BigDecimal(1.1)

相当于写作

val d : Double = 1.1
val x = BigDecimal(d)
Run Code Online (Sandbox Code Playgroud)

当然,问题是Double dALREADY有舍入错误,所以你用不好的数据初始化x.

使用接受字符串的构造函数,一切都会好的.

举个例子,你也可以更好地使用vals而不是vars,你也可以安全地在Scala中保留分号.


Ale*_*rov 6

您可以在内部将值存储为Integer/String(无精度)并使用scale(这是来自Scala REPL的脚本):

scala> val Scale = 2
Scale: Int = 2

scala> val x = BigDecimal(110, Scale)
x: scala.math.BigDecimal = 1.10

scala> val y = BigDecimal(303, Scale)
y: scala.math.BigDecimal = 3.03

scala> (x+y, (x+y).scale)
res0: (scala.math.BigDecimal, Int) = (4.13,2)

scala> (x*2, (x*2).scale)
res1: (scala.math.BigDecimal, Int) = (2.20,2)
Run Code Online (Sandbox Code Playgroud)

或者,如果要解析字符串,可以控制舍入:

scala> val z = BigDecimal("8.937").setScale(Scale, BigDecimal.RoundingMode.FLOOR)      
z: scala.math.BigDecimal = 8.93

scala> val z = BigDecimal("8.937").setScale(Scale, BigDecimal.RoundingMode.CEILING)
z: scala.math.BigDecimal = 8.94
Run Code Online (Sandbox Code Playgroud)


Eas*_*sun 5

scala> implicit def str2tbd(str: String) = new {
     |     def toBD = BigDecimal(str)
     | }
str2tbd: (str: String)java.lang.Object{def toBD: scala.math.BigDecimal}

scala> var x = "1.1".toBD
x: scala.math.BigDecimal = 1.1

scala> var y = "0.1".toBD
y: scala.math.BigDecimal = 0.1

scala> x + y
res0: scala.math.BigDecimal = 1.2

scala> implicit def str2bd(str: String) = BigDecimal(str)
str2bd: (str: String)scala.math.BigDecimal

scala> x + y + "1.2345566"
res1: scala.math.BigDecimal = 2.4345566

scala>
Run Code Online (Sandbox Code Playgroud)