Scala 和 Java BigDecimal

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2697638/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 10:57:46  来源:igfitidea点击:

Scala and Java BigDecimal

javamathscalagroovybigdecimal

提问by geejay

I want to switch from Java to a scripting language for the Math based modules in my app. This is due to the readability, and functional limitations of mathy Java.

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

For e.g, in Java I have this:

例如,在 Java 中,我有这个:

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

As you can see, without BigDecimal operator overloading, simple formulas get complicated real quick.

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

With doubles, this looks fine, but I need the precision.

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

I was hoping in Scala I could do this:

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

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

And by default I would get decimal-like behaviour, alas Scala doesn't use decimal calculation by default.

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

Then I do this in Scala:

然后我在 Scala 中这样做:

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

And I still get an imprecise result.

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

Is there something I am not doing right in Scala?

我在 Scala 中有什么地方做得不对吗?

Maybe I should use Groovy to maximise readability (it uses decimals by default)?

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

采纳答案by Joachim Sauer

I don't know Scala, but in Java new BigDecimal(1.1)initializes the BigDecimalwith a doublevalue and thus it is not exactlyequal to 1.1. In Java you have to use new BigDecimal("1.1")instead. Maybe that will help in Scala as well.

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

回答by Jesper

Change your Scala code to this:

将您的 Scala 代码更改为:

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

and it will work just like it does in Java.

它会像在 Java 中一样工作。

回答by Eastsun

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>

回答by Kevin Wright

Scala is most definitely the same as Java in this respect.

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

As per Joachim's answer, writing val x = BigDecimal(1.1)

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

is equivalent to writing

相当于写

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

The problem, of course, is that the Double dALREADY has the rounding error, so you're initialising x with bad data.

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

Use the constructor that accepts a string instead, and all will be fine.

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

Given your example, you'd also be better off using vals instead of vars, and you can safely leave the semicolons off in Scala as well.

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

回答by Alexander Azarov

You can store values as Integer/String (without precision) internally and use scale(this is a transcript from Scala REPL):

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

Or if you want to parse a string, you can control rounding:

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

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

回答by overthink

I know this question is old and answered, but another option, if you're open to different languages (as the OP seemed to be), would be to use Clojure. Clojure has, IMO, some of the simplest syntax for BigDecimalmath (note the trailing Ms -- that indicates BigDecimal):

我知道这个问题很老并且已经回答了,但是如果您对不同的语言持开放态度(就像 OP 那样),另一种选择是使用 Clojure。Clojure 有,IMO,一些最简单的BigDecimal数学语法(注意尾随的Ms - 表示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

I like Clojure for math since it defaults to precision in many cases, e.g. its use of Ratio:

我喜欢 Clojure 的数学,因为它在许多情况下默认为精度,例如它的使用Ratio

user=> (/ 60 14)
30/7
user=> (type (/ 60 14))
clojure.lang.Ratio