【问题标题】:is it safe to use comparison operators on BigDecimal in groovy/grails?在 groovy/grails 中的 BigDecimal 上使用比较运算符是否安全?
【发布时间】:2015-05-07 12:16:12
【问题描述】:

比较两个 BigDecimal 的 Java 方法是使用 compareTo() 方法,并检查结果是 -1、0 还是 1。

BigDecimal a = new BigDecimal("1.23")
BigDecimal b = new BigDecimal("3.45")
if (a.compareTo(b) > 0)) { }

我看到有些人在 grails 中使用这种格式:

 if (a > b) {  }

这是否正常工作? IE。它会得到正确的小数,还是转换为浮点数或类似的并进行比较?

使用 "==" 与使用 equals() 相比如何?

这样的结果是什么:

BigDecimal a = new BigDecimal("1.00")
BigDecimal b = new BigDecimal("1")
assert (a==b)

这似乎可行,但我们在 Java 中根深蒂固地认为不要做这种事情。

+= 怎么样?例如

a+=b?

这个和

一样吗
a = a.add(b)

在哪里可以找到这种东西?我有两本 groovy 书,不幸的是没有提到 BigDecimal 比较或算术,只有转换/声明。

【问题讨论】:

  • 答案是肯定的,在 Groovy/grails 中的 BigDecimals 上使用比较(和算术)运算符是安全的,完整列表在这里:ibm.com/developerworks/library/j-pg10255Thanks mohsenmadi 和 Nathan Hughes

标签: groovy comparison operator-keyword bigdecimal


【解决方案1】:

Groovy 允许运算符重载。当一个类型实现某些方法时,您可以在该类型上使用相应的运算符。

对于+,实现的方法是加,而不是加。

对于大于或小于比较,Groovy 会在对象上查找 compareTo 方法,而对于 ==,它会查找名为 equals 的方法。 (如果您想像在 Java 中使用 == 一样比较引用,则必须使用 is。)

以下是常用数学运算符的表格以及用于重载它们的方法:

Operator     Method
a + b        a.plus(b)
a - b        a.minus(b)
a * b        a.multiply(b)
a / b        a.divide(b)
a++ or ++a   a.next()
a-- or --a   a.previous()
a << b       a.leftShift(b)

您可以看到 BigDecimal 重载了其中一些方法(您会为加、减、乘和除获得运算符重载,但不会为 next、previous 或 leftShift 重载):

groovy:000> BigDecimal.methods*.name
===> [equals, hashCode, toString, intValue, longValue, floatValue, doubleValue,
byteValue, shortValue, add, add, subtract, subtract, multiply, multiply, divide,
 divide, divide, divide, divide, divide, remainder, remainder, divideAndRemainde
r, divideAndRemainder, divideToIntegralValue, divideToIntegralValue, abs, abs, m
ax, min, negate, negate, plus, plus, byteValueExact, shortValueExact, intValueEx
act, longValueExact, toBigIntegerExact, toBigInteger, compareTo, precision, scal
e, signum, ulp, unscaledValue, pow, pow, movePointLeft, movePointRight, scaleByP
owerOfTen, setScale, setScale, setScale, stripTrailingZeros, toEngineeringString
, toPlainString, round, compareTo, getClass, notify, notifyAll, wait, wait, wait
, valueOf, valueOf, valueOf]

根据您的对象如何实现 equals 和 compareTo,您会得到 ==&gt;&lt;&gt;=&lt;=

因此,运算符导致已在 BigDecimal 中声明的方法,或由 groovy 添加到 BigDecimal 中的方法被调用。为了能够在基元上使用运算符,它绝对不会对像 float 这样的基元类型进行任何类型的转换。

该表取自this developerworks article by Andrew Glover and Scott Davis,其中包含更多详细信息并包含示例代码。

【讨论】:

  • 啊哈!您找到的链接回答了所有问题。我用谷歌搜索得很辛苦,但没有找到这个宝石。
  • 我希望您的答案开头有简单的是/否。类似于:是的,您可以安全地在 BigDecimal 上使用比较运算符。按照说明...
【解决方案2】:

Groovy 在管理数字和无限精确方面做得非常出色。您应该知道的第一件事是,默认情况下,任何带有点的数字都是 BigDecimal - 无限精度的原因。这是一个确切含义的示例。考虑一下这个 sn-p:

    System.out.println(2.0 - 1.1);
    System.out.println(new BigDecimal(2.0).subtract(new BigDecimal(1.1)));
    System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.1")));

    // the above will give these:
    0.8999999999999999
    0.899999999999999911182158029987476766109466552734375
    0.9

这显示了我们必须经历的耐力才能在 Java 中获得一些不错的东西。在 Groovy 中,您只需要这样做:

println 2 - 1.1​

获得您的 0.9!在Groovy web console 上试试这个。这里,第二个操作数是 BigDecimal,所以整个计算都是 BigDecimal,而在这种情况下,Groovy 会努力争取达到干净的精度。

但是怎么做呢?这是因为 Groovy 中几乎每个运算符都映射到底层对象的方法调用上,所以 a + ba.plus(b),而 a ==b 转换为 a.compareTo(b)。因此,假设您的假设是安全的,这就是 Groovy 做事的方式:少写,富有表现力,而 Groovy 将为您完成工作。您可以在Groovy-lang documentation page 中了解所有这些内容,并附上示例。

【讨论】:

  • 非常酷,但是我们也可以使用 a > b 而不是 a.compareTo(b) >0 吗?
  • 确实!就像我说的,少写,期待“正确”。例如,> 运算符不仅适用于 Groovy 中的数字,您甚至可以在对象上运行它。试试这个:断言“一”>“二”==假,或真。你发现了什么?甚至 > 运算符也被重载了。
  • 更多关于 Groovy 文档的链接:Operator overloading
【解决方案3】:

简短的回答是是的,在 Groovy 中使用== 进行BigDecimal 比较是安全的。

来自 Groovy 文档 Behaviour of == 部分:

在 Java 中,== 表示原始类型的相等或对象的标识。在 Groovy 中,== 转换为 a.compareTo(b)==0,如果它们是 Comparable,则转换为 a.equals(b)。要检查身份,有is。例如。 a.is(b).

【讨论】:

    猜你喜欢
    • 2016-04-13
    • 1970-01-01
    • 2017-07-21
    • 2011-07-07
    • 2022-11-02
    • 2012-03-13
    • 2015-08-03
    • 2011-05-09
    • 2014-12-27
    相关资源
    最近更新 更多