Scala 和 Java BigDecimal

发布于 2024-08-30 11:44:45 字数 682 浏览 10 评论 0原文

我想将应用程序中基于数学的模块从 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 来最大化可读性(它默认使用小数)?

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.

For e.g, in Java I have this:

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.

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

I was hoping in Scala I could do this:

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.

Then I do this in 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?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

冷默言语 2024-09-06 11:44:45

我不知道 Scala,但在 Java 中 new BigDecimal(1.1) 使用 double 值初始化 BigDecimal,因此它不是 恰好等于1.1。在 Java 中,您必须使用 new BigDecimal("1.1") 来代替。也许这对 Scala 也有帮助。

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

三生路 2024-09-06 11:44:45

将您的 Scala 代码更改为:

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

它将像在 Java 中一样工作。

Change your Scala code to this:

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.

○闲身 2024-09-06 11:44:45

Scala 在这方面与 Java 绝对是一样的。

根据 Joachim 的回答,编写 val x = BigDecimal(1.1)

相当于编写

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

The Problem, 当然,是 Double d 已经有舍入误差,所以你正在用错误数据初始化 x。

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

根据您的示例,您最好使用 val 而不是 var,并且您也可以在 Scala 中安全地保留分号。

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

As per Joachim's answer, writing 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.

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.

陌路终见情 2024-09-06 11:44:45

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

You can store values as Integer/String (without precision) internally and use scale (this is a transcript from 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
2024-09-06 11:44:45
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>
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>
疯了 2024-09-06 11:44:45

我知道这个问题已经很老了并且已经得到解答,但是如果您对不同的语言持开放态度(就像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

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 Ms -- that indicates 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:

user=> (/ 60 14)
30/7
user=> (type (/ 60 14))
clojure.lang.Ratio
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文