Java 如何正确比较long和float原语?
出于某种原因,我需要比较两个原语:long和float 我可以为此使用以下代码吗Java 如何正确比较long和float原语?,java,primitive-types,Java,Primitive Types,出于某种原因,我需要比较两个原语:long和float 我可以为此使用以下代码吗 long a = 111L; float b = 111.1f if (a > b) { ... } 我知道,用epsilon值等可以比较float和float的精确度 但是,如何才能更正确地对我的案例进行比较呢 多亏了大家。您可以将它们都包装在BigDecimal中,并对它们进行比较: long a = 111L; float b = 111.1f; BigDecimal first = new B
long a = 111L;
float b = 111.1f
if (a > b) {
...
}
我知道,用epsilon值等可以比较float和float的精确度
但是,如何才能更正确地对我的案例进行比较呢
多亏了大家。您可以将它们都包装在
BigDecimal
中,并对它们进行比较:
long a = 111L;
float b = 111.1f;
BigDecimal first = new BigDecimal(a);
BigDecimal second = new BigDecimal(b, MathContext.DECIMAL32);
if (first.compareTo(second) > 0) { ... }
为了理解为什么我们对同一类型下的两个操作数都感兴趣,让我们深入研究一下:
当运算符将二进制数字提升应用于一对操作数(每个操作数必须表示可转换为数字类型的值)时,以下规则依次适用:
- 如果任一操作数的类型为双精度,则另一个操作数将转换为
double
- 否则,如果其中一个操作数的类型为
,则转换另一个操作数 到float
浮动
- 否则,如果任一操作数的类型为
,则转换另一个操作数 到long
长
- 否则,两个操作数都将转换为类型
int
a>b
,long
操作数将隐式提升为float
。但是,这最终可能会导致精度损失,如中所述:
int
或long
值到float
或long的加宽转换
值加倍,可能会导致精度损失-即结果
可能会丢失一些值的最低有效位。在这个
在这种情况下,生成的浮点值将被正确舍入
整数值的版本,使用IEEE 754四舍五入到最近模式
(§4.2.4)
如果你想用ε,你可以这样做
// allow for the smallest rounding error
if (a > b + Math.sign(b) * Float.ulp(b))
或
如果你能假设非负数,你可以放弃数学符号(b)
然而,在这种情况下使用BigDecimal可能更清楚,请参见@kocko的答案
顺便说一句:提高准确性的最简单的改变是使用
double
而不是float
double
的准确度实际上要高出5亿倍,除非你拥有数十亿倍的内存,否则你使用的提取内存将无关紧要。Java支持直接比较长和浮点。但是,有一些警告:
如果比较long和float,long将转换为float,因为float被认为是比long更宽的类型。但是,此转换可能会失去精度:长值将转换为最近的浮点值;因此,对于长a
和浮点b
,a>b
可能为假,尽管a
大于b
,如果b
实际上是最接近b
的浮点值
每个long和float值都可以用BigDecimal
表示,因此您也可以使用BigDecimal
类来比较long和float:
long a = ...;
float b = ...;
if (BigDecimal.valueOf(a).compareTo(BigDecimal.valueOf(b)) > 0) {
...
}
轻松使用此代码:
Double.compare(longVar * 1., floatVar)
我给出了一个可以帮助你的答案。看看这个,你如何定义“正确”?上面的代码将告诉您,
111
不大于111.1f
,这就是我自己所说的“正确”。所以我看不出有什么不同的理由……你可能会考虑使用一个<代码>浮点< /代码>的适当舍入。代码>新的BigDecimal(b,MathContext.DECIMAL32)代码>将值与长
进行比较时,浮点
和双精度
的精度差异不太可能相关。更重要的是,具有较大绝对值的long
无法用float
精确表示,但是,如果源值的精度不高,将其转换为double
并不能神奇地增加精度。但我看不出epsilon如何改善
比较。使用ε对等式测试有意义,但对排序没有意义…@Holger你对比较有什么怀疑。当然a:100>b:10,即使误差为1。误差必须为0才能在误差范围内说100>10吗?好吧,让我们继续看b=10
示例。原始代码是a>b
,因此有效地执行a>10.0
。现在将其替换为a>b+Math.signum(b)*Math.ulp(b)
,这意味着您将有效地执行a>10.000000000000002
。为什么你认为a>10.000000000000002
比a>10.0
有所改进?如果a
是long
也没有区别,但是如果a
是浮点值,引入ε意味着,如果a
恰好是10.00000000000001
,则条件是false
。我看不到这里的改进。我误读了你的评论-所以你说你认为代码<代码> 100000×100L不大于<代码> 100000万0f <代码>作为改进?我不知道。如前所述,当有人测试平等性时,这是有意义的。然后,有一些值不被认为是更大或更小(换句话说,根据ε相等),但对于单个“大于”运算符,不可能在没有上下文的情况下说哪个行为更好。@Holger我同意上下文确实重要。这就是为什么我建议采取保守的方法。即使在相等的情况下,也不能说两个数相等,只能说两个数不相等。
Double.compare(longVar * 1., floatVar)