【问题标题】:Confusion using with double value, when groovy decides to make value in double vs BigDecimal?当 groovy 决定在 double 与 BigDecimal 中产生价值时,混淆使用 double 值?
【发布时间】:2016-09-09 11:13:20
【问题描述】:

我对使用double 值有点困惑。

当我使用如下:-

double foo = 20.46455
assert 20 == foo.round()
assert 20.46 == foo.round(2)

一切正常。但是当我使用类似的东西时:-

def foo = 20.46455
assert 20 == foo.round()

它抛出:-

java.lang.NullPointerException

def foo = 20.46455
assert 20.46 == foo.round(2)

它抛出:-

groovy.lang.MissingMethodException:没有方法签名:java.math.BigDecimal.round() 适用于参数类型:(java.lang.Integer) 值:[2] 可能的解决方案:round(java.math.MathContext)、find()、pow(int)、power(java.lang.Integer)、find(groovy.lang.Closure)和(java.lang.Number)

这意味着默认情况下在groovy 中,值保留在BigDecimalBigDecimal.round() 期望java.math.MathContext 作为输入。

但是当我使用Math.round() 时,我的困惑开始了,除了double 作为输入,然后为什么下面的语句被传递,而 groovy 默认保存在BigDecimal

def foo = 20.46455
assert 20 == Math.round(foo)

为什么我必须使用.toDouble() 来通过我的测试用例,而foo 的值在double 格式如下?

def foo = 20.46455
assert 20 == foo.toDouble().round()
assert 20.46 == foo.toDouble().round(2)

注意 :- 我不想知道如何 round 一个双精度值,我只想知道为什么 groovy 在每种情况下的行为不同??

【问题讨论】:

  • @yash 我不想四舍五入我只想知道为什么groovy 在每种情况下的行为都不同。谢谢..:)
  • @NathanHughes 实际上我知道如何舍入 BigDecimalDouble.. 是的,你是对的,我的问题是 when groovy decides to make something a double vs BigDecimal?
  • 我也更新了问题的标题,谢谢..:)
  • 不要忘记添加缺失的数据类型,而不是让 groovy 假设!为我工作!

标签: groovy double bigdecimal


【解决方案1】:

Groovy 自动隐式地对任何浮点数使用 BigDecimal,除非您定义类型或为数字添加后缀(如 D)。

示例:

def foo = 20.46455
println foo.getClass()

输出:

类 java.math.BigDecimal

double foo = 20.45645
println foo.getClass()

输出:

类 java.lang.Double

def foo = 20.45645d
println foo.getClass()

输出:

类 java.lang.Double

类型转换:

Groovy 还具有某些自动类型转换,这就是为什么即使 Math.round() 只接受 doublefloat 原语作为参数,当您传递 BigDecimal 时代码不会失败。为了证明这一点,您可以实现自己的 round 函数并检查类型转换会发生什么:

示例:

def round(double foo) {
   println foo.getClass()
   return foo.round()
}

def foo = 20.46455
println foo.getClass()
assert 20 == round(foo)

输出:

类 java.math.BigDecimal

类 java.lang.Double

一些更有效的隐式转换示例:

def round(float foo) {
   println foo.getClass()
   return foo.round()
}

def foo = 20.46455
println foo.getClass()
assert 20 == round(foo)

输出:

类 java.math.BigDecimal

类 java.lang.Float

def round(float foo) {
   println foo.getClass()
   return foo.round()
}

def foo = 20
println foo.getClass()
assert 20 == round(foo)

输出:

类 java.lang.Integer

类 java.lang.Float

def round(double foo) {
   println foo.getClass()
   return foo.round()
}

def foo = 20
println foo.getClass()
assert 20 == round(foo)

输出:

类 java.lang.Integer

类 java.lang.Double

def round(BigDecimal foo) {   
   println foo.getClass()
   return foo
}

double foo = 20.0
println foo.getClass()
assert 20 == round(foo)

输出:

类 java.lang.Double

类 java.lang.BigDecimal

根据经验,如果数字是基于浮点数的(doublefloatBigDecimal),则彼此之间将存在隐式类型转换,并且代码在尝试转换时会抛出异常转换为非浮点数(如intlong)。如果一个数字不是浮点类型(intlong),它可以在非浮点类型和浮点类型之间转换,因为浮点数还包括非浮点作为子集(例如 1 可以是用 1.0 表示)。这是有道理的,因为您不能将浮点信息从 float 传递到 int(20.5 不能用 int 变量表示),但在大多数情况下,您可以做相反的事情,偶尔会例外大值溢出(例如,一个非常大的 long 数字到 float 变量中)。

【讨论】:

  • def foo = 20.46455 让 Groovy 使用类型推断来决定这个变量的类型,并选择 BigDecimal。 double foo = 20.46455 强制变量为 double 类型。您也可以使用后缀来强制 double 声明像这样 def foo = 20.46455D
  • 但是它没有强制传递给double,这就是我感到困惑的原因,我只使用double foo = 20.46455,当将其用作assert 20 == Math.round(foo)时,groovy会自动将其视为double但是当我将其用作foo.round() 时,groovy 将其用作BigDecimal 并引发异常...
  • 抱歉,我现在明白你的意思了。 Groovy 也有自动类型转换。让我扩展我的答案以包括这一点。
  • 如果对象本身是 BigDecimal def foo = 20.46455,并且您尝试调用未针对 BigDecimal 实现的方法(如 round()),它将引发异常。但是如果您将它作为参数传递,Groovy 将尝试适应类型(如将 BigDecimal 传递给需要 doublefloat 参数的方法),但如果转换为不可能。我将扩展我的答案以显示更多的隐式转换。
猜你喜欢
  • 2011-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多