31

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

例如,在 Java 中我有这个:

BigDecimal x = new BigDecimal("1.1");
BigDecimal y = new BigDecimal("1.1");
BigDecimal z = x.multiply(y.exp(new BigDecimal("2"));

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

使用双打,这看起来不错,但我需要精度。

我希望在 Scala 中我能做到这一点:

var x = 1.1;
var y = 0.1;
print(x + y);

默认情况下,我会得到类似小数的行为,唉,Scala 默认情况下不使用小数计算。

然后我在 Scala 中执行此操作:

var x = BigDecimal(1.1);
var y = BigDecimal(0.1);
println(x + y);

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

有什么我在 Scala 中没有做对的事情吗?

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

4

6 回答 6

39

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

于 2010-04-23T10:01:48.243 回答
35

将您的 Scala 代码更改为:

var x = BigDecimal("1.1");   // note the double quotes
var y = BigDecimal("0.1");
println(x + y);

它将像在 Java 中一样工作。

于 2010-04-23T10:04:51.943 回答
13

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

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

相当于写

val d : Double = 1.1
val x = BigDecimal(d)

当然,问题在于 Double dALREADY 已经存在舍入误差,因此您正在使用错误数据初始化 x。

改用接受字符串的构造函数,一切都会好起来的。

鉴于您的示例,您最好使用vals 而不是vars,并且您也可以安全地在 Scala 中不使用分号。

于 2010-04-23T11:12:38.800 回答
7

您可以在内部将值存储为整数/字符串(不带精度)并使用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)

或者如果你想解析一个字符串,你可以控制舍入:

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
于 2010-04-23T13:15:32.970 回答
6
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-04-23T10:28:35.733 回答
2

我知道这个问题已经过时并且得到了回答,但是如果您对不同的语言持开放态度(就像 OP 似乎那样),另一种选择是使用 Clojure。Clojure 有,IMO,一些最简单的BigDecimal数学语法(注意尾随M的 s -- 表示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
于 2011-06-06T13:56:04.973 回答