Scala和Java BigDecimal
我想从我的应用程序中的基于Math的模块切换到Java的脚本语言。这是由于mathy Java的可读性和功能限制。Scala和Java BigDecimal
对于e.g,在Java中我有这样的:
BigDecimal x = new BigDecimal("1.1");
BigDecimal y = new BigDecimal("1.1");
BigDecimal z = x.multiply(y.exp(new BigDecimal("2"));
正如你所看到的,没有BigDecimal的操作符重载,简单的公式很复杂真正的快。
随着双打,这看起来不错,但我需要的精度。
我希望在斯卡拉我可以这样做:
var x = 1.1;
var y = 0.1;
print(x + y);
,默认情况下,我会得到小数类似的行为,唉斯卡拉默认情况下不使用十进制计算。
然后,我为此在斯卡拉:
var x = BigDecimal(1.1);
var y = BigDecimal(0.1);
println(x + y);
我仍然得到一个不精确的结果。
有没有什么我不在斯卡拉正确的做?
也许我应该使用Groovy来最大化可读性(默认使用小数)?
我不知道斯卡拉,但在Java new BigDecimal(1.1)
与double
值初始化BigDecimal
,因此它是不准确等于1.1。在Java中,您必须改用new BigDecimal("1.1")
。也许这对斯卡拉也有帮助。
男人,这是丑陋的。我猜如果你关心小数精度,那么使用Groovy是最漂亮的选择。它的BigDecimal支持还不完全完美,但远优于任何其他语言。 – mcv 2011-01-03 14:00:46
@mcv发生了什么事情是在'BigDecimal(1.1)'中,表达式1.1被解析为一个double,甚至在BigDecimal获得它的值之前。所以你需要'BigDecimal(“1.1”)'这样'BigDecimal'可以负责决定“1.1”的含义。这是一个普遍的问题(在任何语言的BigDecimal或同等语言中),AFAICT只能使用不会自动将数字字面读取为浮点值的语言来解决(我一直认为这会节省大量的混淆),但是,我没有意识到任何用这种方式做事情的语言。 – ShreevatsaR 2016-09-30 18:47:21
@ShreevatsaR这正是Groovy所做的。它具有本机BigDecimal支持,并立即将1.1解释为BigDecimal。对于习惯于本地浮动的人来说,这可能会让人困惑,但在商业逻辑中,这通常是您实际需要的。 – mcv 2016-10-01 23:24:22
更改您的Scala代码这样:
var x = BigDecimal("1.1"); // note the double quotes
var y = BigDecimal("0.1");
println(x + y);
,它会工作就像它在Java中。
这里发生了什么?为什么'new'既不需要也不被接受? – ripper234 2013-03-01 09:14:33
请注意,不带'new'的BigDecimal(“1.0”)是'BigDecimal.apply(“1.0”)的缩写' - 它调用'BigDecimal'类的对象BigDecimal的'apply'方法, 。 'apply'方法是一种工厂方法。 – Jesper 2013-03-01 09:46:10
它不适用于'new'(至少不在Scala 2.10.0中),因为显然'BigDecimal'没有一个带'String'的公共构造函数。这可能是Scala版本的'BigDecimal'中的一个bug。请注意,如果您执行'new java.math.BigDecimal(“1.0”)'',它将起作用。 – Jesper 2013-03-01 09:47:39
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>
这实际上并没有回答这个问题,它只是演示了使用字符串构造函数的不同方法,因为已经在不同的答案中介绍过了! – 2010-05-02 17:19:52
在这方面,Scala与Java绝对是一样的。
按照勒夫的回答,写val x = BigDecimal(1.1)
相当于写
的问题,当然,是双d
已经具备了舍入误差,所以你初始化X与坏数据。
使用接受字符串的构造函数代替,并且一切正常。
考虑到您的例子,您最好使用val
而不是var
s,并且您可以安全地将分号保留在Scala中。
我无法验证Scala中BigDecimal的问题。它在2.8.1中按预期工作 – gerferra 2011-01-20 11:21:23
它不等同。在第二种情况下,你使用一个新变量'd'来对命名空间进行监控。 – 2014-07-13 18:46:38
您可以在内部存储值作为整数/字符串(无精),并使用scale
(这是从斯卡拉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)
或者,如果你想解析字符串,你可以控制的四舍五入:
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
为什么使用'val x = new BigDecimal(new JBigD(JBigI.valueOf(110),Scale))'而不是'val x = BigDecimal(110,Scale)'? – 2011-02-27 15:23:20
谢谢指出!我不记得这种方法在Scala 2.7.x中是否可用,但它绝对是Scala 2.8中的一种方式。我会解决答案。 – 2011-02-27 18:38:13
我知道这个问题是旧的,并回答了,但另一种选择,如果你打开不同的语言(如OP似乎是),是使用Clojure的。 Clojure的有,海事组织,一些简单的语法为BigDecimal
数学(注意尾随M
秒 - 表示BigDecimal
):
user=> (def x 1.1M)
#'user/x
user=> (def y 1.1M)
#'user/y
user=> (def z (* x (.pow y 2)))
#'user/z
user=> z
1.331M
user=> (type z)
java.math.BigDecimal
我喜欢的Clojure的数学,因为它默认为精度在许多情况下,例如它的使用Ratio
:
user=> (/ 60 14)
30/7
user=> (type (/ 60 14))
clojure.lang.Ratio
你真的*确定使用BigDecimal是正确的事情吗?你在做什么样的计算? – 2010-04-23 10:06:43
我无法验证Scala中BigDecimal的问题。至少在2.8.1中它至少能够工作 – gerferra 2011-01-20 11:23:13
var x:BigDecimal = 11.0应该是确切的,并且x = x/10.0应该很高兴。 – ChuckCottrill 2016-10-14 23:52:57