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
Scala and Java BigDecimal
提问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 BigDecimal
with a double
value 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 也有帮助。BigDecimal
double
new 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 d
ALREADY has the rounding error, so you're initialising x with bad data.
当然,问题在于 Double d
ALREADY 存在舍入错误,因此您正在使用错误数据初始化 x。
Use the constructor that accepts a string instead, and all will be fine.
改用接受字符串的构造函数,一切都会好起来的。
Given your example, you'd also be better off using val
s instead of var
s, and you can safely leave the semicolons off in Scala as well.
鉴于您的示例,您最好使用val
s 而不是var
s,并且您也可以安全地将分号保留在 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 BigDecimal
math (note the trailing M
s -- that indicates BigDecimal
):
我知道这个问题很老并且已经回答了,但是如果您对不同的语言持开放态度(就像 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
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