当 groovy 决定在 double 与 BigDecimal 中创造价值时,使用 double 值会造成混淆吗?

Confusion using with double value, when groovy decides to make value in double vs BigDecimal?

我对使用 double 值有点困惑。

当我如下使用时:-

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

一切正常。但是当我使用像 as :-

这样的东西时
def foo = 20.46455
assert 20 == foo.round()

它抛出:-

java.lang.NullPointerException

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

它抛出:-

groovy.lang.MissingMethodException: No signature of method: java.math.BigDecimal.round() is applicable for argument types: (java.lang.Integer) values: [2] Possible solutions: round(java.math.MathContext), find(), pow(int), power(java.lang.Integer), find(groovy.lang.Closure), and(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 在每个案例??

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

示例:

def foo = 20.46455
println foo.getClass()

输出:

class java.math.BigDecimal

double foo = 20.45645
println foo.getClass()

输出:

class java.lang.Double

def foo = 20.45645d
println foo.getClass()

输出:

class 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)

输出:

class java.math.BigDecimal

class java.lang.Double

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

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

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

输出:

class java.math.BigDecimal

class java.lang.Float

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

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

输出:

class java.lang.Integer

class java.lang.Float

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

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

输出:

class java.lang.Integer

class java.lang.Double

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

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

输出:

class java.lang.Double

class java.lang.BigDecimal

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